/* * 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 "JSFloatArray.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 "FloatArray.h" #include "WebGLFramebuffer.h" #include "WebGLGetInfo.h" #include "Int32Array.h" #include "WebGLProgram.h" #include "WebGLRenderingContext.h" #include #include #include #if ENABLE(VIDEO) #include "HTMLVideoElement.h" #include "JSHTMLVideoElement.h" #endif using namespace JSC; namespace WebCore { JSValue JSWebGLRenderingContext::bufferData(JSC::ExecState* exec) { if (exec->argumentCount() != 3) return throwError(exec, SyntaxError); unsigned target = exec->argument(0).toInt32(exec); unsigned usage = exec->argument(2).toInt32(exec); ExceptionCode ec = 0; // If argument 1 is a number, we are initializing this buffer to that size if (!exec->argument(1).isObject()) { unsigned int count = exec->argument(1).toInt32(exec); static_cast(impl())->bufferData(target, count, usage, ec); } else { ArrayBufferView* array = toArrayBufferView(exec->argument(1)); static_cast(impl())->bufferData(target, array, usage, ec); } setDOMException(exec, ec); return jsUndefined(); } JSValue JSWebGLRenderingContext::bufferSubData(JSC::ExecState* exec) { if (exec->argumentCount() != 3) return throwError(exec, SyntaxError); unsigned target = exec->argument(0).toInt32(exec); unsigned offset = exec->argument(1).toInt32(exec); ExceptionCode ec = 0; ArrayBufferView* array = toArrayBufferView(exec->argument(2)); static_cast(impl())->bufferSubData(target, offset, array, ec); setDOMException(exec, ec); return jsUndefined(); } static JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, const WebGLGetInfo& info) { switch (info.getType()) { case WebGLGetInfo::kTypeBool: return jsBoolean(info.getBool()); 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 throwError(exec, SyntaxError); 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::getBufferParameter(ExecState* exec) { return getObjectParameter(this, exec, kBuffer); } JSValue JSWebGLRenderingContext::getFramebufferAttachmentParameter(ExecState* exec) { if (exec->argumentCount() != 3) return throwError(exec, SyntaxError); 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 throwError(exec, SyntaxError); 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 throwError(exec, SyntaxError); 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 throwError(exec, SyntaxError); 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 throwError(exec, SyntaxError); 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); } // void texImage2D(in GLenum target, in GLint level, in GLenum internalformat, in GLsizei width, in GLsizei height, in GLint border, in GLenum format, in GLenum type, in ArrayBufferView pixels); // void texImage2D(in GLenum target, in GLint level, in ImageData pixels, [Optional] GLboolean flipY, [Optional] in premultiplyAlpha); // void texImage2D(in GLenum target, in GLint level, in HTMLImageElement image, [Optional] in GLboolean flipY, [Optional] in premultiplyAlpha); // void texImage2D(in GLenum target, in GLint level, in HTMLCanvasElement canvas, [Optional] in GLboolean flipY, [Optional] in premultiplyAlpha); // void texImage2D(in GLenum target, in GLint level, in HTMLVideoElement video, [Optional] in GLboolean flipY, [Optional] in premultiplyAlpha); JSValue JSWebGLRenderingContext::texImage2D(ExecState* exec) { if (exec->argumentCount() < 3 || exec->argumentCount() > 9) return throwError(exec, SyntaxError); ExceptionCode ec = 0; WebGLRenderingContext* context = static_cast(impl()); unsigned target = exec->argument(0).toInt32(exec); if (exec->hadException()) return jsUndefined(); unsigned level = exec->argument(1).toInt32(exec); if (exec->hadException()) return jsUndefined(); JSObject* o = 0; if (exec->argumentCount() <= 5) { // This is one of the last 4 forms. Param 2 can be ImageData or , or