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