/* * Copyright (C) 2009 Google Inc. All rights reserved. * Copyright (C) 2012 Sony Mobile Communications AB * * 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(WEBGL) #include "V8WebGLRenderingContext.h" #include "ExceptionCode.h" #include "NotImplemented.h" #include "V8ArrayBufferView.h" #include "V8Binding.h" #include "V8BindingMacros.h" #include "V8WebKitLoseContext.h" #include "V8Float32Array.h" #include "V8HTMLCanvasElement.h" #include "V8HTMLImageElement.h" #include "V8HTMLVideoElement.h" #include "V8ImageData.h" #include "V8Int16Array.h" #include "V8Int32Array.h" #include "V8Int8Array.h" #include "V8OESStandardDerivatives.h" #include "V8OESTextureFloat.h" #include "V8OESVertexArrayObject.h" #include "V8Proxy.h" #include "V8Uint16Array.h" #include "V8Uint32Array.h" #include "V8Uint8Array.h" #include "V8WebGLBuffer.h" #include "V8WebGLFramebuffer.h" #include "V8WebGLProgram.h" #include "V8WebGLRenderbuffer.h" #include "V8WebGLShader.h" #include "V8WebGLTexture.h" #include "V8WebGLUniformLocation.h" #include "V8WebGLVertexArrayObjectOES.h" #include "WebGLRenderingContext.h" #include 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::kTypeInt: return v8::Integer::New(info.getInt()); case WebGLGetInfo::kTypeNull: return v8::Null(); case WebGLGetInfo::kTypeString: return v8::String::New(fromWebCoreString(info.getString()), info.getString().length()); case WebGLGetInfo::kTypeUnsignedInt: return v8::Integer::NewFromUnsigned(info.getUnsignedInt()); 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()); case WebGLGetInfo::kTypeWebGLUnsignedIntArray: return toV8(info.getWebGLUnsignedIntArray()); case WebGLGetInfo::kTypeWebGLVertexArrayObjectOES: return toV8(info.getWebGLVertexArrayObjectOES()); default: notImplemented(); return v8::Undefined(); } } static v8::Handle toV8Object(WebGLExtension* extension, v8::Handle contextObject) { if (!extension) return v8::Null(); v8::Handle extensionObject; const char* referenceName; switch (extension->getName()) { case WebGLExtension::WebKitLoseContextName: extensionObject = toV8(static_cast(extension)); referenceName = "webKitLoseContextName"; break; case WebGLExtension::OESStandardDerivativesName: extensionObject = toV8(static_cast(extension)); referenceName = "oesStandardDerivativesName"; break; case WebGLExtension::OESTextureFloatName: extensionObject = toV8(static_cast(extension)); referenceName = "oesTextureFloatName"; break; case WebGLExtension::OESVertexArrayObjectName: extensionObject = toV8(static_cast(extension)); referenceName = "oesVertexArrayObjectName"; break; } ASSERT(!extensionObject.IsEmpty()); V8DOMWrapper::setNamedHiddenReference(contextObject, referenceName, extensionObject); return extensionObject; } 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()); unsigned target = toInt32(args[0]); unsigned pname = toInt32(args[1]); 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()); if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLProgram::HasInstance(args[0])) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } 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::Null(); } if (!succeed) return v8::Null(); 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::getExtensionCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getExtensionCallback()"); WebGLRenderingContext* imp = V8WebGLRenderingContext::toNative(args.Holder()); if (args.Length() < 1) { V8Proxy::setDOMException(SYNTAX_ERR); return notHandledByInterceptor(); } STRING_TO_V8PARAMETER_EXCEPTION_BLOCK(V8Parameter<>, name, args[0]); WebGLExtension* extension = imp->getExtension(name); return toV8Object(extension, args.Holder()); } 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()); unsigned target = toInt32(args[0]); unsigned attachment = toInt32(args[1]); unsigned pname = toInt32(args[2]); 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()); unsigned pname = toInt32(args[0]); 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()); if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLProgram::HasInstance(args[0])) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle::Cast(args[0])) : 0; unsigned pname = toInt32(args[1]); 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()); if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLShader::HasInstance(args[0])) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } WebGLShader* shader = V8WebGLShader::HasInstance(args[0]) ? V8WebGLShader::toNative(v8::Handle::Cast(args[0])) : 0; unsigned pname = toInt32(args[1]); WebGLGetInfo info = context->getShaderParameter(shader, pname, ec); if (ec) { V8Proxy::setDOMException(ec); return v8::Undefined(); } return toV8Object(info); } v8::Handle V8WebGLRenderingContext::getSupportedExtensionsCallback(const v8::Arguments& args) { INC_STATS("DOM.WebGLRenderingContext.getSupportedExtensionsCallback()"); WebGLRenderingContext* imp = V8WebGLRenderingContext::toNative(args.Holder()); if (imp->isContextLost()) return v8::Null(); Vector value = imp->getSupportedExtensions(); v8::Local array = v8::Array::New(value.size()); for (size_t ii = 0; ii < value.size(); ++ii) array->Set(v8::Integer::New(ii), v8::String::New(fromWebCoreString(value[ii]), value[ii].length())); return array; } 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()); if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLProgram::HasInstance(args[0])) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle::Cast(args[0])) : 0; if (args.Length() > 1 && !isUndefinedOrNull(args[1]) && !V8WebGLUniformLocation::HasInstance(args[1])) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } 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]); else { if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLUniformLocation::HasInstance(args[0])) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } 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()); if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLUniformLocation::HasInstance(args[0])) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } 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()); if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLUniformLocation::HasInstance(args[0])) { V8Proxy::throwTypeError(); return notHandledByInterceptor(); } 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(WEBGL)