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 areV8ClassIndex::WEBGL
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 "V8WebGLArray.h"
45#include "V8WebGLBuffer.h"
46#include "V8WebGLByteArray.h"
47#include "V8WebGLFloatArray.h"
48#include "V8WebGLFramebuffer.h"
49#include "V8WebGLIntArray.h"
50#include "V8WebGLProgram.h"
51#include "V8WebGLRenderbuffer.h"
52#include "V8WebGLShader.h"
53#include "V8WebGLShortArray.h"
54#include "V8WebGLTexture.h"
55#include "V8WebGLUniformLocation.h"
56#include "V8WebGLUnsignedByteArray.h"
57#include "V8WebGLUnsignedIntArray.h"
58#include "V8WebGLUnsignedShortArray.h"
59#include "V8HTMLCanvasElement.h"
60#include "V8HTMLImageElement.h"
61#include "V8HTMLVideoElement.h"
62#include "V8ImageData.h"
63#include "V8Proxy.h"
64#include "WebGLRenderingContext.h"
65
66namespace WebCore {
67
68// Allocates new storage via tryFastMalloc.
69// Returns NULL if array failed to convert for any reason.
70static 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.
89static 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
108v8::Handle<v8::Value> V8WebGLRenderingContext::bufferDataCallback(const v8::Arguments& args)
109{
110    INC_STATS("DOM.WebGLRenderingContext.bufferData()");
111
112    // Forms:
113    // * bufferData(GLenum target, WebGLArray data, GLenum usage);
114    //   - Sets the buffer's data from the given WebGLArray
115    // * bufferData(GLenum target, GLsizeiptr size, GLenum usage);
116    //   - Sets the size of the buffer to the given size in bytes
117    if (args.Length() != 3) {
118        V8Proxy::setDOMException(SYNTAX_ERR);
119        return notHandledByInterceptor();
120    }
121
122    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
123    bool ok;
124    int target = toInt32(args[0], ok);
125    if (!ok) {
126        V8Proxy::setDOMException(SYNTAX_ERR);
127        return notHandledByInterceptor();
128    }
129    int usage = toInt32(args[2], ok);
130    if (!ok) {
131        V8Proxy::setDOMException(SYNTAX_ERR);
132        return notHandledByInterceptor();
133    }
134    if (args[1]->IsInt32()) {
135        int size = toInt32(args[1]);
136        ExceptionCode exceptionCode;
137        context->bufferData(target, size, usage, exceptionCode);
138    } else if (V8WebGLArray::HasInstance(args[1])) {
139        WebGLArray* array = V8WebGLArray::toNative(args[1]->ToObject());
140        ExceptionCode exceptionCode;
141        context->bufferData(target, array, usage, exceptionCode);
142    } else {
143        V8Proxy::setDOMException(SYNTAX_ERR);
144        return notHandledByInterceptor();
145    }
146    return v8::Undefined();
147}
148
149v8::Handle<v8::Value> V8WebGLRenderingContext::bufferSubDataCallback(const v8::Arguments& args)
150{
151    INC_STATS("DOM.WebGLRenderingContext.bufferSubData()");
152
153    // Forms:
154    // * bufferSubData(GLenum target, GLintptr offset, WebGLArray data);
155    if (args.Length() != 3) {
156        V8Proxy::setDOMException(SYNTAX_ERR);
157        return notHandledByInterceptor();
158    }
159
160    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
161    bool ok;
162    int target = toInt32(args[0], ok);
163    if (!ok) {
164        V8Proxy::setDOMException(SYNTAX_ERR);
165        return notHandledByInterceptor();
166    }
167    int offset = toInt32(args[1], ok);
168    if (!ok) {
169        V8Proxy::setDOMException(SYNTAX_ERR);
170        return notHandledByInterceptor();
171    }
172    if (!V8WebGLArray::HasInstance(args[2])) {
173        V8Proxy::setDOMException(SYNTAX_ERR);
174        return notHandledByInterceptor();
175    }
176    WebGLArray* array = V8WebGLArray::toNative(args[2]->ToObject());
177    ExceptionCode exceptionCode;
178    context->bufferSubData(target, offset, array, exceptionCode);
179    return v8::Undefined();
180}
181
182static v8::Handle<v8::Value> toV8Object(const WebGLGetInfo& info)
183{
184    switch (info.getType()) {
185    case WebGLGetInfo::kTypeBool:
186        return v8::Boolean::New(info.getBool());
187    case WebGLGetInfo::kTypeFloat:
188        return v8::Number::New(info.getFloat());
189    case WebGLGetInfo::kTypeLong:
190        return v8::Integer::New(info.getLong());
191    case WebGLGetInfo::kTypeNull:
192        return v8::Null();
193    case WebGLGetInfo::kTypeString:
194        return v8::String::New(fromWebCoreString(info.getString()), info.getString().length());
195    case WebGLGetInfo::kTypeUnsignedLong:
196        return v8::Integer::NewFromUnsigned(info.getUnsignedLong());
197    case WebGLGetInfo::kTypeWebGLBuffer:
198        return toV8(info.getWebGLBuffer());
199    case WebGLGetInfo::kTypeWebGLFloatArray:
200        return toV8(info.getWebGLFloatArray());
201    case WebGLGetInfo::kTypeWebGLFramebuffer:
202        return toV8(info.getWebGLFramebuffer());
203    case WebGLGetInfo::kTypeWebGLIntArray:
204        return toV8(info.getWebGLIntArray());
205    // FIXME: implement WebGLObjectArray
206    // case WebGLGetInfo::kTypeWebGLObjectArray:
207    case WebGLGetInfo::kTypeWebGLProgram:
208        return toV8(info.getWebGLProgram());
209    case WebGLGetInfo::kTypeWebGLRenderbuffer:
210        return toV8(info.getWebGLRenderbuffer());
211    case WebGLGetInfo::kTypeWebGLTexture:
212        return toV8(info.getWebGLTexture());
213    case WebGLGetInfo::kTypeWebGLUnsignedByteArray:
214        return toV8(info.getWebGLUnsignedByteArray());
215    default:
216        notImplemented();
217        return v8::Undefined();
218    }
219}
220
221enum ObjectType {
222    kBuffer, kRenderbuffer, kTexture, kVertexAttrib
223};
224
225static v8::Handle<v8::Value> getObjectParameter(const v8::Arguments& args, ObjectType objectType)
226{
227    if (args.Length() != 2) {
228        V8Proxy::setDOMException(SYNTAX_ERR);
229        return notHandledByInterceptor();
230    }
231
232    ExceptionCode ec = 0;
233    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
234    bool ok;
235    unsigned target = toInt32(args[0], ok);
236    if (!ok) {
237        V8Proxy::setDOMException(SYNTAX_ERR);
238        return notHandledByInterceptor();
239    }
240    unsigned pname = toInt32(args[1], ok);
241    if (!ok) {
242        V8Proxy::setDOMException(SYNTAX_ERR);
243        return notHandledByInterceptor();
244    }
245    WebGLGetInfo info;
246    switch (objectType) {
247    case kBuffer:
248        info = context->getBufferParameter(target, pname, ec);
249        break;
250    case kRenderbuffer:
251        info = context->getRenderbufferParameter(target, pname, ec);
252        break;
253    case kTexture:
254        info = context->getTexParameter(target, pname, ec);
255        break;
256    case kVertexAttrib:
257        // target => index
258        info = context->getVertexAttrib(target, pname, ec);
259        break;
260    default:
261        notImplemented();
262        break;
263    }
264    if (ec) {
265        V8Proxy::setDOMException(ec);
266        return v8::Undefined();
267    }
268    return toV8Object(info);
269}
270
271static WebGLUniformLocation* toWebGLUniformLocation(v8::Handle<v8::Value> value, bool& ok)
272{
273    ok = false;
274    WebGLUniformLocation* location = 0;
275    if (V8WebGLUniformLocation::HasInstance(value)) {
276        location = V8WebGLUniformLocation::toNative(value->ToObject());
277        ok = true;
278    }
279    return location;
280}
281
282enum WhichProgramCall {
283    kProgramParameter, kUniform
284};
285
286v8::Handle<v8::Value> V8WebGLRenderingContext::getBufferParameterCallback(const v8::Arguments& args)
287{
288    INC_STATS("DOM.WebGLRenderingContext.getBufferParameter()");
289    return getObjectParameter(args, kBuffer);
290}
291
292v8::Handle<v8::Value> V8WebGLRenderingContext::getFramebufferAttachmentParameterCallback(const v8::Arguments& args)
293{
294    INC_STATS("DOM.WebGLRenderingContext.getFramebufferAttachmentParameter()");
295
296    if (args.Length() != 3) {
297        V8Proxy::setDOMException(SYNTAX_ERR);
298        return notHandledByInterceptor();
299    }
300
301    ExceptionCode ec = 0;
302    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
303    bool ok;
304    unsigned target = toInt32(args[0], ok);
305    if (!ok) {
306        V8Proxy::setDOMException(SYNTAX_ERR);
307        return notHandledByInterceptor();
308    }
309    unsigned attachment = toInt32(args[1], ok);
310    if (!ok) {
311        V8Proxy::setDOMException(SYNTAX_ERR);
312        return notHandledByInterceptor();
313    }
314    unsigned pname = toInt32(args[2], ok);
315    if (!ok) {
316        V8Proxy::setDOMException(SYNTAX_ERR);
317        return notHandledByInterceptor();
318    }
319    WebGLGetInfo info = context->getFramebufferAttachmentParameter(target, attachment, pname, ec);
320    if (ec) {
321        V8Proxy::setDOMException(ec);
322        return v8::Undefined();
323    }
324    return toV8Object(info);
325}
326
327v8::Handle<v8::Value> V8WebGLRenderingContext::getParameterCallback(const v8::Arguments& args)
328{
329    INC_STATS("DOM.WebGLRenderingContext.getParameter()");
330
331    if (args.Length() != 1) {
332        V8Proxy::setDOMException(SYNTAX_ERR);
333        return notHandledByInterceptor();
334    }
335
336    ExceptionCode ec = 0;
337    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
338    bool ok;
339    unsigned pname = toInt32(args[0], ok);
340    if (!ok) {
341        V8Proxy::setDOMException(SYNTAX_ERR);
342        return notHandledByInterceptor();
343    }
344    WebGLGetInfo info = context->getParameter(pname, ec);
345    if (ec) {
346        V8Proxy::setDOMException(ec);
347        return v8::Undefined();
348    }
349    return toV8Object(info);
350}
351
352v8::Handle<v8::Value> V8WebGLRenderingContext::getProgramParameterCallback(const v8::Arguments& args)
353{
354    INC_STATS("DOM.WebGLRenderingContext.getProgramParameter()");
355
356    if (args.Length() != 2) {
357        V8Proxy::setDOMException(SYNTAX_ERR);
358        return notHandledByInterceptor();
359    }
360
361    ExceptionCode ec = 0;
362    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
363    WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
364    bool ok;
365    unsigned pname = toInt32(args[1], ok);
366    if (!ok) {
367        V8Proxy::setDOMException(SYNTAX_ERR);
368        return notHandledByInterceptor();
369    }
370    WebGLGetInfo info = context->getProgramParameter(program, pname, ec);
371    if (ec) {
372        V8Proxy::setDOMException(ec);
373        return v8::Undefined();
374    }
375    return toV8Object(info);
376}
377
378v8::Handle<v8::Value> V8WebGLRenderingContext::getRenderbufferParameterCallback(const v8::Arguments& args)
379{
380    INC_STATS("DOM.WebGLRenderingContext.getRenderbufferParameter()");
381    return getObjectParameter(args, kRenderbuffer);
382}
383
384v8::Handle<v8::Value> V8WebGLRenderingContext::getShaderParameterCallback(const v8::Arguments& args)
385{
386    INC_STATS("DOM.WebGLRenderingContext.getShaderParameter()");
387
388    if (args.Length() != 2) {
389        V8Proxy::setDOMException(SYNTAX_ERR);
390        return notHandledByInterceptor();
391    }
392
393    ExceptionCode ec = 0;
394    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
395    WebGLShader* shader = V8WebGLShader::HasInstance(args[0]) ? V8WebGLShader::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
396    bool ok;
397    unsigned pname = toInt32(args[1], ok);
398    if (!ok) {
399        V8Proxy::setDOMException(SYNTAX_ERR);
400        return notHandledByInterceptor();
401    }
402    WebGLGetInfo info = context->getShaderParameter(shader, pname, ec);
403    if (ec) {
404        V8Proxy::setDOMException(ec);
405        return v8::Undefined();
406    }
407    return toV8Object(info);
408}
409
410v8::Handle<v8::Value> V8WebGLRenderingContext::getTexParameterCallback(const v8::Arguments& args)
411{
412    INC_STATS("DOM.WebGLRenderingContext.getTexParameter()");
413    return getObjectParameter(args, kTexture);
414}
415
416v8::Handle<v8::Value> V8WebGLRenderingContext::getUniformCallback(const v8::Arguments& args)
417{
418    INC_STATS("DOM.WebGLRenderingContext.getUniform()");
419
420    if (args.Length() != 2) {
421        V8Proxy::setDOMException(SYNTAX_ERR);
422        return notHandledByInterceptor();
423    }
424
425    ExceptionCode ec = 0;
426    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
427    WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
428
429    bool ok = false;
430    WebGLUniformLocation* location = toWebGLUniformLocation(args[1], ok);
431
432    if (!ok) {
433        V8Proxy::setDOMException(SYNTAX_ERR);
434        return notHandledByInterceptor();
435    }
436    WebGLGetInfo info = context->getUniform(program, location, ec);
437    if (ec) {
438        V8Proxy::setDOMException(ec);
439        return v8::Undefined();
440    }
441    return toV8Object(info);
442}
443
444v8::Handle<v8::Value> V8WebGLRenderingContext::getVertexAttribCallback(const v8::Arguments& args)
445{
446    INC_STATS("DOM.WebGLRenderingContext.getVertexAttrib()");
447    return getObjectParameter(args, kVertexAttrib);
448}
449
450v8::Handle<v8::Value> V8WebGLRenderingContext::texImage2DCallback(const v8::Arguments& args)
451{
452    INC_STATS("DOM.WebGLRenderingContext.texImage2D()");
453
454    // Currently supported forms:
455    // * void texImage2D(in GLenum target, in GLint level,
456    //                   in GLint internalformat,
457    //                   in GLsizei width, in GLsizei height, in GLint border,
458    //                   in GLenum format, in GLenum type, in WebGLArray pixels);
459    // * void texImage2D(in GLenum target, in GLint level, in ImageData pixels,
460    //                   [Optional] in GLboolean flipY, [Optional] in GLboolean premulitplyAlpha);
461    // * void texImage2D(in GLenum target, in GLint level, in HTMLImageElement image,
462    //                   [Optional] in GLboolean flipY, [Optional] in GLboolean premultiplyAlpha);
463    // * void texImage2D(in GLenum target, in GLint level, in HTMLCanvasElement image,
464    //                   [Optional] in GLboolean flipY, [Optional] in GLboolean premultiplyAlpha);
465    // * void texImage2D(in GLenum target, in GLint level, in HTMLVideoElement image,
466    //                   [Optional] in GLboolean flipY, [Optional] in GLboolean premultiplyAlpha);
467    if (args.Length() != 3 &&
468        args.Length() != 4 &&
469        args.Length() != 5 &&
470        args.Length() != 9) {
471        V8Proxy::setDOMException(SYNTAX_ERR);
472        return notHandledByInterceptor();
473    }
474
475    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
476    bool ok;
477    int target = toInt32(args[0], ok);
478    if (!ok) {
479        V8Proxy::setDOMException(SYNTAX_ERR);
480        return notHandledByInterceptor();
481    }
482    int level = toInt32(args[1], ok);
483    if (!ok) {
484        V8Proxy::setDOMException(SYNTAX_ERR);
485        return notHandledByInterceptor();
486    }
487
488    ExceptionCode ec = 0;
489    if (args.Length() == 3 ||
490        args.Length() == 4 ||
491        args.Length() == 5) {
492        bool flipY = false;
493        bool premultiplyAlpha = false;
494        if (args.Length() >= 4)
495            flipY = args[3]->BooleanValue();
496        if (args.Length() >= 5)
497            premultiplyAlpha = args[4]->BooleanValue();
498
499        v8::Handle<v8::Value> arg = args[2];
500        if (V8HTMLImageElement::HasInstance(arg)) {
501            HTMLImageElement* element = V8HTMLImageElement::toNative(v8::Handle<v8::Object>::Cast(arg));
502            context->texImage2D(target, level, element, flipY, premultiplyAlpha, ec);
503        } else if (V8HTMLCanvasElement::HasInstance(arg)) {
504            HTMLCanvasElement* element = V8HTMLCanvasElement::toNative(v8::Handle<v8::Object>::Cast(arg));
505            context->texImage2D(target, level, element, flipY, premultiplyAlpha, ec);
506        } else if(V8ImageData::HasInstance(arg)) {
507            ImageData* imageElement = V8ImageData::toNative(v8::Handle<v8::Object>::Cast(arg));
508            context->texImage2D(target, level, imageElement, flipY, premultiplyAlpha, ec);
509        } else if (V8HTMLVideoElement::HasInstance(arg)) {
510            HTMLVideoElement* element = V8HTMLVideoElement::toNative(v8::Handle<v8::Object>::Cast(arg));
511            context->texImage2D(target, level, element, flipY, premultiplyAlpha, ec);
512        }
513        else {
514            // FIXME: consider different / better exception type.
515            V8Proxy::setDOMException(SYNTAX_ERR);
516            return notHandledByInterceptor();
517        }
518        // Fall through
519    } else if (args.Length() == 9) {
520        int internalformat = toInt32(args[2], ok);
521        if (!ok) {
522            V8Proxy::setDOMException(SYNTAX_ERR);
523            return notHandledByInterceptor();
524        }
525        int width = toInt32(args[3], ok);
526        if (!ok) {
527            V8Proxy::setDOMException(SYNTAX_ERR);
528            return notHandledByInterceptor();
529        }
530        int height = toInt32(args[4], ok);
531        if (!ok) {
532            V8Proxy::setDOMException(SYNTAX_ERR);
533            return notHandledByInterceptor();
534        }
535        int border = toInt32(args[5], ok);
536        if (!ok) {
537            V8Proxy::setDOMException(SYNTAX_ERR);
538            return notHandledByInterceptor();
539        }
540        int format = toInt32(args[6], ok);
541        if (!ok) {
542            V8Proxy::setDOMException(SYNTAX_ERR);
543            return notHandledByInterceptor();
544        }
545        int type = toInt32(args[7], ok);
546        if (!ok) {
547            V8Proxy::setDOMException(SYNTAX_ERR);
548            return notHandledByInterceptor();
549        }
550        v8::Handle<v8::Value> arg = args[8];
551        if (!arg->IsObject())
552        // Assume that the user is passing null for texture
553            context->texImage2D(target,
554                                level,
555                                internalformat,
556                                width,
557                                height,
558                                border,
559                                format,
560                                type,
561                                0,
562                                ec);
563     else if (V8WebGLArray::HasInstance(arg)) {
564            WebGLArray* array = V8WebGLArray::toNative(arg->ToObject());
565            context->texImage2D(target,
566                                level,
567                                internalformat,
568                                width,
569                                height,
570                                border,
571                                format,
572                                type,
573                                array,
574                                ec);
575            // Fall through
576        } else {
577            V8Proxy::setDOMException(SYNTAX_ERR);
578            return notHandledByInterceptor();
579        }
580    } else {
581        ASSERT_NOT_REACHED();
582        V8Proxy::setDOMException(SYNTAX_ERR);
583        return notHandledByInterceptor();
584    }
585    if (ec) {
586        V8Proxy::setDOMException(ec);
587        return v8::Handle<v8::Value>();
588    }
589    return v8::Undefined();
590}
591
592v8::Handle<v8::Value> V8WebGLRenderingContext::texSubImage2DCallback(const v8::Arguments& args)
593{
594    INC_STATS("DOM.WebGLRenderingContext.texSubImage2D()");
595
596    // Currently supported forms:
597    // * void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset,
598    //                      in GLsizei width, in GLsizei height,
599    //                      in GLenum format, in GLenum type, in WebGLArray pixels);
600    // * void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset,
601    //                      in ImageData pixels, [Optional] GLboolean flipY, [Optional] in premultiplyAlpha);
602    // * void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset,
603    //                      in HTMLImageElement image, [Optional] GLboolean flipY, [Optional] in premultiplyAlpha);
604    // * void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset,
605    //                      in HTMLCanvasElement canvas, [Optional] GLboolean flipY, [Optional] in premultiplyAlpha);
606    // * void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset,
607    //                      in HTMLVideoElement video, [Optional] GLboolean flipY, [Optional] in premultiplyAlpha);
608
609    if (args.Length() != 5 &&
610        args.Length() != 6 &&
611        args.Length() != 7 &&
612        args.Length() != 9) {
613        V8Proxy::setDOMException(SYNTAX_ERR);
614        return notHandledByInterceptor();
615    }
616
617    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
618    bool ok;
619    int target = toInt32(args[0], ok);
620    if (!ok) {
621        V8Proxy::setDOMException(SYNTAX_ERR);
622        return notHandledByInterceptor();
623    }
624    int level = toInt32(args[1], ok);
625    if (!ok) {
626        V8Proxy::setDOMException(SYNTAX_ERR);
627        return notHandledByInterceptor();
628    }
629    int xoff = toInt32(args[2], ok);
630    if (!ok) {
631        V8Proxy::setDOMException(SYNTAX_ERR);
632        return notHandledByInterceptor();
633    }
634    int yoff = toInt32(args[3], ok);
635    if (!ok) {
636        V8Proxy::setDOMException(SYNTAX_ERR);
637        return notHandledByInterceptor();
638    }
639
640    ExceptionCode ec = 0;
641    if (args.Length() == 5 ||
642        args.Length() == 6 ||
643        args.Length() == 7) {
644        bool flipY = false;
645        bool premultiplyAlpha = false;
646        if (args.Length() >= 6)
647            flipY = args[5]->BooleanValue();
648        if (args.Length() >= 7)
649            premultiplyAlpha = args[6]->BooleanValue();
650
651        v8::Handle<v8::Value> arg = args[4];
652        if (V8HTMLImageElement::HasInstance(arg)) {
653            HTMLImageElement* element = V8HTMLImageElement::toNative(v8::Handle<v8::Object>::Cast(arg));
654            context->texSubImage2D(target, level, xoff, yoff, element, flipY, premultiplyAlpha, ec);
655        } else if (V8HTMLCanvasElement::HasInstance(arg)) {
656            HTMLCanvasElement* element = V8HTMLCanvasElement::toNative(v8::Handle<v8::Object>::Cast(arg));
657            context->texSubImage2D(target, level, xoff, yoff, element, flipY, premultiplyAlpha, ec);
658        } else if(V8ImageData::HasInstance(arg)) {
659            ImageData* imageElement = V8ImageData::toNative(v8::Handle<v8::Object>::Cast(arg));
660            context->texSubImage2D(target, level, xoff, yoff, imageElement, flipY, premultiplyAlpha, ec);
661        } else if (V8HTMLVideoElement::HasInstance(arg)) {
662            HTMLVideoElement* element = V8HTMLVideoElement::toNative(v8::Handle<v8::Object>::Cast(arg));
663            context->texSubImage2D(target, level, xoff, yoff, element, flipY, premultiplyAlpha, ec);
664        }
665        else {
666            // FIXME: consider different / better exception type.
667            V8Proxy::setDOMException(SYNTAX_ERR);
668            return notHandledByInterceptor();
669        }
670        // Fall through
671    } else if (args.Length() == 9) {
672        int width = toInt32(args[4], ok);
673        if (!ok) {
674            V8Proxy::setDOMException(SYNTAX_ERR);
675            return notHandledByInterceptor();
676        }
677        int height = toInt32(args[5], ok);
678        if (!ok) {
679            V8Proxy::setDOMException(SYNTAX_ERR);
680            return notHandledByInterceptor();
681        }
682        int format = toInt32(args[6], ok);
683        if (!ok) {
684            V8Proxy::setDOMException(SYNTAX_ERR);
685            return notHandledByInterceptor();
686        }
687        int type = toInt32(args[7], ok);
688        if (!ok) {
689            V8Proxy::setDOMException(SYNTAX_ERR);
690            return notHandledByInterceptor();
691        }
692        v8::Handle<v8::Value> arg = args[8];
693        if (!arg->IsObject())
694        // Assume that the user is passing null for texture
695            context->texSubImage2D(target,
696                                   level,
697                                   xoff,
698                                   yoff,
699                                   width,
700                                   height,
701                                   format,
702                                   type,
703                                   0,
704                                   ec);
705     else if (V8WebGLArray::HasInstance(arg)) {
706            WebGLArray* array = V8WebGLArray::toNative(arg->ToObject());
707            context->texSubImage2D(target,
708                                   level,
709                                   xoff,
710                                   yoff,
711                                   width,
712                                   height,
713                                   format,
714                                   type,
715                                   array,
716                                   ec);
717            // Fall through
718        } else {
719            V8Proxy::setDOMException(SYNTAX_ERR);
720            return notHandledByInterceptor();
721        }
722    } else {
723        ASSERT_NOT_REACHED();
724        V8Proxy::setDOMException(SYNTAX_ERR);
725        return notHandledByInterceptor();
726    }
727    if (ec) {
728        V8Proxy::setDOMException(ec);
729        return v8::Handle<v8::Value>();
730    }
731    return v8::Undefined();
732}
733
734enum FunctionToCall {
735    kUniform1v, kUniform2v, kUniform3v, kUniform4v,
736    kVertexAttrib1v, kVertexAttrib2v, kVertexAttrib3v, kVertexAttrib4v
737};
738
739bool isFunctionToCallForAttribute(FunctionToCall functionToCall)
740{
741    switch (functionToCall) {
742    case kVertexAttrib1v:
743    case kVertexAttrib2v:
744    case kVertexAttrib3v:
745    case kVertexAttrib4v:
746        return true;
747    default:
748        break;
749    }
750    return false;
751}
752
753static v8::Handle<v8::Value> vertexAttribAndUniformHelperf(const v8::Arguments& args,
754                                                           FunctionToCall functionToCall) {
755    // Forms:
756    // * glUniform1fv(WebGLUniformLocation location, Array data);
757    // * glUniform1fv(WebGLUniformLocation location, WebGLFloatArray data);
758    // * glUniform2fv(WebGLUniformLocation location, Array data);
759    // * glUniform2fv(WebGLUniformLocation location, WebGLFloatArray data);
760    // * glUniform3fv(WebGLUniformLocation location, Array data);
761    // * glUniform3fv(WebGLUniformLocation location, WebGLFloatArray data);
762    // * glUniform4fv(WebGLUniformLocation location, Array data);
763    // * glUniform4fv(WebGLUniformLocation location, WebGLFloatArray data);
764    // * glVertexAttrib1fv(GLint index, Array data);
765    // * glVertexAttrib1fv(GLint index, WebGLFloatArray data);
766    // * glVertexAttrib2fv(GLint index, Array data);
767    // * glVertexAttrib2fv(GLint index, WebGLFloatArray data);
768    // * glVertexAttrib3fv(GLint index, Array data);
769    // * glVertexAttrib3fv(GLint index, WebGLFloatArray data);
770    // * glVertexAttrib4fv(GLint index, Array data);
771    // * glVertexAttrib4fv(GLint index, WebGLFloatArray data);
772
773    if (args.Length() != 2) {
774        V8Proxy::setDOMException(SYNTAX_ERR);
775        return notHandledByInterceptor();
776    }
777
778    bool ok = false;
779    int index = -1;
780    WebGLUniformLocation* location = 0;
781
782    if (isFunctionToCallForAttribute(functionToCall))
783        index = toInt32(args[0], ok);
784    else
785        location = toWebGLUniformLocation(args[0], ok);
786
787    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
788
789    if (!ok) {
790        V8Proxy::setDOMException(SYNTAX_ERR);
791        return notHandledByInterceptor();
792    }
793    if (V8WebGLFloatArray::HasInstance(args[1])) {
794        WebGLFloatArray* array = V8WebGLFloatArray::toNative(args[1]->ToObject());
795        ASSERT(array != NULL);
796        ExceptionCode ec = 0;
797        switch (functionToCall) {
798            case kUniform1v: context->uniform1fv(location, array, ec); break;
799            case kUniform2v: context->uniform2fv(location, array, ec); break;
800            case kUniform3v: context->uniform3fv(location, array, ec); break;
801            case kUniform4v: context->uniform4fv(location, array, ec); break;
802            case kVertexAttrib1v: context->vertexAttrib1fv(index, array); break;
803            case kVertexAttrib2v: context->vertexAttrib2fv(index, array); break;
804            case kVertexAttrib3v: context->vertexAttrib3fv(index, array); break;
805            case kVertexAttrib4v: context->vertexAttrib4fv(index, array); break;
806            default: ASSERT_NOT_REACHED(); break;
807        }
808        if (ec)
809            V8Proxy::setDOMException(ec);
810        return v8::Undefined();
811    }
812
813    v8::Handle<v8::Array> array =
814      v8::Local<v8::Array>::Cast(args[1]);
815    if (array.IsEmpty()) {
816        V8Proxy::setDOMException(SYNTAX_ERR);
817        return notHandledByInterceptor();
818    }
819    uint32_t len = array->Length();
820    float* data = jsArrayToFloatArray(array, len);
821    if (!data) {
822        // FIXME: consider different / better exception type.
823        V8Proxy::setDOMException(SYNTAX_ERR);
824        return notHandledByInterceptor();
825    }
826    ExceptionCode ec = 0;
827    switch (functionToCall) {
828        case kUniform1v: context->uniform1fv(location, data, len, ec); break;
829        case kUniform2v: context->uniform2fv(location, data, len, ec); break;
830        case kUniform3v: context->uniform3fv(location, data, len, ec); break;
831        case kUniform4v: context->uniform4fv(location, data, len, ec); break;
832        case kVertexAttrib1v: context->vertexAttrib1fv(index, data, len); break;
833        case kVertexAttrib2v: context->vertexAttrib2fv(index, data, len); break;
834        case kVertexAttrib3v: context->vertexAttrib3fv(index, data, len); break;
835        case kVertexAttrib4v: context->vertexAttrib4fv(index, data, len); break;
836        default: ASSERT_NOT_REACHED(); break;
837    }
838    fastFree(data);
839    if (ec)
840        V8Proxy::setDOMException(ec);
841    return v8::Undefined();
842}
843
844static v8::Handle<v8::Value> uniformHelperi(const v8::Arguments& args,
845                                            FunctionToCall functionToCall) {
846    // Forms:
847    // * glUniform1iv(GLUniformLocation location, Array data);
848    // * glUniform1iv(GLUniformLocation location, WebGLIntArray data);
849    // * glUniform2iv(GLUniformLocation location, Array data);
850    // * glUniform2iv(GLUniformLocation location, WebGLIntArray data);
851    // * glUniform3iv(GLUniformLocation location, Array data);
852    // * glUniform3iv(GLUniformLocation location, WebGLIntArray data);
853    // * glUniform4iv(GLUniformLocation location, Array data);
854    // * glUniform4iv(GLUniformLocation location, WebGLIntArray data);
855
856    if (args.Length() != 2) {
857        V8Proxy::setDOMException(SYNTAX_ERR);
858        return notHandledByInterceptor();
859    }
860
861    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
862    bool ok = false;
863    WebGLUniformLocation* location = toWebGLUniformLocation(args[0], ok);
864
865    if (!ok) {
866        V8Proxy::setDOMException(SYNTAX_ERR);
867        return notHandledByInterceptor();
868    }
869    if (V8WebGLIntArray::HasInstance(args[1])) {
870        WebGLIntArray* array = V8WebGLIntArray::toNative(args[1]->ToObject());
871        ASSERT(array != NULL);
872        ExceptionCode ec = 0;
873        switch (functionToCall) {
874            case kUniform1v: context->uniform1iv(location, array, ec); break;
875            case kUniform2v: context->uniform2iv(location, array, ec); break;
876            case kUniform3v: context->uniform3iv(location, array, ec); break;
877            case kUniform4v: context->uniform4iv(location, array, ec); break;
878            default: ASSERT_NOT_REACHED(); break;
879        }
880        if (ec)
881            V8Proxy::setDOMException(ec);
882        return v8::Undefined();
883    }
884
885    v8::Handle<v8::Array> array =
886      v8::Local<v8::Array>::Cast(args[1]);
887    if (array.IsEmpty()) {
888        V8Proxy::setDOMException(SYNTAX_ERR);
889        return notHandledByInterceptor();
890    }
891    uint32_t len = array->Length();
892    int* data = jsArrayToIntArray(array, len);
893    if (!data) {
894        // FIXME: consider different / better exception type.
895        V8Proxy::setDOMException(SYNTAX_ERR);
896        return notHandledByInterceptor();
897    }
898    ExceptionCode ec = 0;
899    switch (functionToCall) {
900        case kUniform1v: context->uniform1iv(location, data, len, ec); break;
901        case kUniform2v: context->uniform2iv(location, data, len, ec); break;
902        case kUniform3v: context->uniform3iv(location, data, len, ec); break;
903        case kUniform4v: context->uniform4iv(location, data, len, ec); break;
904        default: ASSERT_NOT_REACHED(); break;
905    }
906    fastFree(data);
907    if (ec)
908        V8Proxy::setDOMException(ec);
909    return v8::Undefined();
910}
911
912v8::Handle<v8::Value> V8WebGLRenderingContext::uniform1fvCallback(const v8::Arguments& args)
913{
914    INC_STATS("DOM.WebGLRenderingContext.uniform1fv()");
915    return vertexAttribAndUniformHelperf(args, kUniform1v);
916}
917
918v8::Handle<v8::Value> V8WebGLRenderingContext::uniform1ivCallback(const v8::Arguments& args)
919{
920    INC_STATS("DOM.WebGLRenderingContext.uniform1iv()");
921    return uniformHelperi(args, kUniform1v);
922}
923
924v8::Handle<v8::Value> V8WebGLRenderingContext::uniform2fvCallback(const v8::Arguments& args)
925{
926    INC_STATS("DOM.WebGLRenderingContext.uniform2fv()");
927    return vertexAttribAndUniformHelperf(args, kUniform2v);
928}
929
930v8::Handle<v8::Value> V8WebGLRenderingContext::uniform2ivCallback(const v8::Arguments& args)
931{
932    INC_STATS("DOM.WebGLRenderingContext.uniform2iv()");
933    return uniformHelperi(args, kUniform2v);
934}
935
936v8::Handle<v8::Value> V8WebGLRenderingContext::uniform3fvCallback(const v8::Arguments& args)
937{
938    INC_STATS("DOM.WebGLRenderingContext.uniform3fv()");
939    return vertexAttribAndUniformHelperf(args, kUniform3v);
940}
941
942v8::Handle<v8::Value> V8WebGLRenderingContext::uniform3ivCallback(const v8::Arguments& args)
943{
944    INC_STATS("DOM.WebGLRenderingContext.uniform3iv()");
945    return uniformHelperi(args, kUniform3v);
946}
947
948v8::Handle<v8::Value> V8WebGLRenderingContext::uniform4fvCallback(const v8::Arguments& args)
949{
950    INC_STATS("DOM.WebGLRenderingContext.uniform4fv()");
951    return vertexAttribAndUniformHelperf(args, kUniform4v);
952}
953
954v8::Handle<v8::Value> V8WebGLRenderingContext::uniform4ivCallback(const v8::Arguments& args)
955{
956    INC_STATS("DOM.WebGLRenderingContext.uniform4iv()");
957    return uniformHelperi(args, kUniform4v);
958}
959
960static v8::Handle<v8::Value> uniformMatrixHelper(const v8::Arguments& args,
961                                                 int matrixSize)
962{
963    // Forms:
964    // * glUniformMatrix2fv(GLint location, GLboolean transpose, Array data);
965    // * glUniformMatrix2fv(GLint location, GLboolean transpose, WebGLFloatArray data);
966    // * glUniformMatrix3fv(GLint location, GLboolean transpose, Array data);
967    // * glUniformMatrix3fv(GLint location, GLboolean transpose, WebGLFloatArray data);
968    // * glUniformMatrix4fv(GLint location, GLboolean transpose, Array data);
969    // * glUniformMatrix4fv(GLint location, GLboolean transpose, WebGLFloatArray data);
970    //
971    // FIXME: need to change to accept WebGLFloatArray as well.
972    if (args.Length() != 3) {
973        V8Proxy::setDOMException(SYNTAX_ERR);
974        return notHandledByInterceptor();
975    }
976
977    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
978
979    bool ok = false;
980    WebGLUniformLocation* location = toWebGLUniformLocation(args[0], ok);
981
982    if (!ok) {
983        V8Proxy::setDOMException(SYNTAX_ERR);
984        return notHandledByInterceptor();
985    }
986    bool transpose = args[1]->BooleanValue();
987    if (V8WebGLFloatArray::HasInstance(args[2])) {
988        WebGLFloatArray* array = V8WebGLFloatArray::toNative(args[2]->ToObject());
989        ASSERT(array != NULL);
990        ExceptionCode ec = 0;
991        switch (matrixSize) {
992            case 2: context->uniformMatrix2fv(location, transpose, array, ec); break;
993            case 3: context->uniformMatrix3fv(location, transpose, array, ec); break;
994            case 4: context->uniformMatrix4fv(location, transpose, array, ec); break;
995            default: ASSERT_NOT_REACHED(); break;
996        }
997        if (ec)
998            V8Proxy::setDOMException(ec);
999        return v8::Undefined();
1000    }
1001
1002    v8::Handle<v8::Array> array =
1003      v8::Local<v8::Array>::Cast(args[2]);
1004    if (array.IsEmpty()) {
1005        V8Proxy::setDOMException(SYNTAX_ERR);
1006        return notHandledByInterceptor();
1007    }
1008    uint32_t len = array->Length();
1009    float* data = jsArrayToFloatArray(array, len);
1010    if (!data) {
1011        // FIXME: consider different / better exception type.
1012        V8Proxy::setDOMException(SYNTAX_ERR);
1013        return notHandledByInterceptor();
1014    }
1015    ExceptionCode ec = 0;
1016    switch (matrixSize) {
1017        case 2: context->uniformMatrix2fv(location, transpose, data, len, ec); break;
1018        case 3: context->uniformMatrix3fv(location, transpose, data, len, ec); break;
1019        case 4: context->uniformMatrix4fv(location, transpose, data, len, ec); break;
1020        default: ASSERT_NOT_REACHED(); break;
1021    }
1022    fastFree(data);
1023    if (ec)
1024        V8Proxy::setDOMException(ec);
1025    return v8::Undefined();
1026}
1027
1028v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix2fvCallback(const v8::Arguments& args)
1029{
1030    INC_STATS("DOM.WebGLRenderingContext.uniformMatrix2fv()");
1031    return uniformMatrixHelper(args, 2);
1032}
1033
1034v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix3fvCallback(const v8::Arguments& args)
1035{
1036    INC_STATS("DOM.WebGLRenderingContext.uniformMatrix3fv()");
1037    return uniformMatrixHelper(args, 3);
1038}
1039
1040v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix4fvCallback(const v8::Arguments& args)
1041{
1042    INC_STATS("DOM.WebGLRenderingContext.uniformMatrix4fv()");
1043    return uniformMatrixHelper(args, 4);
1044}
1045
1046v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib1fvCallback(const v8::Arguments& args)
1047{
1048    INC_STATS("DOM.WebGLRenderingContext.vertexAttrib1fv()");
1049    return vertexAttribAndUniformHelperf(args, kVertexAttrib1v);
1050}
1051
1052v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib2fvCallback(const v8::Arguments& args)
1053{
1054    INC_STATS("DOM.WebGLRenderingContext.vertexAttrib2fv()");
1055    return vertexAttribAndUniformHelperf(args, kVertexAttrib2v);
1056}
1057
1058v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib3fvCallback(const v8::Arguments& args)
1059{
1060    INC_STATS("DOM.WebGLRenderingContext.vertexAttrib3fv()");
1061    return vertexAttribAndUniformHelperf(args, kVertexAttrib3v);
1062}
1063
1064v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib4fvCallback(const v8::Arguments& args)
1065{
1066    INC_STATS("DOM.WebGLRenderingContext.vertexAttrib4fv()");
1067    return vertexAttribAndUniformHelperf(args, kVertexAttrib4v);
1068}
1069
1070} // namespace WebCore
1071
1072#endif // ENABLE(3D_CANVAS)
1073