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