WebCore/bindings/js/JSWebGLRenderingContextCustom.cpp
changeset 0 4f2f89ce4247
--- /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 <runtime/Error.h>
+#include <runtime/JSArray.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/OwnFastMallocPtr.h>
+
+#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<bool>& 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<WebGLRenderingContext*>(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<WebGLRenderingContext*>(impl());
+    WebGLProgram* program = toWebGLProgram(exec->argument(0));
+    if (exec->hadException())
+        return jsUndefined();
+    Vector<WebGLShader*> 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<WebGLRenderingContext*>(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<WebGLRenderingContext*>(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<WebGLRenderingContext*>(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<WebGLRenderingContext*>(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<WebGLRenderingContext*>(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<typename T, size_t inlineCapacity>
+bool toVector(JSC::ExecState* exec, JSC::JSValue value, Vector<T, inlineCapacity>& 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<T>(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<Float32Array> 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<float, 64> 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<Int32Array> 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<int, 64> 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<Float32Array> 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<float, 64> 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<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::uniform1iv(JSC::ExecState* exec)
+{
+    return dataFunctioni(f_uniform1v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::uniform2fv(JSC::ExecState* exec)
+{
+    return dataFunctionf(f_uniform2v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::uniform2iv(JSC::ExecState* exec)
+{
+    return dataFunctioni(f_uniform2v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::uniform3fv(JSC::ExecState* exec)
+{
+    return dataFunctionf(f_uniform3v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::uniform3iv(JSC::ExecState* exec)
+{
+    return dataFunctioni(f_uniform3v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::uniform4fv(JSC::ExecState* exec)
+{
+    return dataFunctionf(f_uniform4v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::uniform4iv(JSC::ExecState* exec)
+{
+    return dataFunctioni(f_uniform4v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::uniformMatrix2fv(JSC::ExecState* exec)
+{
+    return dataFunctionMatrix(f_uniformMatrix2fv, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::uniformMatrix3fv(JSC::ExecState* exec)
+{
+    return dataFunctionMatrix(f_uniformMatrix3fv, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::uniformMatrix4fv(JSC::ExecState* exec)
+{
+    return dataFunctionMatrix(f_uniformMatrix4fv, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::vertexAttrib1fv(JSC::ExecState* exec)
+{
+    return dataFunctionf(f_vertexAttrib1v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::vertexAttrib2fv(JSC::ExecState* exec)
+{
+    return dataFunctionf(f_vertexAttrib2v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::vertexAttrib3fv(JSC::ExecState* exec)
+{
+    return dataFunctionf(f_vertexAttrib3v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+JSC::JSValue JSWebGLRenderingContext::vertexAttrib4fv(JSC::ExecState* exec)
+{
+    return dataFunctionf(f_vertexAttrib4v, exec, static_cast<WebGLRenderingContext*>(impl()));
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)