/* * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #if ENABLE(3D_CANVAS) #include "V8WebGLRenderingContext.h" #include "ExceptionCode.h" #include "NotImplemented.h" #include #include "V8Binding.h" #include "V8ArrayBufferView.h" #include "V8WebGLBuffer.h" #include "V8Int8Array.h" #include "V8Float32Array.h" #include "V8WebGLFramebuffer.h" #include "V8Int32Array.h" #include "V8WebGLProgram.h" #include "V8WebGLRenderbuffer.h" #include "V8WebGLShader.h" #include "V8Int16Array.h" #include "V8WebGLTexture.h" #include "V8WebGLUniformLocation.h" #include "V8Uint8Array.h" #include "V8Uint32Array.h" #include "V8Uint16Array.h" #include "V8HTMLCanvasElement.h" #include "V8HTMLImageElement.h" #include "V8HTMLVideoElement.h" #include "V8ImageData.h" #include "V8Proxy.h" #include "WebGLRenderingContext.h" namespace WebCore { // Allocates new storage via tryFastMalloc. // Returns NULL if array failed to convert for any reason. static float* jsArrayToFloatArray(v8::Handle array, uint32_t len) { // Convert the data element-by-element. float* data; if (!tryFastMalloc(len * sizeof(float)).getValue(data)) return 0; for (uint32_t i = 0; i < len; i++) { v8::Local val = array->Get(v8::Integer::New(i)); if (!val->IsNumber()) { fastFree(data); return 0; } data[i] = toFloat(val); } return data; } // Allocates new storage via tryFastMalloc. // Returns NULL if array failed to convert for any reason. static int* jsArrayToIntArray(v8::Handle array, uint32_t len) { // Convert the data element-by-element. int* data; if (!tryFastMalloc(len * sizeof(int)).getValue(data)) return 0; for (uint32_t i = 0; i < len; i++) { v8::Local val = array->Get(v8::Integer::New(i)); bool ok; int ival = toInt32(val, ok); if (!ok) { fastFree(data); return 0; } data[i] = ival; } return data; } static v8::Handle toV8Object(const WebGLGetInfo& info) { switch (info.getType()) { case WebGLGetInfo::kTypeBool: return v8::Boolean::New(info.getBool()); case WebGLGetInfo::kTypeBoolArray: { const Vector& value = info.getBoolArray(); v8::Local array = v8::Array::New(value.size()); for (size_t ii = 0; ii < value.size(); ++ii) array->Set(v8::Integer::New(ii), v8::Boolean::New(value[ii])); return array; } case WebGLGetInfo::kTypeFloat: return v8::Number::New(info.getFloat()); case WebGLGetInfo::kTypeLong: return v8::Integer::New(info.getLong()); case WebGLGetInfo::kTypeNull: return v8::Null(); case WebGLGetInfo::kTypeString: return v8::String::New(fromWebCoreString(info.getString()), info.getString().length()); case WebGLGetInfo::kTypeUnsignedLong: return v8::Integer::NewFromUnsigned(info.getUnsignedLong()); case WebGLGetInfo::kTypeWebGLBuffer: return toV8(info.getWebGLBuffer()); case WebGLGetInfo::kTypeWebGLFloatArray: return toV8(info.getWebGLFloatArray()); case WebGLGetInfo::kTypeWebGLFramebuffer: return toV8(info.getWebGLFramebuffer()); case WebGLGetInfo::kTypeWebGLIntArray: return toV8(info.getWebGLIntArray()); // FIXME: implement WebGLObjectArray // case WebGLGetInfo::kTypeWebGLObjectArray: case WebGLGetInfo::kTypeWebGLProgram: return toV8(info.getWebGLProgram()); case WebGLGetInfo::kTypeWebGLRenderbuffer: return toV8(info.getWebGLRenderbuffer()); case WebGLGetInfo::kTypeWebGLTexture: return toV8(info.getWebGLTexture()); case WebGLGetInfo::kTypeWebGLUnsignedByteArray: return toV8(info.getWebGLUnsignedByteArray()); default: notImplemented(); return v8::Undefined(); } } enum ObjectType { kBuffer, kRenderbuffer, kTexture, kVertexAttrib }; static v8::Handle getObjectParameter(const v8::Arguments& args, ObjectType objectType) { if (args.Length() != 2) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } ExceptionCode ec = 0; WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); bool ok; unsigned target = toInt32(args[0], ok); if (!ok) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } unsigned pname = toInt32(args[1], ok); if (!ok) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } WebGLGetInfo info; switch (objectType) { case kBuffer: info = context->getBufferParameter(target, pname, ec); break; case kRenderbuffer: info = context->getRenderbufferParameter(target, pname, ec); break; case kTexture: info = context->getTexParameter(target, pname, ec); break; case kVertexAttrib: // target => index info = context->getVertexAttrib(target, pname, ec); break; default: notImplemented(); break; } if (ec) { V8Proxy::setDOMException(ec); return v8::Undefined(); } return toV8Object(info); } static WebGLUniformLocation* toWebGLUniformLocation(v8::Handle value, bool& ok) { ok = false; WebGLUniformLocation* location = 0; if (V8WebGLUniformLocation::HasInstance(value)) { location = V8WebGLUniformLocation::toNative(value->ToObject()); ok = true; } return location; } enum WhichProgramCall { kProgramParameter, kUniform }; v8::Handle V8WebGLRenderingContext::getAttachedShadersCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getAttachedShaders()"); if (args.Length() < 1) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } ExceptionCode ec = 0; WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle::Cast(args[0])) : 0; Vector shaders; bool succeed = context->getAttachedShaders(program, shaders, ec); if (ec) { V8Proxy::setDOMException(ec); return v8::Undefined(); } if (!succeed) return v8::Undefined(); v8::Local array = v8::Array::New(shaders.size()); for (size_t ii = 0; ii < shaders.size(); ++ii) array->Set(v8::Integer::New(ii), toV8(shaders[ii])); return array; } v8::Handle V8WebGLRenderingContext::getBufferParameterCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getBufferParameter()"); return getObjectParameter(args, kBuffer); } v8::Handle V8WebGLRenderingContext::getFramebufferAttachmentParameterCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getFramebufferAttachmentParameter()"); if (args.Length() != 3) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } ExceptionCode ec = 0; WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); bool ok; unsigned target = toInt32(args[0], ok); if (!ok) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } unsigned attachment = toInt32(args[1], ok); if (!ok) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } unsigned pname = toInt32(args[2], ok); if (!ok) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } WebGLGetInfo info = context->getFramebufferAttachmentParameter(target, attachment, pname, ec); if (ec) { V8Proxy::setDOMException(ec); return v8::Undefined(); } return toV8Object(info); } v8::Handle V8WebGLRenderingContext::getParameterCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getParameter()"); if (args.Length() != 1) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } ExceptionCode ec = 0; WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); bool ok; unsigned pname = toInt32(args[0], ok); if (!ok) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } WebGLGetInfo info = context->getParameter(pname, ec); if (ec) { V8Proxy::setDOMException(ec); return v8::Undefined(); } return toV8Object(info); } v8::Handle V8WebGLRenderingContext::getProgramParameterCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getProgramParameter()"); if (args.Length() != 2) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } ExceptionCode ec = 0; WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle::Cast(args[0])) : 0; bool ok; unsigned pname = toInt32(args[1], ok); if (!ok) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } WebGLGetInfo info = context->getProgramParameter(program, pname, ec); if (ec) { V8Proxy::setDOMException(ec); return v8::Undefined(); } return toV8Object(info); } v8::Handle V8WebGLRenderingContext::getRenderbufferParameterCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getRenderbufferParameter()"); return getObjectParameter(args, kRenderbuffer); } v8::Handle V8WebGLRenderingContext::getShaderParameterCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getShaderParameter()"); if (args.Length() != 2) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } ExceptionCode ec = 0; WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); WebGLShader* shader = V8WebGLShader::HasInstance(args[0]) ? V8WebGLShader::toNative(v8::Handle::Cast(args[0])) : 0; bool ok; unsigned pname = toInt32(args[1], ok); if (!ok) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } WebGLGetInfo info = context->getShaderParameter(shader, pname, ec); if (ec) { V8Proxy::setDOMException(ec); return v8::Undefined(); } return toV8Object(info); } v8::Handle V8WebGLRenderingContext::getTexParameterCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getTexParameter()"); return getObjectParameter(args, kTexture); } v8::Handle V8WebGLRenderingContext::getUniformCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getUniform()"); if (args.Length() != 2) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } ExceptionCode ec = 0; WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle::Cast(args[0])) : 0; bool ok = false; WebGLUniformLocation* location = toWebGLUniformLocation(args[1], ok); WebGLGetInfo info = context->getUniform(program, location, ec); if (ec) { V8Proxy::setDOMException(ec); return v8::Undefined(); } return toV8Object(info); } v8::Handle V8WebGLRenderingContext::getVertexAttribCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getVertexAttrib()"); return getObjectParameter(args, kVertexAttrib); } enum FunctionToCall { kUniform1v, kUniform2v, kUniform3v, kUniform4v, kVertexAttrib1v, kVertexAttrib2v, kVertexAttrib3v, kVertexAttrib4v }; bool isFunctionToCallForAttribute(FunctionToCall functionToCall) { switch (functionToCall) { case kVertexAttrib1v: case kVertexAttrib2v: case kVertexAttrib3v: case kVertexAttrib4v: return true; default: break; } return false; } static v8::Handle vertexAttribAndUniformHelperf(const v8::Arguments& args, FunctionToCall functionToCall) { // Forms: // * glUniform1fv(WebGLUniformLocation location, Array data); // * glUniform1fv(WebGLUniformLocation location, Float32Array data); // * glUniform2fv(WebGLUniformLocation location, Array data); // * glUniform2fv(WebGLUniformLocation location, Float32Array data); // * glUniform3fv(WebGLUniformLocation location, Array data); // * glUniform3fv(WebGLUniformLocation location, Float32Array data); // * glUniform4fv(WebGLUniformLocation location, Array data); // * glUniform4fv(WebGLUniformLocation location, Float32Array data); // * glVertexAttrib1fv(GLint index, Array data); // * glVertexAttrib1fv(GLint index, Float32Array data); // * glVertexAttrib2fv(GLint index, Array data); // * glVertexAttrib2fv(GLint index, Float32Array data); // * glVertexAttrib3fv(GLint index, Array data); // * glVertexAttrib3fv(GLint index, Float32Array data); // * glVertexAttrib4fv(GLint index, Array data); // * glVertexAttrib4fv(GLint index, Float32Array data); if (args.Length() != 2) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } bool ok = false; int index = -1; WebGLUniformLocation* location = 0; if (isFunctionToCallForAttribute(functionToCall)) index = toInt32(args[0], ok); else location = toWebGLUniformLocation(args[0], ok); WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); if (V8Float32Array::HasInstance(args[1])) { Float32Array* array = V8Float32Array::toNative(args[1]->ToObject()); ASSERT(array != NULL); ExceptionCode ec = 0; switch (functionToCall) { case kUniform1v: context->uniform1fv(location, array, ec); break; case kUniform2v: context->uniform2fv(location, array, ec); break; case kUniform3v: context->uniform3fv(location, array, ec); break; case kUniform4v: context->uniform4fv(location, array, ec); break; case kVertexAttrib1v: context->vertexAttrib1fv(index, array); break; case kVertexAttrib2v: context->vertexAttrib2fv(index, array); break; case kVertexAttrib3v: context->vertexAttrib3fv(index, array); break; case kVertexAttrib4v: context->vertexAttrib4fv(index, array); break; default: ASSERT_NOT_REACHED(); break; } if (ec) V8Proxy::setDOMException(ec); return v8::Undefined(); } if (args[1].IsEmpty() || !args[1]->IsArray()) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } v8::Handle array = v8::Local::Cast(args[1]); uint32_t len = array->Length(); float* data = jsArrayToFloatArray(array, len); if (!data) { // FIXME: consider different / better exception type. V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } ExceptionCode ec = 0; switch (functionToCall) { case kUniform1v: context->uniform1fv(location, data, len, ec); break; case kUniform2v: context->uniform2fv(location, data, len, ec); break; case kUniform3v: context->uniform3fv(location, data, len, ec); break; case kUniform4v: context->uniform4fv(location, data, len, ec); break; case kVertexAttrib1v: context->vertexAttrib1fv(index, data, len); break; case kVertexAttrib2v: context->vertexAttrib2fv(index, data, len); break; case kVertexAttrib3v: context->vertexAttrib3fv(index, data, len); break; case kVertexAttrib4v: context->vertexAttrib4fv(index, data, len); break; default: ASSERT_NOT_REACHED(); break; } fastFree(data); if (ec) V8Proxy::setDOMException(ec); return v8::Undefined(); } static v8::Handle uniformHelperi(const v8::Arguments& args, FunctionToCall functionToCall) { // Forms: // * glUniform1iv(GLUniformLocation location, Array data); // * glUniform1iv(GLUniformLocation location, Int32Array data); // * glUniform2iv(GLUniformLocation location, Array data); // * glUniform2iv(GLUniformLocation location, Int32Array data); // * glUniform3iv(GLUniformLocation location, Array data); // * glUniform3iv(GLUniformLocation location, Int32Array data); // * glUniform4iv(GLUniformLocation location, Array data); // * glUniform4iv(GLUniformLocation location, Int32Array data); if (args.Length() != 2) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); bool ok = false; WebGLUniformLocation* location = toWebGLUniformLocation(args[0], ok); if (V8Int32Array::HasInstance(args[1])) { Int32Array* array = V8Int32Array::toNative(args[1]->ToObject()); ASSERT(array != NULL); ExceptionCode ec = 0; switch (functionToCall) { case kUniform1v: context->uniform1iv(location, array, ec); break; case kUniform2v: context->uniform2iv(location, array, ec); break; case kUniform3v: context->uniform3iv(location, array, ec); break; case kUniform4v: context->uniform4iv(location, array, ec); break; default: ASSERT_NOT_REACHED(); break; } if (ec) V8Proxy::setDOMException(ec); return v8::Undefined(); } if (args[1].IsEmpty() || !args[1]->IsArray()) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } v8::Handle array = v8::Local::Cast(args[1]); uint32_t len = array->Length(); int* data = jsArrayToIntArray(array, len); if (!data) { // FIXME: consider different / better exception type. V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } ExceptionCode ec = 0; switch (functionToCall) { case kUniform1v: context->uniform1iv(location, data, len, ec); break; case kUniform2v: context->uniform2iv(location, data, len, ec); break; case kUniform3v: context->uniform3iv(location, data, len, ec); break; case kUniform4v: context->uniform4iv(location, data, len, ec); break; default: ASSERT_NOT_REACHED(); break; } fastFree(data); if (ec) V8Proxy::setDOMException(ec); return v8::Undefined(); } v8::Handle V8WebGLRenderingContext::uniform1fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniform1fv()"); return vertexAttribAndUniformHelperf(args, kUniform1v); } v8::Handle V8WebGLRenderingContext::uniform1ivCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniform1iv()"); return uniformHelperi(args, kUniform1v); } v8::Handle V8WebGLRenderingContext::uniform2fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniform2fv()"); return vertexAttribAndUniformHelperf(args, kUniform2v); } v8::Handle V8WebGLRenderingContext::uniform2ivCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniform2iv()"); return uniformHelperi(args, kUniform2v); } v8::Handle V8WebGLRenderingContext::uniform3fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniform3fv()"); return vertexAttribAndUniformHelperf(args, kUniform3v); } v8::Handle V8WebGLRenderingContext::uniform3ivCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniform3iv()"); return uniformHelperi(args, kUniform3v); } v8::Handle V8WebGLRenderingContext::uniform4fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniform4fv()"); return vertexAttribAndUniformHelperf(args, kUniform4v); } v8::Handle V8WebGLRenderingContext::uniform4ivCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniform4iv()"); return uniformHelperi(args, kUniform4v); } static v8::Handle uniformMatrixHelper(const v8::Arguments& args, int matrixSize) { // Forms: // * glUniformMatrix2fv(GLint location, GLboolean transpose, Array data); // * glUniformMatrix2fv(GLint location, GLboolean transpose, Float32Array data); // * glUniformMatrix3fv(GLint location, GLboolean transpose, Array data); // * glUniformMatrix3fv(GLint location, GLboolean transpose, Float32Array data); // * glUniformMatrix4fv(GLint location, GLboolean transpose, Array data); // * glUniformMatrix4fv(GLint location, GLboolean transpose, Float32Array data); // // FIXME: need to change to accept Float32Array as well. if (args.Length() != 3) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); bool ok = false; WebGLUniformLocation* location = toWebGLUniformLocation(args[0], ok); bool transpose = args[1]->BooleanValue(); if (V8Float32Array::HasInstance(args[2])) { Float32Array* array = V8Float32Array::toNative(args[2]->ToObject()); ASSERT(array != NULL); ExceptionCode ec = 0; switch (matrixSize) { case 2: context->uniformMatrix2fv(location, transpose, array, ec); break; case 3: context->uniformMatrix3fv(location, transpose, array, ec); break; case 4: context->uniformMatrix4fv(location, transpose, array, ec); break; default: ASSERT_NOT_REACHED(); break; } if (ec) V8Proxy::setDOMException(ec); return v8::Undefined(); } if (args[2].IsEmpty() || !args[2]->IsArray()) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } v8::Handle array = v8::Local::Cast(args[2]); uint32_t len = array->Length(); float* data = jsArrayToFloatArray(array, len); if (!data) { // FIXME: consider different / better exception type. V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } ExceptionCode ec = 0; switch (matrixSize) { case 2: context->uniformMatrix2fv(location, transpose, data, len, ec); break; case 3: context->uniformMatrix3fv(location, transpose, data, len, ec); break; case 4: context->uniformMatrix4fv(location, transpose, data, len, ec); break; default: ASSERT_NOT_REACHED(); break; } fastFree(data); if (ec) V8Proxy::setDOMException(ec); return v8::Undefined(); } v8::Handle V8WebGLRenderingContext::uniformMatrix2fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniformMatrix2fv()"); return uniformMatrixHelper(args, 2); } v8::Handle V8WebGLRenderingContext::uniformMatrix3fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniformMatrix3fv()"); return uniformMatrixHelper(args, 3); } v8::Handle V8WebGLRenderingContext::uniformMatrix4fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.uniformMatrix4fv()"); return uniformMatrixHelper(args, 4); } v8::Handle V8WebGLRenderingContext::vertexAttrib1fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.vertexAttrib1fv()"); return vertexAttribAndUniformHelperf(args, kVertexAttrib1v); } v8::Handle V8WebGLRenderingContext::vertexAttrib2fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.vertexAttrib2fv()"); return vertexAttribAndUniformHelperf(args, kVertexAttrib2v); } v8::Handle V8WebGLRenderingContext::vertexAttrib3fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.vertexAttrib3fv()"); return vertexAttribAndUniformHelperf(args, kVertexAttrib3v); } v8::Handle V8WebGLRenderingContext::vertexAttrib4fvCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.vertexAttrib4fv()"); return vertexAttribAndUniformHelperf(args, kVertexAttrib4v); } } // namespace WebCore #endif // ENABLE(3D_CANVAS)