diff -r 000000000000 -r 4f2f89ce4247 WebCore/bindings/js/JSWebGLRenderingContextCustom.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/bindings/js/JSWebGLRenderingContextCustom.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,633 @@ +/* + * Copyright (C) 2009 Apple 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "JSWebGLRenderingContext.h" + +#include "ExceptionCode.h" +#include "HTMLCanvasElement.h" +#include "HTMLImageElement.h" +#include "JSHTMLCanvasElement.h" +#include "JSHTMLImageElement.h" +#include "JSImageData.h" +#include "JSWebGLBuffer.h" +#include "JSFloat32Array.h" +#include "JSWebGLFramebuffer.h" +#include "JSInt32Array.h" +#include "JSWebGLProgram.h" +#include "JSWebGLRenderbuffer.h" +#include "JSWebGLShader.h" +#include "JSWebGLTexture.h" +#include "JSWebGLUniformLocation.h" +#include "JSUint8Array.h" +#include "JSWebKitCSSMatrix.h" +#include "NotImplemented.h" +#include "WebGLBuffer.h" +#include "Float32Array.h" +#include "WebGLFramebuffer.h" +#include "WebGLGetInfo.h" +#include "Int32Array.h" +#include "WebGLProgram.h" +#include "WebGLRenderingContext.h" +#include +#include +#include +#include + +#if ENABLE(VIDEO) +#include "HTMLVideoElement.h" +#include "JSHTMLVideoElement.h" +#endif + +using namespace JSC; + +namespace WebCore { + +static JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, const WebGLGetInfo& info) +{ + switch (info.getType()) { + case WebGLGetInfo::kTypeBool: + return jsBoolean(info.getBool()); + case WebGLGetInfo::kTypeBoolArray: { + MarkedArgumentBuffer list; + const Vector& value = info.getBoolArray(); + for (size_t ii = 0; ii < value.size(); ++ii) + list.append(jsBoolean(value[ii])); + return constructArray(exec, list); + } + case WebGLGetInfo::kTypeFloat: + return jsNumber(exec, info.getFloat()); + case WebGLGetInfo::kTypeLong: + return jsNumber(exec, info.getLong()); + case WebGLGetInfo::kTypeNull: + return jsNull(); + case WebGLGetInfo::kTypeString: + return jsString(exec, info.getString()); + case WebGLGetInfo::kTypeUnsignedLong: + return jsNumber(exec, info.getUnsignedLong()); + case WebGLGetInfo::kTypeWebGLBuffer: + return toJS(exec, globalObject, info.getWebGLBuffer()); + case WebGLGetInfo::kTypeWebGLFloatArray: + return toJS(exec, globalObject, info.getWebGLFloatArray()); + case WebGLGetInfo::kTypeWebGLFramebuffer: + return toJS(exec, globalObject, info.getWebGLFramebuffer()); + case WebGLGetInfo::kTypeWebGLIntArray: + return toJS(exec, globalObject, info.getWebGLIntArray()); + // FIXME: implement WebGLObjectArray + // case WebGLGetInfo::kTypeWebGLObjectArray: + case WebGLGetInfo::kTypeWebGLProgram: + return toJS(exec, globalObject, info.getWebGLProgram()); + case WebGLGetInfo::kTypeWebGLRenderbuffer: + return toJS(exec, globalObject, info.getWebGLRenderbuffer()); + case WebGLGetInfo::kTypeWebGLTexture: + return toJS(exec, globalObject, info.getWebGLTexture()); + case WebGLGetInfo::kTypeWebGLUnsignedByteArray: + return toJS(exec, globalObject, info.getWebGLUnsignedByteArray()); + default: + notImplemented(); + return jsUndefined(); + } +} + +enum ObjectType { + kBuffer, kRenderbuffer, kTexture, kVertexAttrib +}; + +static JSValue getObjectParameter(JSWebGLRenderingContext* obj, ExecState* exec, ObjectType objectType) +{ + if (exec->argumentCount() != 2) + return throwSyntaxError(exec); + + ExceptionCode ec = 0; + WebGLRenderingContext* context = static_cast(obj->impl()); + unsigned target = exec->argument(0).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + unsigned pname = exec->argument(1).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + 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) { + setDOMException(exec, ec); + return jsUndefined(); + } + return toJS(exec, obj->globalObject(), info); +} + +enum WhichProgramCall { + kProgramParameter, kUniform +}; + +JSValue JSWebGLRenderingContext::getAttachedShaders(ExecState* exec) +{ + if (exec->argumentCount() < 1) + return throwSyntaxError(exec); + ExceptionCode ec = 0; + WebGLRenderingContext* context = static_cast(impl()); + WebGLProgram* program = toWebGLProgram(exec->argument(0)); + if (exec->hadException()) + return jsUndefined(); + Vector shaders; + bool succeed = context->getAttachedShaders(program, shaders, ec); + if (ec) { + setDOMException(exec, ec); + return jsUndefined(); + } + if (!succeed) + return jsUndefined(); + MarkedArgumentBuffer list; + for (size_t ii = 0; ii < shaders.size(); ++ii) + list.append(toJS(exec, globalObject(), shaders[ii])); + return constructArray(exec, list); +} + +JSValue JSWebGLRenderingContext::getBufferParameter(ExecState* exec) +{ + return getObjectParameter(this, exec, kBuffer); +} + +JSValue JSWebGLRenderingContext::getFramebufferAttachmentParameter(ExecState* exec) +{ + if (exec->argumentCount() != 3) + return throwSyntaxError(exec); + + ExceptionCode ec = 0; + WebGLRenderingContext* context = static_cast(impl()); + unsigned target = exec->argument(0).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + unsigned attachment = exec->argument(1).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + unsigned pname = exec->argument(2).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + WebGLGetInfo info = context->getFramebufferAttachmentParameter(target, attachment, pname, ec); + if (ec) { + setDOMException(exec, ec); + return jsUndefined(); + } + return toJS(exec, globalObject(), info); +} + +JSValue JSWebGLRenderingContext::getParameter(ExecState* exec) +{ + if (exec->argumentCount() != 1) + return throwSyntaxError(exec); + + ExceptionCode ec = 0; + WebGLRenderingContext* context = static_cast(impl()); + unsigned pname = exec->argument(0).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + WebGLGetInfo info = context->getParameter(pname, ec); + if (ec) { + setDOMException(exec, ec); + return jsUndefined(); + } + return toJS(exec, globalObject(), info); +} + +JSValue JSWebGLRenderingContext::getProgramParameter(ExecState* exec) +{ + if (exec->argumentCount() != 2) + return throwSyntaxError(exec); + + ExceptionCode ec = 0; + WebGLRenderingContext* context = static_cast(impl()); + WebGLProgram* program = toWebGLProgram(exec->argument(0)); + unsigned pname = exec->argument(1).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + WebGLGetInfo info = context->getProgramParameter(program, pname, ec); + if (ec) { + setDOMException(exec, ec); + return jsUndefined(); + } + return toJS(exec, globalObject(), info); +} + +JSValue JSWebGLRenderingContext::getRenderbufferParameter(ExecState* exec) +{ + return getObjectParameter(this, exec, kRenderbuffer); +} + +JSValue JSWebGLRenderingContext::getShaderParameter(ExecState* exec) +{ + if (exec->argumentCount() != 2) + return throwSyntaxError(exec); + + ExceptionCode ec = 0; + WebGLRenderingContext* context = static_cast(impl()); + WebGLShader* shader = toWebGLShader(exec->argument(0)); + unsigned pname = exec->argument(1).toInt32(exec); + if (exec->hadException()) + return jsUndefined(); + WebGLGetInfo info = context->getShaderParameter(shader, pname, ec); + if (ec) { + setDOMException(exec, ec); + return jsUndefined(); + } + return toJS(exec, globalObject(), info); +} + +JSValue JSWebGLRenderingContext::getTexParameter(ExecState* exec) +{ + return getObjectParameter(this, exec, kTexture); +} + +JSValue JSWebGLRenderingContext::getUniform(ExecState* exec) +{ + if (exec->argumentCount() != 2) + return throwSyntaxError(exec); + + ExceptionCode ec = 0; + WebGLRenderingContext* context = static_cast(impl()); + WebGLProgram* program = toWebGLProgram(exec->argument(0)); + WebGLUniformLocation* loc = toWebGLUniformLocation(exec->argument(1)); + if (exec->hadException()) + return jsUndefined(); + WebGLGetInfo info = context->getUniform(program, loc, ec); + if (ec) { + setDOMException(exec, ec); + return jsUndefined(); + } + return toJS(exec, globalObject(), info); +} + +JSValue JSWebGLRenderingContext::getVertexAttrib(ExecState* exec) +{ + return getObjectParameter(this, exec, kVertexAttrib); +} + +template +bool toVector(JSC::ExecState* exec, JSC::JSValue value, Vector& vector) +{ + if (!value.isObject()) + return false; + + JSC::JSObject* object = asObject(value); + int32_t length = object->get(exec, JSC::Identifier(exec, "length")).toInt32(exec); + vector.resize(length); + + for (int32_t i = 0; i < length; ++i) { + JSC::JSValue v = object->get(exec, i); + if (exec->hadException()) + return false; + vector[i] = static_cast(v.toNumber(exec)); + } + + return true; +} + +enum DataFunctionToCall { + f_uniform1v, f_uniform2v, f_uniform3v, f_uniform4v, + f_vertexAttrib1v, f_vertexAttrib2v, f_vertexAttrib3v, f_vertexAttrib4v +}; + +enum DataFunctionMatrixToCall { + f_uniformMatrix2fv, f_uniformMatrix3fv, f_uniformMatrix4fv +}; + +static bool functionForUniform(DataFunctionToCall f) +{ + switch (f) { + case f_uniform1v: + case f_uniform2v: + case f_uniform3v: + case f_uniform4v: + return true; + break; + default: break; + } + return false; +} + +static JSC::JSValue dataFunctionf(DataFunctionToCall f, JSC::ExecState* exec, WebGLRenderingContext* context) +{ + if (exec->argumentCount() != 2) + return throwSyntaxError(exec); + + WebGLUniformLocation* location = 0; + long index = -1; + + if (functionForUniform(f)) + location = toWebGLUniformLocation(exec->argument(0)); + else + index = exec->argument(0).toInt32(exec); + + if (exec->hadException()) + return jsUndefined(); + + RefPtr webGLArray = toFloat32Array(exec->argument(1)); + if (exec->hadException()) + return jsUndefined(); + + ExceptionCode ec = 0; + if (webGLArray) { + switch (f) { + case f_uniform1v: + context->uniform1fv(location, webGLArray.get(), ec); + break; + case f_uniform2v: + context->uniform2fv(location, webGLArray.get(), ec); + break; + case f_uniform3v: + context->uniform3fv(location, webGLArray.get(), ec); + break; + case f_uniform4v: + context->uniform4fv(location, webGLArray.get(), ec); + break; + case f_vertexAttrib1v: + context->vertexAttrib1fv(index, webGLArray.get()); + break; + case f_vertexAttrib2v: + context->vertexAttrib2fv(index, webGLArray.get()); + break; + case f_vertexAttrib3v: + context->vertexAttrib3fv(index, webGLArray.get()); + break; + case f_vertexAttrib4v: + context->vertexAttrib4fv(index, webGLArray.get()); + break; + } + + setDOMException(exec, ec); + return jsUndefined(); + } + + Vector array; + if (!toVector(exec, exec->argument(1), array)) + return throwTypeError(exec); + + switch (f) { + case f_uniform1v: + context->uniform1fv(location, array.data(), array.size(), ec); + break; + case f_uniform2v: + context->uniform2fv(location, array.data(), array.size(), ec); + break; + case f_uniform3v: + context->uniform3fv(location, array.data(), array.size(), ec); + break; + case f_uniform4v: + context->uniform4fv(location, array.data(), array.size(), ec); + break; + case f_vertexAttrib1v: + context->vertexAttrib1fv(index, array.data(), array.size()); + break; + case f_vertexAttrib2v: + context->vertexAttrib2fv(index, array.data(), array.size()); + break; + case f_vertexAttrib3v: + context->vertexAttrib3fv(index, array.data(), array.size()); + break; + case f_vertexAttrib4v: + context->vertexAttrib4fv(index, array.data(), array.size()); + break; + } + + setDOMException(exec, ec); + return jsUndefined(); +} + +static JSC::JSValue dataFunctioni(DataFunctionToCall f, JSC::ExecState* exec, WebGLRenderingContext* context) +{ + if (exec->argumentCount() != 2) + return throwSyntaxError(exec); + + WebGLUniformLocation* location = toWebGLUniformLocation(exec->argument(0)); + + if (exec->hadException()) + return jsUndefined(); + + RefPtr webGLArray = toInt32Array(exec->argument(1)); + if (exec->hadException()) + return jsUndefined(); + + ExceptionCode ec = 0; + if (webGLArray) { + switch (f) { + case f_uniform1v: + context->uniform1iv(location, webGLArray.get(), ec); + break; + case f_uniform2v: + context->uniform2iv(location, webGLArray.get(), ec); + break; + case f_uniform3v: + context->uniform3iv(location, webGLArray.get(), ec); + break; + case f_uniform4v: + context->uniform4iv(location, webGLArray.get(), ec); + break; + default: + break; + } + + setDOMException(exec, ec); + return jsUndefined(); + } + + + Vector array; + if (!toVector(exec, exec->argument(1), array)) + return throwTypeError(exec); + + switch (f) { + case f_uniform1v: + context->uniform1iv(location, array.data(), array.size(), ec); + break; + case f_uniform2v: + context->uniform2iv(location, array.data(), array.size(), ec); + break; + case f_uniform3v: + context->uniform3iv(location, array.data(), array.size(), ec); + break; + case f_uniform4v: + context->uniform4iv(location, array.data(), array.size(), ec); + break; + default: + break; + } + + setDOMException(exec, ec); + return jsUndefined(); +} + +static JSC::JSValue dataFunctionMatrix(DataFunctionMatrixToCall f, JSC::ExecState* exec, WebGLRenderingContext* context) +{ + if (exec->argumentCount() != 3) + return throwSyntaxError(exec); + + WebGLUniformLocation* location = toWebGLUniformLocation(exec->argument(0)); + + if (exec->hadException()) + return jsUndefined(); + + bool transpose = exec->argument(1).toBoolean(exec); + if (exec->hadException()) + return jsUndefined(); + + RefPtr webGLArray = toFloat32Array(exec->argument(2)); + if (exec->hadException()) + return jsUndefined(); + + ExceptionCode ec = 0; + if (webGLArray) { + switch (f) { + case f_uniformMatrix2fv: + context->uniformMatrix2fv(location, transpose, webGLArray.get(), ec); + break; + case f_uniformMatrix3fv: + context->uniformMatrix3fv(location, transpose, webGLArray.get(), ec); + break; + case f_uniformMatrix4fv: + context->uniformMatrix4fv(location, transpose, webGLArray.get(), ec); + break; + } + + setDOMException(exec, ec); + return jsUndefined(); + } + + Vector array; + if (!toVector(exec, exec->argument(2), array)) + return throwTypeError(exec); + + switch (f) { + case f_uniformMatrix2fv: + context->uniformMatrix2fv(location, transpose, array.data(), array.size(), ec); + break; + case f_uniformMatrix3fv: + context->uniformMatrix3fv(location, transpose, array.data(), array.size(), ec); + break; + case f_uniformMatrix4fv: + context->uniformMatrix4fv(location, transpose, array.data(), array.size(), ec); + break; + } + + setDOMException(exec, ec); + return jsUndefined(); +} + +JSC::JSValue JSWebGLRenderingContext::uniform1fv(JSC::ExecState* exec) +{ + return dataFunctionf(f_uniform1v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::uniform1iv(JSC::ExecState* exec) +{ + return dataFunctioni(f_uniform1v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::uniform2fv(JSC::ExecState* exec) +{ + return dataFunctionf(f_uniform2v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::uniform2iv(JSC::ExecState* exec) +{ + return dataFunctioni(f_uniform2v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::uniform3fv(JSC::ExecState* exec) +{ + return dataFunctionf(f_uniform3v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::uniform3iv(JSC::ExecState* exec) +{ + return dataFunctioni(f_uniform3v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::uniform4fv(JSC::ExecState* exec) +{ + return dataFunctionf(f_uniform4v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::uniform4iv(JSC::ExecState* exec) +{ + return dataFunctioni(f_uniform4v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::uniformMatrix2fv(JSC::ExecState* exec) +{ + return dataFunctionMatrix(f_uniformMatrix2fv, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::uniformMatrix3fv(JSC::ExecState* exec) +{ + return dataFunctionMatrix(f_uniformMatrix3fv, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::uniformMatrix4fv(JSC::ExecState* exec) +{ + return dataFunctionMatrix(f_uniformMatrix4fv, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::vertexAttrib1fv(JSC::ExecState* exec) +{ + return dataFunctionf(f_vertexAttrib1v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::vertexAttrib2fv(JSC::ExecState* exec) +{ + return dataFunctionf(f_vertexAttrib2v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::vertexAttrib3fv(JSC::ExecState* exec) +{ + return dataFunctionf(f_vertexAttrib3v, exec, static_cast(impl())); +} + +JSC::JSValue JSWebGLRenderingContext::vertexAttrib4fv(JSC::ExecState* exec) +{ + return dataFunctionf(f_vertexAttrib4v, exec, static_cast(impl())); +} + +} // namespace WebCore + +#endif // ENABLE(3D_CANVAS)