[webgl] Reland earlier-backed out patches, b=520708, b=520920, b=522201; r=me/mwsteele
authorVladimir Vukicevic <vladimir@pobox.com>
Sun, 01 Nov 2009 16:33:39 -0800
changeset 34453 dfac413f4a89ea6c407b79c174a6b004d68fb8af
parent 34452 5fef6a5ab9dc081bb9dc01b131648a5e07171061
child 34454 2fa0a16c7af79ca9f8401219ded186d59245f701
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme, mwsteele
bugs520708, 520920, 522201
milestone1.9.3a1pre
[webgl] Reland earlier-backed out patches, b=520708, b=520920, b=522201; r=me/mwsteele
content/canvas/public/WebGLArray.h
content/canvas/src/Makefile.in
content/canvas/src/SimpleBuffer.h
content/canvas/src/WebGLArrays.cpp
content/canvas/src/WebGLArrays.h
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextNotSupported.cpp
content/canvas/src/localgl.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoID.h
dom/interfaces/canvas/nsICanvasRenderingContextWebGL.idl
layout/build/nsLayoutModule.cpp
--- a/content/canvas/public/WebGLArray.h
+++ b/content/canvas/public/WebGLArray.h
@@ -33,16 +33,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef WEBGLARRAY_H_
 #define WEBGLARRAY_H_
 
+nsresult NS_NewCanvasArrayBuffer(nsISupports **aNewObject);
 nsresult NS_NewCanvasFloatArray(nsISupports **aNewObject);
 nsresult NS_NewCanvasByteArray(nsISupports **aNewObject);
 nsresult NS_NewCanvasUnsignedByteArray(nsISupports **aNewObject);
 nsresult NS_NewCanvasShortArray(nsISupports **aNewObject);
 nsresult NS_NewCanvasUnsignedShortArray(nsISupports **aNewObject);
 nsresult NS_NewCanvasIntArray(nsISupports **aNewObject);
 nsresult NS_NewCanvasUnsignedIntArray(nsISupports **aNewObject);
 
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -53,16 +53,17 @@ CPPSRCS	= \
 	nsCanvasRenderingContext2D.cpp \
 	$(NULL)
 
 # Canvas 3D Pieces
 
 ifdef MOZ_WEBGL
 
 CPPSRCS += \
+	WebGLArrays.cpp \
 	WebGLContext.cpp \
 	WebGLContextGL.cpp \
 	WebGLContextUtils.cpp \
 	WebGLContextValidate.cpp \
 	NativeJSContext.cpp \
 	glwrap.cpp \
 	nsGLPbuffer.cpp \
 	nsGLPbufferOSMesa.cpp \
--- a/content/canvas/src/SimpleBuffer.h
+++ b/content/canvas/src/SimpleBuffer.h
@@ -80,17 +80,17 @@ public:
         if (type == LOCAL_GL_FLOAT) return sizeof(float);
         if (type == LOCAL_GL_SHORT) return sizeof(short);
         if (type == LOCAL_GL_UNSIGNED_SHORT) return sizeof(unsigned short);
         if (type == LOCAL_GL_BYTE) return 1;
         if (type == LOCAL_GL_UNSIGNED_BYTE) return 1;
         if (type == LOCAL_GL_INT) return sizeof(int);
         if (type == LOCAL_GL_UNSIGNED_INT) return sizeof(unsigned int);
         if (type == LOCAL_GL_DOUBLE) return sizeof(double);
-        return 0;
+        return 1;
     }
 
     void Clear() {
         Release();
     }
 
     void Set(PRUint32 t, PRUint32 spv, PRUint32 count, void* vals) {
         Prepare(t, spv, count);
@@ -113,16 +113,20 @@ public:
     void Release() {
         if (data)
             free(data);
         length = 0;
         capacity = 0;
         data = nsnull;
     }
 
+    void Zero() {
+        memset(data, 0, capacity);
+    }
+
     void EnsureCapacity(PRBool preserve, PRUint32 cap) {
         if (capacity >= cap)
             return;
 
         void* newdata = malloc(cap);
         if (preserve && length)
             memcpy(newdata, data, length*ElementSize());
         free(data);
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/WebGLArrays.cpp
@@ -0,0 +1,1777 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mark Steele <mwsteele@gmail.com>
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "WebGLArrays.h"
+
+#include "NativeJSContext.h"
+
+// TODO:
+// XXX: fix overflow in integer mult in ::Set!
+// XXX: get rid of code duplication, use inline helpers, templates, or macros
+// XXX: Prepare/Zero in initializers is inefficient, we should really
+//      just be doing calloc
+// XXX: array Set() shouldn't call into the inner Set(), because that
+//      repeats the length check and is probably not getting inlined
+// write benchmarks
+
+using namespace mozilla;
+
+nsresult
+NS_NewCanvasArrayBuffer(nsISupports **aResult)
+{
+    nsICanvasArrayBuffer *wgab = new WebGLArrayBuffer();
+    if (!wgab)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_ADDREF(*aResult = wgab);
+    return NS_OK;
+}
+
+WebGLArrayBuffer::WebGLArrayBuffer(PRUint32 length)
+{
+    EnsureCapacity(PR_FALSE, length);
+}
+
+NS_IMETHODIMP
+WebGLArrayBuffer::Initialize(nsISupports *owner,
+                             JSContext *cx,
+                             JSObject *obj,
+                             PRUint32 argc,
+                             jsval *argv)
+{
+    /* Constructor: WebGLArrayBuffer(n) */
+    if (JSVAL_IS_NUMBER(argv[0])) {
+        uint32 length;
+        ::JS_ValueToECMAUint32(cx, argv[0], &length);
+        if (length == 0)
+            return NS_ERROR_FAILURE;
+
+        EnsureCapacity(PR_FALSE, length);
+
+        return NS_OK;
+    }
+
+    return NS_ERROR_DOM_SYNTAX_ERR;
+}
+
+/* readonly attribute unsigned long byteLength; */
+NS_IMETHODIMP WebGLArrayBuffer::GetByteLength(PRUint32 *aByteLength)
+{
+    *aByteLength = capacity;
+    return NS_OK;
+}
+
+/* [noscript, notxpcom] voidPtr GetNativeArrayBuffer (); */
+NS_IMETHODIMP_(WebGLArrayBuffer *) WebGLArrayBuffer::GetNativeArrayBuffer()
+{
+    return this;
+}
+
+/* [noscript, notxpcom] voidPtr nativePointer (); */
+NS_IMETHODIMP_(void *) WebGLArrayBuffer::NativePointer()
+{
+    return data;
+}
+
+/* [noscript, notxpcom] unsigned long nativeSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLArrayBuffer::NativeSize()
+{
+    return capacity;
+}
+
+/*
+ * CanvasFloatArray
+ */
+
+nsresult
+NS_NewCanvasFloatArray(nsISupports **aResult)
+{
+    nsICanvasFloatArray *wgfa = new WebGLFloatArray();
+    if (!wgfa)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_ADDREF(*aResult = wgfa);
+    return NS_OK;
+}
+
+WebGLFloatArray::WebGLFloatArray(PRUint32 length)
+    : mOffset(0), mLength(length)
+{
+    mBuffer = new WebGLArrayBuffer(length * sizeof(float));
+}
+
+WebGLFloatArray::WebGLFloatArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length)
+    : mBuffer(buffer), mOffset(offset), mLength(length)
+{
+}
+
+WebGLFloatArray::WebGLFloatArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
+    : mOffset(0), mLength(arrayLen)
+{
+    mBuffer = new WebGLArrayBuffer();
+    mBuffer->InitFromJSArray(LOCAL_GL_FLOAT, 1, cx, arrayObj, arrayLen);
+}
+
+NS_IMETHODIMP
+WebGLFloatArray::Initialize(nsISupports *owner,
+                            JSContext *cx,
+                            JSObject *obj,
+                            PRUint32 argc,
+                            jsval *argv)
+{
+    if (JSVAL_IS_NUMBER(argv[0])) {
+        uint32 length;
+        ::JS_ValueToECMAUint32(cx, argv[0], &length);
+        mBuffer = new WebGLArrayBuffer();
+        mBuffer->Prepare(LOCAL_GL_FLOAT, 1, length);
+        mBuffer->Zero();
+        mLength = length;
+    } else {
+        JSObject *arrayObj;
+        jsuint arrayLen;
+        jsuint byteOffset = 0;
+        jsuint length = 0;
+
+        if (!::JS_ConvertArguments(cx, argc, argv, "o/uu", &arrayObj, &byteOffset, &length) ||
+            arrayObj == NULL)
+        {
+            return NS_ERROR_DOM_SYNTAX_ERR;
+        }
+
+        if (::JS_IsArrayObject(cx, arrayObj) &&
+            ::JS_GetArrayLength(cx, arrayObj, &arrayLen))
+        {
+            mBuffer = new WebGLArrayBuffer();
+            mBuffer->InitFromJSArray(LOCAL_GL_FLOAT, 1, cx, arrayObj, arrayLen);
+            mLength = arrayLen;
+        } else {
+            nsCOMPtr<nsICanvasArrayBuffer> canvasObj;
+            nsresult rv;
+            rv = nsContentUtils::XPConnect()->WrapJS(cx, arrayObj, NS_GET_IID(nsICanvasArrayBuffer), getter_AddRefs(canvasObj));
+            if (NS_FAILED(rv) || !canvasObj) {
+                return NS_ERROR_DOM_SYNTAX_ERR;
+            }
+
+            mBuffer = canvasObj->GetNativeArrayBuffer();
+
+            if (byteOffset % sizeof(float))
+                return NS_ERROR_FAILURE;
+
+            if ((byteOffset + (length * sizeof(float))) > mBuffer->capacity)
+                return NS_ERROR_FAILURE;
+
+            if (length > 0) {
+                mLength = length;
+            } else {
+                if ((mBuffer->capacity - byteOffset) % sizeof(float))
+                    return NS_ERROR_FAILURE;
+
+                mLength = (mBuffer->capacity - byteOffset) / sizeof(float);
+            }
+        }
+    }
+
+    return NS_OK;
+}
+
+/* readonly attribute nsICanvasArrayBuffer buffer; */
+NS_IMETHODIMP WebGLFloatArray::GetBuffer(nsICanvasArrayBuffer **aBuffer)
+{
+    NS_ADDREF(*aBuffer = mBuffer);
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteOffset; */
+NS_IMETHODIMP WebGLFloatArray::GetByteOffset(PRUint32 *aByteOffset)
+{
+    *aByteOffset = mOffset;
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteLength; */
+NS_IMETHODIMP WebGLFloatArray::GetByteLength(PRUint32 *aByteLength)
+{
+    *aByteLength = mLength * sizeof(float);
+    return NS_OK;
+}
+
+/* attribute unsigned long length; */
+NS_IMETHODIMP WebGLFloatArray::GetLength(PRUint32 *aLength)
+{
+    *aLength = mLength;
+    return NS_OK;
+}
+
+/* unsigned long alignedSizeInBytes (); */
+NS_IMETHODIMP WebGLFloatArray::AlignedSizeInBytes(PRUint32 *retval)
+{
+    *retval = mBuffer->capacity;
+    return NS_OK;
+}
+
+/* nsICanvasArray slice (in unsigned long offset, in unsigned long length); */
+NS_IMETHODIMP WebGLFloatArray::Slice(PRUint32 offset, PRUint32 length, nsICanvasArray **retval)
+{
+    if (length == 0) 
+        return NS_ERROR_FAILURE;
+
+    if (offset + length > mBuffer->capacity)
+        return NS_ERROR_FAILURE;
+
+    nsICanvasArray *wga = new WebGLFloatArray(mBuffer, offset, length);
+    NS_ADDREF(*retval = wga);
+    return NS_OK;
+}
+
+/* [IndexGetter] float get (in unsigned long index); */
+NS_IMETHODIMP WebGLFloatArray::Get(PRUint32 index, float *retval)
+{
+    if (index >= mLength)
+        return NS_ERROR_FAILURE;
+
+    float *values = static_cast<float*>(mBuffer->data);
+    *retval = values[index];
+
+    return NS_OK;
+}
+
+void
+WebGLFloatArray::Set(PRUint32 index, float value)
+{
+    if (index >= mLength)
+        return;
+
+    float *values = static_cast<float*>(mBuffer->data);
+    values[index] = value;
+}
+
+/* void set (); */
+NS_IMETHODIMP WebGLFloatArray::Set()
+{
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    if (js.argc < 1 || js.argc > 2)
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
+    if (JSVAL_IS_NUMBER(js.argv[0])) {
+        if (js.argc != 2)
+            return NS_ERROR_DOM_SYNTAX_ERR;
+
+        uint32 index;
+        ::JS_ValueToECMAUint32(js.ctx, js.argv[0], &index);
+
+        jsdouble value;
+        ::JS_ValueToNumber(js.ctx, js.argv[1], &value);
+
+        if (index >= mLength)
+            return NS_ERROR_FAILURE;
+
+        Set(index, (float) value);
+    } else {
+        return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP_(PRUint32) WebGLFloatArray::NativeType()
+{
+    return mBuffer->type;
+}
+
+/* [noscript, notxpcom] voidPtr nativePointer (); */
+NS_IMETHODIMP_(void *) WebGLFloatArray::NativePointer()
+{
+    return mBuffer->data;
+}
+
+/* [noscript, notxpcom] unsigned long nativeSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLFloatArray::NativeSize()
+{
+    return mBuffer->capacity;
+}
+
+/* [noscript, notxpcom] unsigned long nativeElementSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLFloatArray::NativeElementSize()
+{
+    return mBuffer->ElementSize();
+}
+
+/* [noscript, notxpcom] unsigned long nativeCount (); */
+NS_IMETHODIMP_(PRUint32) WebGLFloatArray::NativeCount()
+{
+    return mBuffer->length;
+}
+
+/*
+ * CanvasByteArray
+ */
+
+nsresult
+NS_NewCanvasByteArray(nsISupports **aResult)
+{
+    nsICanvasByteArray *wgba = new WebGLByteArray();
+    if (!wgba)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_ADDREF(*aResult = wgba);
+    return NS_OK;
+}
+
+WebGLByteArray::WebGLByteArray(PRUint32 length)
+    : mOffset(0), mLength(length)
+{
+    mBuffer = new WebGLArrayBuffer(length);
+}
+
+WebGLByteArray::WebGLByteArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length)
+    : mBuffer(buffer), mOffset(offset), mLength(length)
+{
+}
+
+WebGLByteArray::WebGLByteArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
+    : mOffset(0), mLength(arrayLen)
+{
+    mBuffer = new WebGLArrayBuffer();
+    mBuffer->InitFromJSArray(LOCAL_GL_UNSIGNED_BYTE, 1, cx, arrayObj, arrayLen);
+}
+
+NS_IMETHODIMP
+WebGLByteArray::Initialize(nsISupports *owner,
+                           JSContext *cx,
+                           JSObject *obj,
+                           PRUint32 argc,
+                           jsval *argv)
+{
+    if (JSVAL_IS_NUMBER(argv[0])) {
+        uint32 length;
+        ::JS_ValueToECMAUint32(cx, argv[0], &length);
+        mBuffer = new WebGLArrayBuffer();
+        mBuffer->Prepare(LOCAL_GL_BYTE, 1, length);
+        mBuffer->Zero();
+        mLength = length;
+    } else {
+        JSObject *arrayObj;
+        jsuint arrayLen;
+        jsuint byteOffset = 0;
+        jsuint length = 0;
+
+        if (!::JS_ConvertArguments(cx, argc, argv, "o/uu", &arrayObj, &byteOffset, &length) ||
+            arrayObj == NULL)
+        {
+            return NS_ERROR_DOM_SYNTAX_ERR;
+        }
+
+        if (::JS_IsArrayObject(cx, arrayObj) &&
+            ::JS_GetArrayLength(cx, arrayObj, &arrayLen))
+        {
+            mBuffer = new WebGLArrayBuffer();
+            mBuffer->InitFromJSArray(LOCAL_GL_UNSIGNED_BYTE, 1, cx, arrayObj, arrayLen);
+            mLength = arrayLen;
+        } else {
+            nsCOMPtr<nsICanvasArrayBuffer> canvasObj;
+            nsresult rv;
+            rv = nsContentUtils::XPConnect()->WrapJS(cx, arrayObj, NS_GET_IID(nsICanvasArrayBuffer), getter_AddRefs(canvasObj));
+            if (NS_FAILED(rv) || !canvasObj) {
+                return NS_ERROR_DOM_SYNTAX_ERR;
+            }
+
+            mBuffer = canvasObj->GetNativeArrayBuffer();
+
+            if ((byteOffset + length) > mBuffer->capacity)
+                return NS_ERROR_FAILURE;
+
+            if (length > 0)
+                mLength = length;
+            else
+                mLength = (mBuffer->capacity - byteOffset);
+        }
+    }
+
+    return NS_OK;
+}
+
+/* readonly attribute nsICanvasArrayBuffer buffer; */
+NS_IMETHODIMP WebGLByteArray::GetBuffer(nsICanvasArrayBuffer **aBuffer)
+{
+    NS_ADDREF(*aBuffer = mBuffer);
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteOffset; */
+NS_IMETHODIMP WebGLByteArray::GetByteOffset(PRUint32 *aByteOffset)
+{
+    *aByteOffset = mOffset;
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteLength; */
+NS_IMETHODIMP WebGLByteArray::GetByteLength(PRUint32 *aByteLength)
+{
+    *aByteLength = mLength;
+    return NS_OK;
+}
+
+/* attribute unsigned long length; */
+NS_IMETHODIMP WebGLByteArray::GetLength(PRUint32 *aLength)
+{
+    *aLength = mLength;
+    return NS_OK;
+}
+
+/* unsigned long alignedSizeInBytes (); */
+NS_IMETHODIMP WebGLByteArray::AlignedSizeInBytes(PRUint32 *retval)
+{
+    *retval = mBuffer->capacity;
+    return NS_OK;
+}
+
+/* nsICanvasArray slice (in unsigned long offset, in unsigned long length); */
+NS_IMETHODIMP WebGLByteArray::Slice(PRUint32 offset, PRUint32 length, nsICanvasArray **retval)
+{
+    if (length == 0) 
+        return NS_ERROR_FAILURE;
+
+    if (offset + length > mBuffer->capacity)
+        return NS_ERROR_FAILURE;
+
+    nsICanvasArray *wga = new WebGLByteArray(mBuffer, offset, length);
+    NS_ADDREF(*retval = wga);
+    return NS_OK;
+}
+
+/* [IndexGetter] long get (in unsigned long index); */
+NS_IMETHODIMP WebGLByteArray::Get(PRUint32 index, PRInt32 *retval)
+{
+    if (index >= mLength)
+        return NS_ERROR_FAILURE;
+
+    char *values = static_cast<char*>(mBuffer->data);
+    *retval = values[index];
+
+    return NS_OK;
+}
+
+void
+WebGLByteArray::Set(PRUint32 index, char value)
+{
+    if (index >= mLength)
+        return;
+
+    char *values = static_cast<char*>(mBuffer->data);
+    values[index] = value;
+}
+
+/* void set (); */
+NS_IMETHODIMP WebGLByteArray::Set()
+{
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    if (js.argc < 1 || js.argc > 2)
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
+    if (JSVAL_IS_NUMBER(js.argv[0])) {
+        if (js.argc != 2)
+            return NS_ERROR_DOM_SYNTAX_ERR;
+
+        uint32 index;
+        ::JS_ValueToECMAUint32(js.ctx, js.argv[0], &index);
+
+        int32 value;
+        ::JS_ValueToECMAInt32(js.ctx, js.argv[1], &value);
+
+        if (index >= mLength)
+            return NS_ERROR_FAILURE;
+
+        Set(index, (char) value);
+    } else {
+        return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP_(PRUint32) WebGLByteArray::NativeType()
+{
+    return mBuffer->type;
+}
+
+/* [noscript, notxpcom] voidPtr nativePointer (); */
+NS_IMETHODIMP_(void *) WebGLByteArray::NativePointer()
+{
+    return mBuffer->data;
+}
+
+/* [noscript, notxpcom] unsigned long nativeSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLByteArray::NativeSize()
+{
+    return mBuffer->capacity;
+}
+
+/* [noscript, notxpcom] unsigned long nativeElementSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLByteArray::NativeElementSize()
+{
+    return mBuffer->ElementSize();
+}
+
+/* [noscript, notxpcom] unsigned long nativeCount (); */
+NS_IMETHODIMP_(PRUint32) WebGLByteArray::NativeCount()
+{
+    return mBuffer->length;
+}
+
+
+/*
+ * CanvasUnsignedByteArray
+ */
+
+nsresult
+NS_NewCanvasUnsignedByteArray(nsISupports **aResult)
+{
+    nsICanvasUnsignedByteArray *wguba = new WebGLUnsignedByteArray();
+    if (!wguba)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_ADDREF(*aResult = wguba);
+    return NS_OK;
+}
+
+WebGLUnsignedByteArray::WebGLUnsignedByteArray(PRUint32 length)
+    : mOffset(0), mLength(length)
+{
+    mBuffer = new WebGLArrayBuffer(length);
+}
+
+WebGLUnsignedByteArray::WebGLUnsignedByteArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length)
+    : mBuffer(buffer), mOffset(offset), mLength(length)
+{
+}
+
+WebGLUnsignedByteArray::WebGLUnsignedByteArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
+    : mOffset(0), mLength(arrayLen)
+{
+    mBuffer = new WebGLArrayBuffer();
+    mBuffer->InitFromJSArray(LOCAL_GL_UNSIGNED_BYTE, 1, cx, arrayObj, arrayLen);
+}
+
+NS_IMETHODIMP
+WebGLUnsignedByteArray::Initialize(nsISupports *owner,
+                                   JSContext *cx,
+                                   JSObject *obj,
+                                   PRUint32 argc,
+                                   jsval *argv)
+{
+    if (JSVAL_IS_NUMBER(argv[0])) {
+        uint32 length;
+        ::JS_ValueToECMAUint32(cx, argv[0], &length);
+        mBuffer = new WebGLArrayBuffer();
+        mBuffer->Prepare(LOCAL_GL_UNSIGNED_BYTE, 1, length);
+        mBuffer->Zero();
+        mLength = length;
+    } else {
+        JSObject *arrayObj;
+        jsuint arrayLen;
+        jsuint byteOffset = 0;
+        jsuint length = 0;
+
+        if (!::JS_ConvertArguments(cx, argc, argv, "o/uu", &arrayObj, &byteOffset, &length) ||
+            arrayObj == NULL)
+        {
+            return NS_ERROR_DOM_SYNTAX_ERR;
+        }
+
+        if (::JS_IsArrayObject(cx, arrayObj) &&
+            ::JS_GetArrayLength(cx, arrayObj, &arrayLen))
+        {
+            mBuffer = new WebGLArrayBuffer();
+            mBuffer->InitFromJSArray(LOCAL_GL_UNSIGNED_BYTE, 1, cx, arrayObj, arrayLen);
+            mLength = arrayLen;
+        } else {
+            nsCOMPtr<nsICanvasArrayBuffer> canvasObj;
+            nsresult rv;
+            rv = nsContentUtils::XPConnect()->WrapJS(cx, arrayObj, NS_GET_IID(nsICanvasArrayBuffer), getter_AddRefs(canvasObj));
+            if (NS_FAILED(rv) || !canvasObj) {
+                return NS_ERROR_DOM_SYNTAX_ERR;
+            }
+
+            mBuffer = canvasObj->GetNativeArrayBuffer();
+
+            if ((byteOffset + length) > mBuffer->capacity)
+                return NS_ERROR_FAILURE;
+
+            if (length > 0)
+                mLength = length;
+            else
+                mLength = (mBuffer->capacity - byteOffset);
+        }
+    }
+
+    return NS_OK;
+}
+
+/* readonly attribute nsICanvasArrayBuffer buffer; */
+NS_IMETHODIMP WebGLUnsignedByteArray::GetBuffer(nsICanvasArrayBuffer **aBuffer)
+{
+    NS_ADDREF(*aBuffer = mBuffer);
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteOffset; */
+NS_IMETHODIMP WebGLUnsignedByteArray::GetByteOffset(PRUint32 *aByteOffset)
+{
+    *aByteOffset = mOffset;
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteLength; */
+NS_IMETHODIMP WebGLUnsignedByteArray::GetByteLength(PRUint32 *aByteLength)
+{
+    *aByteLength = mLength;
+    return NS_OK;
+}
+
+/* attribute unsigned long length; */
+NS_IMETHODIMP WebGLUnsignedByteArray::GetLength(PRUint32 *aLength)
+{
+    *aLength = mLength;
+    return NS_OK;
+}
+
+/* unsigned long alignedSizeInBytes (); */
+NS_IMETHODIMP WebGLUnsignedByteArray::AlignedSizeInBytes(PRUint32 *retval)
+{
+    *retval = mBuffer->capacity;
+    return NS_OK;
+}
+
+/* nsICanvasArray slice (in unsigned long offset, in unsigned long length); */
+NS_IMETHODIMP WebGLUnsignedByteArray::Slice(PRUint32 offset, PRUint32 length, nsICanvasArray **retval)
+{
+    if (length == 0) 
+        return NS_ERROR_FAILURE;
+
+    if (offset + length > mBuffer->capacity)
+        return NS_ERROR_FAILURE;
+
+    nsICanvasArray *wga = new WebGLUnsignedByteArray(mBuffer, offset, length);
+    NS_ADDREF(*retval = wga);
+    return NS_OK;
+}
+
+/* [IndexGetter] unsigned long get (in unsigned long index); */
+NS_IMETHODIMP WebGLUnsignedByteArray::Get(PRUint32 index, PRUint32 *retval)
+{
+    if (index >= mLength)
+        return NS_ERROR_FAILURE;
+
+    unsigned char *values = static_cast<unsigned char*>(mBuffer->data);
+    *retval = values[index];
+
+    return NS_OK;
+}
+
+void
+WebGLUnsignedByteArray::Set(PRUint32 index, unsigned char value)
+{
+    if (index >= mLength)
+        return;
+
+    unsigned char *values = static_cast<unsigned char*>(mBuffer->data);
+    values[index] = value;
+}
+
+/* void set (); */
+NS_IMETHODIMP WebGLUnsignedByteArray::Set()
+{
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    if (js.argc < 1 || js.argc > 2)
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
+    if (JSVAL_IS_NUMBER(js.argv[0])) {
+        if (js.argc != 2)
+            return NS_ERROR_DOM_SYNTAX_ERR;
+
+        uint32 index;
+        ::JS_ValueToECMAUint32(js.ctx, js.argv[0], &index);
+
+        uint32 value;
+        ::JS_ValueToECMAUint32(js.ctx, js.argv[1], &value);
+
+        if (index >= mLength)
+            return NS_ERROR_FAILURE;
+
+        Set(index, (unsigned char) value);
+    } else {
+        return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedByteArray::NativeType()
+{
+    return mBuffer->type;
+}
+
+/* [noscript, notxpcom] voidPtr nativePointer (); */
+NS_IMETHODIMP_(void *) WebGLUnsignedByteArray::NativePointer()
+{
+    return mBuffer->data;
+}
+
+/* [noscript, notxpcom] unsigned long nativeSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedByteArray::NativeSize()
+{
+    return mBuffer->capacity;
+}
+
+/* [noscript, notxpcom] unsigned long nativeElementSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedByteArray::NativeElementSize()
+{
+    return mBuffer->ElementSize();
+}
+
+/* [noscript, notxpcom] unsigned long nativeCount (); */
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedByteArray::NativeCount()
+{
+    return mBuffer->length;
+}
+
+/*
+ * CanvasShortArray
+ */
+
+nsresult
+NS_NewCanvasShortArray(nsISupports **aResult)
+{
+    nsICanvasShortArray *wgsa = new WebGLShortArray();
+    if (!wgsa)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_ADDREF(*aResult = wgsa);
+    return NS_OK;
+}
+
+WebGLShortArray::WebGLShortArray(PRUint32 length)
+    : mOffset(0), mLength(length)
+{
+    mBuffer = new WebGLArrayBuffer(length * sizeof(short));
+}
+
+WebGLShortArray::WebGLShortArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length)
+    : mBuffer(buffer), mOffset(offset), mLength(length)
+{
+}
+
+WebGLShortArray::WebGLShortArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
+    : mOffset(0), mLength(arrayLen)
+{
+    mBuffer = new WebGLArrayBuffer();
+    mBuffer->InitFromJSArray(LOCAL_GL_SHORT, 1, cx, arrayObj, arrayLen);
+}
+
+NS_IMETHODIMP
+WebGLShortArray::Initialize(nsISupports *owner,
+                            JSContext *cx,
+                            JSObject *obj,
+                            PRUint32 argc,
+                            jsval *argv)
+{
+    if (JSVAL_IS_NUMBER(argv[0])) {
+        uint32 length;
+        ::JS_ValueToECMAUint32(cx, argv[0], &length);
+        mBuffer = new WebGLArrayBuffer();
+        mBuffer->Prepare(LOCAL_GL_SHORT, 1, length);
+        mBuffer->Zero();
+        mLength = length;
+    } else {
+        JSObject *arrayObj;
+        jsuint arrayLen;
+        jsuint byteOffset = 0;
+        jsuint length = 0;
+
+        if (!::JS_ConvertArguments(cx, argc, argv, "o/uu", &arrayObj, &byteOffset, &length) ||
+            arrayObj == NULL)
+        {
+            return NS_ERROR_DOM_SYNTAX_ERR;
+        }
+
+        if (::JS_IsArrayObject(cx, arrayObj) &&
+            ::JS_GetArrayLength(cx, arrayObj, &arrayLen))
+        {
+            mBuffer = new WebGLArrayBuffer();
+            mBuffer->InitFromJSArray(LOCAL_GL_SHORT, 1, cx, arrayObj, arrayLen);
+            mLength = arrayLen;
+        } else {
+            nsCOMPtr<nsICanvasArrayBuffer> canvasObj;
+            nsresult rv;
+            rv = nsContentUtils::XPConnect()->WrapJS(cx, arrayObj, NS_GET_IID(nsICanvasArrayBuffer), getter_AddRefs(canvasObj));
+            if (NS_FAILED(rv) || !canvasObj) {
+                return NS_ERROR_DOM_SYNTAX_ERR;
+            }
+
+            mBuffer = canvasObj->GetNativeArrayBuffer();
+
+            if (byteOffset % sizeof(short))
+                return NS_ERROR_FAILURE;
+
+            if ((byteOffset + (length * sizeof(short))) > mBuffer->capacity)
+                return NS_ERROR_FAILURE;
+
+            if (length > 0) {
+                mLength = length;
+            } else {
+                if ((mBuffer->capacity - byteOffset) % sizeof(short))
+                    return NS_ERROR_FAILURE;
+
+                mLength = (mBuffer->capacity - byteOffset) / sizeof(short);
+            }
+        }
+    }
+
+    return NS_OK;
+}
+
+/* readonly attribute nsICanvasArrayBuffer buffer; */
+NS_IMETHODIMP WebGLShortArray::GetBuffer(nsICanvasArrayBuffer * *aBuffer)
+{
+    NS_ADDREF(*aBuffer = mBuffer);
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteOffset; */
+NS_IMETHODIMP WebGLShortArray::GetByteOffset(PRUint32 *aByteOffset)
+{
+    *aByteOffset = mOffset;
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteLength; */
+NS_IMETHODIMP WebGLShortArray::GetByteLength(PRUint32 *aByteLength)
+{
+    *aByteLength = mLength * sizeof(short);
+    return NS_OK;
+}
+
+/* attribute unsigned long length; */
+NS_IMETHODIMP WebGLShortArray::GetLength(PRUint32 *aLength)
+{
+    *aLength = mLength;
+    return NS_OK;
+}
+
+/* unsigned long alignedSizeInBytes (); */
+NS_IMETHODIMP WebGLShortArray::AlignedSizeInBytes(PRUint32 *retval)
+{
+    *retval = mBuffer->capacity;
+    return NS_OK;
+}
+
+/* nsICanvasArray slice (in unsigned long offset, in unsigned long length); */
+NS_IMETHODIMP WebGLShortArray::Slice(PRUint32 offset, PRUint32 length, nsICanvasArray **retval)
+{
+    if (length == 0) 
+        return NS_ERROR_FAILURE;
+
+    if (offset + length > mBuffer->capacity)
+        return NS_ERROR_FAILURE;
+
+    nsICanvasArray *wga = new WebGLShortArray(mBuffer, offset, length);
+    NS_ADDREF(*retval = wga);
+    return NS_OK;
+}
+
+/* [IndexGetter] long get (in unsigned long index); */
+NS_IMETHODIMP WebGLShortArray::Get(PRUint32 index, PRInt32 *retval)
+{
+    if (index >= mLength)
+        return NS_ERROR_FAILURE;
+
+    short *values = static_cast<short*>(mBuffer->data);
+    *retval = values[index];
+
+    return NS_OK;
+}
+
+void
+WebGLShortArray::Set(PRUint32 index, short value)
+{
+    if (index >= mLength)
+        return;
+
+    short *values = static_cast<short*>(mBuffer->data);
+    values[index] = value;
+}
+
+/* void set (); */
+NS_IMETHODIMP WebGLShortArray::Set()
+{
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    if (js.argc < 1 || js.argc > 2)
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
+    if (JSVAL_IS_NUMBER(js.argv[0])) {
+        if (js.argc != 2)
+            return NS_ERROR_DOM_SYNTAX_ERR;
+
+        uint32 index;
+        ::JS_ValueToECMAUint32(js.ctx, js.argv[0], &index);
+
+        int32 value;
+        ::JS_ValueToECMAInt32(js.ctx, js.argv[1], &value);
+
+        if (index >= mLength)
+            return NS_ERROR_FAILURE;
+
+        Set(index, (short) value);
+    } else {
+        return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP_(PRUint32) WebGLShortArray::NativeType()
+{
+    return mBuffer->type;
+}
+
+/* [noscript, notxpcom] voidPtr nativePointer (); */
+NS_IMETHODIMP_(void *) WebGLShortArray::NativePointer()
+{
+    return mBuffer->data;
+}
+
+/* [noscript, notxpcom] unsigned long nativeSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLShortArray::NativeSize()
+{
+    return mBuffer->capacity;
+}
+
+/* [noscript, notxpcom] unsigned long nativeElementSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLShortArray::NativeElementSize()
+{
+    return mBuffer->ElementSize();
+}
+
+/* [noscript, notxpcom] unsigned long nativeCount (); */
+NS_IMETHODIMP_(PRUint32) WebGLShortArray::NativeCount()
+{
+    return mBuffer->length;
+}
+
+/*
+ * CanvasUnsignedShortArray
+ */
+
+nsresult
+NS_NewCanvasUnsignedShortArray(nsISupports **aResult)
+{
+    nsICanvasUnsignedShortArray *wgusa = new WebGLUnsignedShortArray();
+    if (!wgusa)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_ADDREF(*aResult = wgusa);
+    return NS_OK;
+}
+
+WebGLUnsignedShortArray::WebGLUnsignedShortArray(PRUint32 length)
+    : mOffset(0), mLength(length)
+{
+    mBuffer = new WebGLArrayBuffer(length * sizeof(short));
+}
+
+WebGLUnsignedShortArray::WebGLUnsignedShortArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length)
+    : mBuffer(buffer), mOffset(offset), mLength(length)
+{
+}
+
+WebGLUnsignedShortArray::WebGLUnsignedShortArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
+    : mOffset(0), mLength(arrayLen)
+{
+    mBuffer = new WebGLArrayBuffer();
+    mBuffer->InitFromJSArray(LOCAL_GL_UNSIGNED_SHORT, 1, cx, arrayObj, arrayLen);
+}
+
+NS_IMETHODIMP
+WebGLUnsignedShortArray::Initialize(nsISupports *owner,
+                                   JSContext *cx,
+                                   JSObject *obj,
+                                   PRUint32 argc,
+                                   jsval *argv)
+{
+    if (JSVAL_IS_NUMBER(argv[0])) {
+        uint32 length;
+        ::JS_ValueToECMAUint32(cx, argv[0], &length);
+        mBuffer = new WebGLArrayBuffer();
+        mBuffer->Prepare(LOCAL_GL_UNSIGNED_SHORT, 1, length);
+        mBuffer->Zero();
+        mLength = length;
+    } else {
+        JSObject *arrayObj;
+        jsuint arrayLen;
+        jsuint byteOffset = 0;
+        jsuint length = 0;
+
+        if (!::JS_ConvertArguments(cx, argc, argv, "o/uu", &arrayObj, &byteOffset, &length) ||
+            arrayObj == NULL)
+        {
+            return NS_ERROR_DOM_SYNTAX_ERR;
+        }
+
+        if (::JS_IsArrayObject(cx, arrayObj) &&
+            ::JS_GetArrayLength(cx, arrayObj, &arrayLen))
+        {
+            mBuffer = new WebGLArrayBuffer();
+            mBuffer->InitFromJSArray(LOCAL_GL_UNSIGNED_SHORT, 1, cx, arrayObj, arrayLen);
+            mLength = arrayLen;
+        } else {
+            nsCOMPtr<nsICanvasArrayBuffer> canvasObj;
+            nsresult rv;
+            rv = nsContentUtils::XPConnect()->WrapJS(cx, arrayObj, NS_GET_IID(nsICanvasArrayBuffer), getter_AddRefs(canvasObj));
+            if (NS_FAILED(rv) || !canvasObj) {
+                return NS_ERROR_DOM_SYNTAX_ERR;
+            }
+
+            mBuffer = canvasObj->GetNativeArrayBuffer();
+
+            if (byteOffset % sizeof(short))
+                return NS_ERROR_FAILURE;
+
+            if ((byteOffset + (length * sizeof(short))) > mBuffer->capacity)
+                return NS_ERROR_FAILURE;
+
+            if (length > 0) {
+                mLength = length;
+            } else {
+                if ((mBuffer->capacity - byteOffset) % sizeof(short)) 
+                    return NS_ERROR_FAILURE;
+
+                mLength = (mBuffer->capacity - byteOffset) / sizeof(short);
+            }
+        }
+    }
+
+    return NS_OK;
+}
+
+/* readonly attribute nsICanvasArrayBuffer buffer; */
+NS_IMETHODIMP WebGLUnsignedShortArray::GetBuffer(nsICanvasArrayBuffer * *aBuffer)
+{
+    NS_ADDREF(*aBuffer = mBuffer);
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteOffset; */
+NS_IMETHODIMP WebGLUnsignedShortArray::GetByteOffset(PRUint32 *aByteOffset)
+{
+    *aByteOffset = mOffset;
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteLength; */
+NS_IMETHODIMP WebGLUnsignedShortArray::GetByteLength(PRUint32 *aByteLength)
+{
+    *aByteLength = mLength * sizeof(short);
+    return NS_OK;
+}
+
+/* attribute unsigned long length; */
+NS_IMETHODIMP WebGLUnsignedShortArray::GetLength(PRUint32 *aLength)
+{
+    *aLength = mLength;
+    return NS_OK;
+}
+
+/* unsigned long alignedSizeInBytes (); */
+NS_IMETHODIMP WebGLUnsignedShortArray::AlignedSizeInBytes(PRUint32 *retval)
+{
+    *retval = mBuffer->capacity;
+    return NS_OK;
+}
+
+/* nsICanvasArray slice (in unsigned long offset, in unsigned long length); */
+NS_IMETHODIMP WebGLUnsignedShortArray::Slice(PRUint32 offset, PRUint32 length, nsICanvasArray **retval)
+{
+    if (length == 0) 
+        return NS_ERROR_FAILURE;
+
+    if (offset + length > mBuffer->capacity)
+        return NS_ERROR_FAILURE;
+
+    nsICanvasArray *wga = new WebGLUnsignedShortArray(mBuffer, offset, length);
+    NS_ADDREF(*retval = wga);
+    return NS_OK;
+}
+
+/* [IndexGetter] unsigned long get (in unsigned long index); */
+NS_IMETHODIMP WebGLUnsignedShortArray::Get(PRUint32 index, PRUint32 *retval)
+{
+    if (index >= mLength)
+        return NS_ERROR_FAILURE;
+
+    unsigned short *values = static_cast<unsigned short*>(mBuffer->data);
+    *retval = values[index];
+
+    return NS_OK;
+}
+
+void
+WebGLUnsignedShortArray::Set(PRUint32 index, unsigned short value)
+{
+    if (index >= mLength)
+        return;
+
+    unsigned short *values = static_cast<unsigned short*>(mBuffer->data);
+    values[index] = value;
+}
+
+/* void set (); */
+NS_IMETHODIMP WebGLUnsignedShortArray::Set()
+{
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    if (js.argc < 1 || js.argc > 2)
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
+    if (JSVAL_IS_NUMBER(js.argv[0])) {
+        if (js.argc != 2)
+            return NS_ERROR_DOM_SYNTAX_ERR;
+
+        uint32 index;
+        ::JS_ValueToECMAUint32(js.ctx, js.argv[0], &index);
+
+        uint32 value;
+        ::JS_ValueToECMAUint32(js.ctx, js.argv[1], &value);
+
+        if (index >= mLength)
+            return NS_ERROR_FAILURE;
+
+        Set(index, (unsigned short) value);
+    } else {
+        return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedShortArray::NativeType()
+{
+    return mBuffer->type;
+}
+
+/* [noscript, notxpcom] voidPtr nativePointer (); */
+NS_IMETHODIMP_(void *) WebGLUnsignedShortArray::NativePointer()
+{
+    return mBuffer->data;
+}
+
+/* [noscript, notxpcom] unsigned long nativeSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedShortArray::NativeSize()
+{
+    return mBuffer->capacity;
+}
+
+/* [noscript, notxpcom] unsigned long nativeElementSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedShortArray::NativeElementSize()
+{
+    return mBuffer->ElementSize();
+}
+
+/* [noscript, notxpcom] unsigned long nativeCount (); */
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedShortArray::NativeCount()
+{
+    return mBuffer->length;
+}
+
+/*
+ * CanvasIntArray
+ */
+
+nsresult
+NS_NewCanvasIntArray(nsISupports **aResult)
+{
+    nsICanvasIntArray *wgia = new WebGLIntArray();
+    if (!wgia)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_ADDREF(*aResult = wgia);
+    return NS_OK;
+}
+
+WebGLIntArray::WebGLIntArray(PRUint32 length)
+    : mOffset(0), mLength(length)
+{
+    mBuffer = new WebGLArrayBuffer(length * sizeof(int));
+}
+
+WebGLIntArray::WebGLIntArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length)
+    : mBuffer(buffer), mOffset(offset), mLength(length)
+{
+}
+
+WebGLIntArray::WebGLIntArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
+    : mOffset(0), mLength(arrayLen)
+{
+    mBuffer = new WebGLArrayBuffer();
+    mBuffer->InitFromJSArray(LOCAL_GL_INT, 1, cx, arrayObj, arrayLen);
+}
+
+NS_IMETHODIMP
+WebGLIntArray::Initialize(nsISupports *owner,
+                          JSContext *cx,
+                          JSObject *obj,
+                          PRUint32 argc,
+                          jsval *argv)
+{
+    if (JSVAL_IS_NUMBER(argv[0])) {
+        uint32 length;
+        ::JS_ValueToECMAUint32(cx, argv[0], &length);
+        mBuffer = new WebGLArrayBuffer();
+        mBuffer->Prepare(LOCAL_GL_INT, 1, length);
+        mBuffer->Zero();
+        mLength = length;
+    } else {
+        JSObject *arrayObj;
+        jsuint arrayLen;
+        jsuint byteOffset = 0;
+        jsuint length = 0;
+
+        if (!::JS_ConvertArguments(cx, argc, argv, "o/uu", &arrayObj, &byteOffset, &length) ||
+            arrayObj == NULL)
+        {
+            return NS_ERROR_DOM_SYNTAX_ERR;
+        }
+
+        if (::JS_IsArrayObject(cx, arrayObj) &&
+            ::JS_GetArrayLength(cx, arrayObj, &arrayLen))
+        {
+            mBuffer = new WebGLArrayBuffer();
+            mBuffer->InitFromJSArray(LOCAL_GL_INT, 1, cx, arrayObj, arrayLen);
+            mLength = arrayLen;
+        } else {
+            nsCOMPtr<nsICanvasArrayBuffer> canvasObj;
+            nsresult rv;
+            rv = nsContentUtils::XPConnect()->WrapJS(cx, arrayObj, NS_GET_IID(nsICanvasArrayBuffer), getter_AddRefs(canvasObj));
+            if (NS_FAILED(rv) || !canvasObj) {
+                return NS_ERROR_DOM_SYNTAX_ERR;
+            }
+
+            mBuffer = canvasObj->GetNativeArrayBuffer();
+
+            if (byteOffset % sizeof(int))
+                return NS_ERROR_FAILURE;
+
+            if ((byteOffset + (length * sizeof(int))) > mBuffer->capacity)
+                return NS_ERROR_FAILURE;
+
+            if (length > 0) {
+                mLength = length;
+            } else {
+                if ((mBuffer->capacity - byteOffset) % sizeof(int))
+                    return NS_ERROR_FAILURE;
+
+                mLength = (mBuffer->capacity - byteOffset) / sizeof(int);
+            }
+        }
+    }
+
+    return NS_OK;
+}
+
+/* readonly attribute nsICanvasArrayBuffer buffer; */
+NS_IMETHODIMP WebGLIntArray::GetBuffer(nsICanvasArrayBuffer * *aBuffer)
+{
+    NS_ADDREF(*aBuffer = mBuffer);
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteOffset; */
+NS_IMETHODIMP WebGLIntArray::GetByteOffset(PRUint32 *aByteOffset)
+{
+    *aByteOffset = mOffset;
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteLength; */
+NS_IMETHODIMP WebGLIntArray::GetByteLength(PRUint32 *aByteLength)
+{
+    *aByteLength = mLength * sizeof(int);
+    return NS_OK;
+}
+
+/* attribute unsigned long length; */
+NS_IMETHODIMP WebGLIntArray::GetLength(PRUint32 *aLength)
+{
+    *aLength = mLength;
+    return NS_OK;
+}
+
+/* unsigned long alignedSizeInBytes (); */
+NS_IMETHODIMP WebGLIntArray::AlignedSizeInBytes(PRUint32 *retval)
+{
+    *retval = mBuffer->capacity;
+    return NS_OK;
+}
+
+/* nsICanvasArray slice (in unsigned long offset, in unsigned long length); */
+NS_IMETHODIMP WebGLIntArray::Slice(PRUint32 offset, PRUint32 length, nsICanvasArray **retval)
+{
+    if (length == 0) 
+        return NS_ERROR_FAILURE;
+
+    if (offset + length > mBuffer->capacity)
+        return NS_ERROR_FAILURE;
+
+    nsICanvasArray *wga = new WebGLIntArray(mBuffer, offset, length);
+    NS_ADDREF(*retval = wga);
+    return NS_OK;
+}
+
+/* [IndexGetter] long get (in unsigned long index); */
+NS_IMETHODIMP WebGLIntArray::Get(PRUint32 index, PRInt32 *retval)
+{
+    if (index >= mLength)
+        return NS_ERROR_FAILURE;
+
+    int *values = static_cast<int*>(mBuffer->data);
+    *retval = values[index];
+
+    return NS_OK;
+}
+
+void
+WebGLIntArray::Set(PRUint32 index, int value)
+{
+    if (index >= mLength)
+        return;
+
+    int *values = static_cast<int*>(mBuffer->data);
+    values[index] = value;
+}
+
+/* void set (); */
+NS_IMETHODIMP WebGLIntArray::Set()
+{
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    if (js.argc < 1 || js.argc > 2)
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
+    if (JSVAL_IS_NUMBER(js.argv[0])) {
+        if (js.argc != 2)
+            return NS_ERROR_DOM_SYNTAX_ERR;
+
+        uint32 index;
+        ::JS_ValueToECMAUint32(js.ctx, js.argv[0], &index);
+
+        int32 value;
+        ::JS_ValueToECMAInt32(js.ctx, js.argv[1], &value);
+
+        if (index >= mLength)
+            return NS_ERROR_FAILURE;
+
+        Set(index, value);
+    } else {
+        return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP_(PRUint32) WebGLIntArray::NativeType()
+{
+    return mBuffer->type;
+}
+
+/* [noscript, notxpcom] voidPtr nativePointer (); */
+NS_IMETHODIMP_(void *) WebGLIntArray::NativePointer()
+{
+    return mBuffer->data;
+}
+
+/* [noscript, notxpcom] unsigned long nativeSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLIntArray::NativeSize()
+{
+    return mBuffer->capacity;
+}
+
+/* [noscript, notxpcom] unsigned long nativeElementSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLIntArray::NativeElementSize()
+{
+    return mBuffer->ElementSize();
+}
+
+/* [noscript, notxpcom] unsigned long nativeCount (); */
+NS_IMETHODIMP_(PRUint32) WebGLIntArray::NativeCount()
+{
+    return mBuffer->length;
+}
+
+/*
+ * CanvasUnsignedIntArray
+ */
+
+nsresult
+NS_NewCanvasUnsignedIntArray(nsISupports **aResult)
+{
+    nsICanvasUnsignedIntArray *wguia = new WebGLUnsignedIntArray();
+    if (!wguia)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_ADDREF(*aResult = wguia);
+    return NS_OK;
+}
+
+WebGLUnsignedIntArray::WebGLUnsignedIntArray(PRUint32 length)
+    : mOffset(0), mLength(length)
+{
+    mBuffer = new WebGLArrayBuffer(length * sizeof(int));
+}
+
+WebGLUnsignedIntArray::WebGLUnsignedIntArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length)
+    : mBuffer(buffer), mOffset(offset), mLength(length)
+{
+}
+
+WebGLUnsignedIntArray::WebGLUnsignedIntArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
+    : mOffset(0), mLength(arrayLen)
+{
+    mBuffer = new WebGLArrayBuffer();
+    mBuffer->InitFromJSArray(LOCAL_GL_UNSIGNED_INT, 1, cx, arrayObj, arrayLen);
+}
+
+NS_IMETHODIMP
+WebGLUnsignedIntArray::Initialize(nsISupports *owner,
+                                  JSContext *cx,
+                                  JSObject *obj,
+                                  PRUint32 argc,
+                                  jsval *argv)
+{
+    if (JSVAL_IS_NUMBER(argv[0])) {
+        uint32 length;
+        ::JS_ValueToECMAUint32(cx, argv[0], &length);
+        mBuffer = new WebGLArrayBuffer();
+        mBuffer->Prepare(LOCAL_GL_UNSIGNED_INT, 1, length);
+        mBuffer->Zero();
+        mLength = length;
+    } else {
+        JSObject *arrayObj;
+        jsuint arrayLen;
+        jsuint byteOffset = 0;
+        jsuint length = 0;
+
+        if (!::JS_ConvertArguments(cx, argc, argv, "o/uu", &arrayObj, &byteOffset, &length) ||
+            arrayObj == NULL)
+        {
+            return NS_ERROR_DOM_SYNTAX_ERR;
+        }
+
+        if (::JS_IsArrayObject(cx, arrayObj) &&
+            ::JS_GetArrayLength(cx, arrayObj, &arrayLen))
+        {
+            mBuffer = new WebGLArrayBuffer();
+            mBuffer->InitFromJSArray(LOCAL_GL_UNSIGNED_INT, 1, cx, arrayObj, arrayLen);
+            mLength = arrayLen;
+        } else {
+            nsCOMPtr<nsICanvasArrayBuffer> canvasObj;
+            nsresult rv;
+            rv = nsContentUtils::XPConnect()->WrapJS(cx, arrayObj, NS_GET_IID(nsICanvasArrayBuffer), getter_AddRefs(canvasObj));
+            if (NS_FAILED(rv) || !canvasObj) {
+                return NS_ERROR_DOM_SYNTAX_ERR;
+            }
+
+            mBuffer = canvasObj->GetNativeArrayBuffer();
+
+            if (byteOffset % sizeof(int))
+                return NS_ERROR_FAILURE;
+
+            if ((byteOffset + (length * sizeof(int))) > mBuffer->capacity)
+                return NS_ERROR_FAILURE;
+
+            if (length > 0) {
+                mLength = length;
+            } else {
+                if ((mBuffer->capacity - byteOffset) % sizeof(int))
+                    return NS_ERROR_FAILURE;
+
+                mLength = (mBuffer->capacity - byteOffset) / sizeof(int);
+            }
+        }
+    }
+
+    return NS_OK;
+}
+
+/* readonly attribute nsICanvasArrayBuffer buffer; */
+NS_IMETHODIMP WebGLUnsignedIntArray::GetBuffer(nsICanvasArrayBuffer * *aBuffer)
+{
+    NS_ADDREF(*aBuffer = mBuffer);
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteOffset; */
+NS_IMETHODIMP WebGLUnsignedIntArray::GetByteOffset(PRUint32 *aByteOffset)
+{
+    *aByteOffset = mOffset;
+    return NS_OK;
+}
+
+/* readonly attribute unsigned long byteLength; */
+NS_IMETHODIMP WebGLUnsignedIntArray::GetByteLength(PRUint32 *aByteLength)
+{
+    *aByteLength = mLength * sizeof(int);
+    return NS_OK;
+}
+
+/* attribute unsigned long length; */
+NS_IMETHODIMP WebGLUnsignedIntArray::GetLength(PRUint32 *aLength)
+{
+    *aLength = mLength;
+    return NS_OK;
+}
+
+/* unsigned long alignedSizeInBytes (); */
+NS_IMETHODIMP WebGLUnsignedIntArray::AlignedSizeInBytes(PRUint32 *retval)
+{
+    *retval = mBuffer->capacity;
+    return NS_OK;
+}
+
+/* nsICanvasArray slice (in unsigned long offset, in unsigned long length); */
+NS_IMETHODIMP WebGLUnsignedIntArray::Slice(PRUint32 offset, PRUint32 length, nsICanvasArray **retval)
+{
+    if (length == 0) 
+        return NS_ERROR_FAILURE;
+
+    if (offset + length > mBuffer->capacity)
+        return NS_ERROR_FAILURE;
+
+    nsICanvasArray *wga = new WebGLUnsignedIntArray(mBuffer, offset, length);
+    NS_ADDREF(*retval = wga);
+    return NS_OK;
+}
+
+/* [IndexGetter] unsigned long get (in unsigned long index); */
+NS_IMETHODIMP WebGLUnsignedIntArray::Get(PRUint32 index, PRUint32 *retval)
+{
+    if (index >= mLength)
+        return NS_ERROR_FAILURE;
+
+    unsigned int *values = static_cast<unsigned int*>(mBuffer->data);
+    *retval = values[index];
+
+    return NS_OK;
+}
+
+void
+WebGLUnsignedIntArray::Set(PRUint32 index, unsigned int value)
+{
+    if (index >= mLength)
+        return;
+
+    unsigned int *values = static_cast<unsigned int*>(mBuffer->data);
+    values[index] = value;
+}
+
+/* void set (); */
+NS_IMETHODIMP WebGLUnsignedIntArray::Set()
+{
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    if (js.argc < 1 || js.argc > 2)
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
+    if (JSVAL_IS_NUMBER(js.argv[0])) {
+        if (js.argc != 2)
+            return NS_ERROR_DOM_SYNTAX_ERR;
+
+        uint32 index;
+        ::JS_ValueToECMAUint32(js.ctx, js.argv[0], &index);
+
+        uint32 value;
+        ::JS_ValueToECMAUint32(js.ctx, js.argv[1], &value);
+
+        if (index >= mLength)
+            return NS_ERROR_FAILURE;
+
+        Set(index, value);
+    } else {
+        return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedIntArray::NativeType()
+{
+    return mBuffer->type;
+}
+
+/* [noscript, notxpcom] voidPtr nativePointer (); */
+NS_IMETHODIMP_(void *) WebGLUnsignedIntArray::NativePointer()
+{
+    return mBuffer->data;
+}
+
+/* [noscript, notxpcom] unsigned long nativeSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedIntArray::NativeSize()
+{
+    return mBuffer->capacity;
+}
+
+/* [noscript, notxpcom] unsigned long nativeElementSize (); */
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedIntArray::NativeElementSize()
+{
+    return mBuffer->ElementSize();
+}
+
+/* [noscript, notxpcom] unsigned long nativeCount (); */
+NS_IMETHODIMP_(PRUint32) WebGLUnsignedIntArray::NativeCount()
+{
+    return mBuffer->length;
+}
+
+
+
+/*
+ * XPCOM AddRef/Release/QI
+ */
+NS_IMPL_ADDREF(WebGLArrayBuffer)
+NS_IMPL_RELEASE(WebGLArrayBuffer)
+
+NS_INTERFACE_MAP_BEGIN(WebGLArrayBuffer)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasArrayBuffer)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasArrayBuffer)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasArrayBuffer)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(WebGLFloatArray)
+NS_IMPL_RELEASE(WebGLFloatArray)
+
+NS_INTERFACE_MAP_BEGIN(WebGLFloatArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasFloatArray)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasFloatArray)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasFloatArray)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(WebGLByteArray)
+NS_IMPL_RELEASE(WebGLByteArray)
+
+NS_INTERFACE_MAP_BEGIN(WebGLByteArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasByteArray)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasByteArray)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasByteArray)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(WebGLUnsignedByteArray)
+NS_IMPL_RELEASE(WebGLUnsignedByteArray)
+
+NS_INTERFACE_MAP_BEGIN(WebGLUnsignedByteArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasUnsignedByteArray)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasUnsignedByteArray)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasUnsignedByteArray)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(WebGLShortArray)
+NS_IMPL_RELEASE(WebGLShortArray)
+
+NS_INTERFACE_MAP_BEGIN(WebGLShortArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasShortArray)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasShortArray)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasShortArray)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(WebGLUnsignedShortArray)
+NS_IMPL_RELEASE(WebGLUnsignedShortArray)
+
+NS_INTERFACE_MAP_BEGIN(WebGLUnsignedShortArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasUnsignedShortArray)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasUnsignedShortArray)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasUnsignedShortArray)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(WebGLIntArray)
+NS_IMPL_RELEASE(WebGLIntArray)
+
+NS_INTERFACE_MAP_BEGIN(WebGLIntArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasIntArray)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasIntArray)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasIntArray)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(WebGLUnsignedIntArray)
+NS_IMPL_RELEASE(WebGLUnsignedIntArray)
+
+NS_INTERFACE_MAP_BEGIN(WebGLUnsignedIntArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
+  NS_INTERFACE_MAP_ENTRY(nsICanvasUnsignedIntArray)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasUnsignedIntArray)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasUnsignedIntArray)
+NS_INTERFACE_MAP_END
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/WebGLArrays.h
@@ -0,0 +1,317 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mark Steele <mwsteele@gmail.com>
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef WEBGLARRAYS_H_
+#define WEBGLARRAYS_H_
+
+#include <stdarg.h>
+
+#include "nsTArray.h"
+#include "nsDataHashtable.h"
+#include "nsRefPtrHashtable.h"
+#include "nsHashKeys.h"
+
+#include "nsICanvasRenderingContextWebGL.h"
+#include "nsICanvasRenderingContextInternal.h"
+#include "nsIJSNativeInitializer.h"
+
+#include "SimpleBuffer.h"
+
+namespace mozilla {
+
+//
+// array wrapper classes
+//
+
+// XXX refactor buffer stuff
+class WebGLArrayBuffer :
+    public nsICanvasArrayBuffer,
+    public nsIJSNativeInitializer,
+    public SimpleBuffer
+{
+public:
+
+    WebGLArrayBuffer() { }
+    WebGLArrayBuffer(PRUint32 length);
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSICANVASARRAYBUFFER
+
+    NS_IMETHOD Initialize(nsISupports* aOwner,
+                          JSContext* aCx,
+                          JSObject* aObj,
+                          PRUint32 aArgc,
+                          jsval* aArgv);
+};
+
+class WebGLFloatArray :
+    public nsICanvasFloatArray,
+    public nsIJSNativeInitializer
+{
+public:
+    WebGLFloatArray() :
+        mOffset(0), mLength(0) { }
+
+    WebGLFloatArray(PRUint32 length);
+    WebGLFloatArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length);
+    WebGLFloatArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSICANVASARRAY
+    NS_DECL_NSICANVASFLOATARRAY
+
+    NS_IMETHOD Initialize(nsISupports* aOwner,
+                          JSContext* aCx,
+                          JSObject* aObj,
+                          PRUint32 aArgc,
+                          jsval* aArgv);
+
+    void Set(PRUint32 index, float value);
+
+protected:
+    nsRefPtr<WebGLArrayBuffer> mBuffer;
+    PRUint32 mOffset;
+    PRUint32 mLength;
+    PRUint32 mSize;
+    PRUint32 mElementSize;
+    PRUint32 mCount;
+};
+
+class WebGLByteArray :
+    public nsICanvasByteArray,
+    public nsIJSNativeInitializer
+{
+public:
+    WebGLByteArray() :
+        mOffset(0), mLength(0) { }
+
+    WebGLByteArray(PRUint32 length);
+    WebGLByteArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length);
+    WebGLByteArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSICANVASARRAY
+    NS_DECL_NSICANVASBYTEARRAY
+
+    NS_IMETHOD Initialize(nsISupports* aOwner,
+                          JSContext* aCx,
+                          JSObject* aObj,
+                          PRUint32 aArgc,
+                          jsval* aArgv);
+
+    void Set(PRUint32 index, char value);
+
+protected:
+    nsRefPtr<WebGLArrayBuffer> mBuffer;
+    PRUint32 mOffset;
+    PRUint32 mLength;
+    PRUint32 mSize;
+    PRUint32 mElementSize;
+    PRUint32 mCount;
+};
+
+class WebGLUnsignedByteArray :
+    public nsICanvasUnsignedByteArray,
+    public nsIJSNativeInitializer
+{
+public:
+    WebGLUnsignedByteArray() :
+        mOffset(0), mLength(0) { }
+
+    WebGLUnsignedByteArray(PRUint32 length);
+    WebGLUnsignedByteArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length);
+    WebGLUnsignedByteArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSICANVASARRAY
+    NS_DECL_NSICANVASUNSIGNEDBYTEARRAY
+
+    NS_IMETHOD Initialize(nsISupports* aOwner,
+                          JSContext* aCx,
+                          JSObject* aObj,
+                          PRUint32 aArgc,
+                          jsval* aArgv);
+
+    void Set(PRUint32 index, unsigned char value);
+
+protected:
+    nsRefPtr<WebGLArrayBuffer> mBuffer;
+    PRUint32 mOffset;
+    PRUint32 mLength;
+    PRUint32 mSize;
+    PRUint32 mElementSize;
+    PRUint32 mCount;
+};
+
+class WebGLShortArray :
+    public nsICanvasShortArray,
+    public nsIJSNativeInitializer
+{
+public:
+    WebGLShortArray() :
+        mOffset(0), mLength(0) { }
+
+    WebGLShortArray(PRUint32 length);
+    WebGLShortArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length);
+    WebGLShortArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSICANVASARRAY
+    NS_DECL_NSICANVASSHORTARRAY
+
+    NS_IMETHOD Initialize(nsISupports* aOwner,
+                          JSContext* aCx,
+                          JSObject* aObj,
+                          PRUint32 aArgc,
+                          jsval* aArgv);
+
+    void Set(PRUint32 index, short value);
+
+protected:
+    nsRefPtr<WebGLArrayBuffer> mBuffer;
+    PRUint32 mOffset;
+    PRUint32 mLength;
+    PRUint32 mSize;
+    PRUint32 mElementSize;
+    PRUint32 mCount;
+};
+
+class WebGLUnsignedShortArray :
+    public nsICanvasUnsignedShortArray,
+    public nsIJSNativeInitializer
+{
+public:
+    WebGLUnsignedShortArray() :
+        mOffset(0), mLength(0) { }
+
+    WebGLUnsignedShortArray(PRUint32 length);
+    WebGLUnsignedShortArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length);
+    WebGLUnsignedShortArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSICANVASARRAY
+    NS_DECL_NSICANVASUNSIGNEDSHORTARRAY
+
+    NS_IMETHOD Initialize(nsISupports* aOwner,
+                          JSContext* aCx,
+                          JSObject* aObj,
+                          PRUint32 aArgc,
+                          jsval* aArgv);
+
+    void Set(PRUint32 index, unsigned short value);
+
+protected:
+    nsRefPtr<WebGLArrayBuffer> mBuffer;
+    PRUint32 mOffset;
+    PRUint32 mLength;
+    PRUint32 mSize;
+    PRUint32 mElementSize;
+    PRUint32 mCount;
+};
+
+class WebGLIntArray :
+    public nsICanvasIntArray,
+    public nsIJSNativeInitializer
+{
+public:
+    WebGLIntArray() :
+        mOffset(0), mLength(0) { }
+
+    WebGLIntArray(PRUint32 length);
+    WebGLIntArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length);
+    WebGLIntArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSICANVASARRAY
+    NS_DECL_NSICANVASINTARRAY
+
+    NS_IMETHOD Initialize(nsISupports* aOwner,
+                          JSContext* aCx,
+                          JSObject* aObj,
+                          PRUint32 aArgc,
+                          jsval* aArgv);
+
+    void Set(PRUint32 index, int value);
+
+protected:
+    nsRefPtr<WebGLArrayBuffer> mBuffer;
+    PRUint32 mOffset;
+    PRUint32 mLength;
+    PRUint32 mSize;
+    PRUint32 mElementSize;
+    PRUint32 mCount;
+};
+
+class WebGLUnsignedIntArray :
+    public nsICanvasUnsignedIntArray,
+    public nsIJSNativeInitializer
+{
+public:
+    WebGLUnsignedIntArray() :
+        mOffset(0), mLength(0) { }
+
+    WebGLUnsignedIntArray(PRUint32 length);
+    WebGLUnsignedIntArray(WebGLArrayBuffer *buffer, PRUint32 offset, PRUint32 length);
+    WebGLUnsignedIntArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSICANVASARRAY
+    NS_DECL_NSICANVASUNSIGNEDINTARRAY
+
+    NS_IMETHOD Initialize(nsISupports* aOwner,
+                          JSContext* aCx,
+                          JSObject* aObj,
+                          PRUint32 aArgc,
+                          jsval* aArgv);
+
+    void Set(PRUint32 index, unsigned int value);
+
+protected:
+    nsRefPtr<WebGLArrayBuffer> mBuffer;
+    PRUint32 mOffset;
+    PRUint32 mLength;
+    PRUint32 mSize;
+    PRUint32 mElementSize;
+    PRUint32 mCount;
+};
+
+} /* namespace mozilla */
+
+
+#endif /* WEBGLARRAYS_H_ */
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -1,21 +1,27 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 #include "WebGLContext.h"
 
 #include "nsIConsoleService.h"
 #include "nsIPrefService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIClassInfoImpl.h"
 #include "nsContentUtils.h"
+#include "nsIXPConnect.h"
 #include "nsDOMError.h"
 
 #include "gfxContext.h"
 #include "gfxPattern.h"
 
+#include "CanvasUtils.h"
+#include "NativeJSContext.h"
+
+#include "WebGLArray.h"
+
 using namespace mozilla;
 
 nsresult NS_NewCanvasRenderingContextWebGL(nsICanvasRenderingContextWebGL** aResult);
 
 nsresult
 NS_NewCanvasRenderingContextWebGL(nsICanvasRenderingContextWebGL** aResult)
 {
     nsICanvasRenderingContextWebGL* ctx = new WebGLContext();
@@ -412,665 +418,16 @@ NS_IMPL_ADDREF(WebGLRenderbuffer)
 NS_IMPL_RELEASE(WebGLRenderbuffer)
 
 NS_INTERFACE_MAP_BEGIN(WebGLRenderbuffer)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLRenderbuffer)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(WebGLRenderbuffer)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_ADDREF(WebGLFloatArray)
-NS_IMPL_RELEASE(WebGLFloatArray)
-
-NS_INTERFACE_MAP_BEGIN(WebGLFloatArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasFloatArray)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasFloatArray)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
-  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasFloatArray)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_ADDREF(WebGLByteArray)
-NS_IMPL_RELEASE(WebGLByteArray)
-
-NS_INTERFACE_MAP_BEGIN(WebGLByteArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasByteArray)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasByteArray)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
-  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasByteArray)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_ADDREF(WebGLUnsignedByteArray)
-NS_IMPL_RELEASE(WebGLUnsignedByteArray)
-
-NS_INTERFACE_MAP_BEGIN(WebGLUnsignedByteArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasUnsignedByteArray)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasUnsignedByteArray)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
-  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasUnsignedByteArray)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_ADDREF(WebGLShortArray)
-NS_IMPL_RELEASE(WebGLShortArray)
-
-NS_INTERFACE_MAP_BEGIN(WebGLShortArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasShortArray)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasShortArray)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
-  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasShortArray)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_ADDREF(WebGLUnsignedShortArray)
-NS_IMPL_RELEASE(WebGLUnsignedShortArray)
-
-NS_INTERFACE_MAP_BEGIN(WebGLUnsignedShortArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasUnsignedShortArray)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasUnsignedShortArray)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
-  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasUnsignedShortArray)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_ADDREF(WebGLIntArray)
-NS_IMPL_RELEASE(WebGLIntArray)
-
-NS_INTERFACE_MAP_BEGIN(WebGLIntArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasIntArray)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasIntArray)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
-  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasIntArray)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_ADDREF(WebGLUnsignedIntArray)
-NS_IMPL_RELEASE(WebGLUnsignedIntArray)
-
-NS_INTERFACE_MAP_BEGIN(WebGLUnsignedIntArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasArray)
-  NS_INTERFACE_MAP_ENTRY(nsICanvasUnsignedIntArray)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICanvasUnsignedIntArray)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
-  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasUnsignedIntArray)
-NS_INTERFACE_MAP_END
-
-
-nsresult
-NS_NewCanvasFloatArray(nsISupports **aResult)
-{
-    nsICanvasFloatArray *wgfa = new WebGLFloatArray();
-    if (!wgfa)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_ADDREF(*aResult = wgfa);
-    return NS_OK;
-}
-
-WebGLFloatArray::WebGLFloatArray()
-{
-}
-
-WebGLFloatArray::WebGLFloatArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
-{
-    mBuffer.InitFromJSArray(LOCAL_GL_FLOAT, 1, cx, arrayObj, arrayLen);
-}
-
-NS_IMETHODIMP
-WebGLFloatArray::Initialize(nsISupports *owner,
-                            JSContext *cx,
-                            JSObject *obj,
-                            PRUint32 argc,
-                            jsval *argv)
-{
-    JSObject *arrayObj;
-    jsuint arrayLen;
-
-    if (!::JS_ConvertArguments(cx, argc, argv, "o", &arrayObj) ||
-        arrayObj == NULL ||
-        !::JS_IsArrayObject(cx, arrayObj) ||
-        !::JS_GetArrayLength(cx, arrayObj, &arrayLen))
-    {
-        return NS_ERROR_DOM_SYNTAX_ERR;
-    }
-
-    mBuffer.InitFromJSArray(LOCAL_GL_FLOAT, 1, cx, arrayObj, arrayLen);
-
-    return NS_OK;
-}
-
-/* attribute unsigned long length; */
-NS_IMETHODIMP WebGLFloatArray::GetLength(PRUint32 *aLength)
-{
-    *aLength = mBuffer.length;
-    return NS_OK;
-}
-NS_IMETHODIMP WebGLFloatArray::SetLength(PRUint32 aLength)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP_(PRUint32) WebGLFloatArray::NativeType()
-{
-    return mBuffer.type;
-}
-
-/* [noscript, notxpcom] voidPtr nativePointer (); */
-NS_IMETHODIMP_(void *) WebGLFloatArray::NativePointer()
-{
-    return mBuffer.data;
-}
-
-/* [noscript, notxpcom] unsigned long nativeSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLFloatArray::NativeSize()
-{
-    return mBuffer.capacity;
-}
-
-/* [noscript, notxpcom] unsigned long nativeElementSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLFloatArray::NativeElementSize()
-{
-    return mBuffer.ElementSize();
-}
-
-/* [noscript, notxpcom] unsigned long nativeCount (); */
-NS_IMETHODIMP_(PRUint32) WebGLFloatArray::NativeCount()
-{
-    return mBuffer.length;
-}
-
-nsresult
-NS_NewCanvasByteArray(nsISupports **aResult)
-{
-    nsICanvasByteArray *wgba = new WebGLByteArray();
-    if (!wgba)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_ADDREF(*aResult = wgba);
-    return NS_OK;
-}
-
-WebGLByteArray::WebGLByteArray() { }
- 
-WebGLByteArray::WebGLByteArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
-{
-    mBuffer.InitFromJSArray(LOCAL_GL_BYTE, 1, cx, arrayObj, arrayLen);
-}
-
-NS_IMETHODIMP
-WebGLByteArray::Initialize(nsISupports *owner,
-                           JSContext *cx,
-                           JSObject *obj,
-                           PRUint32 argc,
-                           jsval *argv)
-{
-    JSObject *arrayObj;
-    jsuint arrayLen;
-
-    if (!::JS_ConvertArguments(cx, argc, argv, "o", &arrayObj) ||
-        arrayObj == NULL ||
-        !::JS_IsArrayObject(cx, arrayObj) ||
-        !::JS_GetArrayLength(cx, arrayObj, &arrayLen))
-    {
-        return NS_ERROR_DOM_SYNTAX_ERR;
-    }
-
-    mBuffer.InitFromJSArray(LOCAL_GL_BYTE, 1, cx, arrayObj, arrayLen);
-
-    return NS_OK;
-}
-
-/* attribute unsigned long length; */
-NS_IMETHODIMP WebGLByteArray::GetLength(PRUint32 *aLength)
-{
-    *aLength = mBuffer.length;
-    return NS_OK;
-}
-NS_IMETHODIMP WebGLByteArray::SetLength(PRUint32 aLength)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP_(PRUint32) WebGLByteArray::NativeType()
-{
-    return mBuffer.type;
-}
-
-/* [noscript, notxpcom] voidPtr nativePointer (); */
-NS_IMETHODIMP_(void *) WebGLByteArray::NativePointer()
-{
-    return mBuffer.data;
-}
-
-/* [noscript, notxpcom] unsigned long nativeSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLByteArray::NativeSize()
-{
-    return mBuffer.capacity;
-}
-
-/* [noscript, notxpcom] unsigned long nativeElementSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLByteArray::NativeElementSize()
-{
-    return mBuffer.ElementSize();
-}
-
-/* [noscript, notxpcom] unsigned long nativeCount (); */
-NS_IMETHODIMP_(PRUint32) WebGLByteArray::NativeCount()
-{
-    return mBuffer.length;
-}
-
-nsresult
-NS_NewCanvasUnsignedByteArray(nsISupports **aResult)
-{
-    nsICanvasUnsignedByteArray *wguba = new WebGLUnsignedByteArray();
-    if (!wguba)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_ADDREF(*aResult = wguba);
-    return NS_OK;
-}
-
-WebGLUnsignedByteArray::WebGLUnsignedByteArray() { }
-
-WebGLUnsignedByteArray::WebGLUnsignedByteArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
-{
-    mBuffer.InitFromJSArray(LOCAL_GL_UNSIGNED_BYTE, 1, cx, arrayObj, arrayLen);
-}
-
-NS_IMETHODIMP
-WebGLUnsignedByteArray::Initialize(nsISupports *owner,
-                                   JSContext *cx,
-                                   JSObject *obj,
-                                   PRUint32 argc,
-                                   jsval *argv)
-{
-    JSObject *arrayObj;
-    jsuint arrayLen;
-
-    if (!::JS_ConvertArguments(cx, argc, argv, "o", &arrayObj) ||
-        arrayObj == NULL ||
-        !::JS_IsArrayObject(cx, arrayObj) ||
-        !::JS_GetArrayLength(cx, arrayObj, &arrayLen))
-    {
-        return NS_ERROR_DOM_SYNTAX_ERR;
-    }
-
-    mBuffer.InitFromJSArray(LOCAL_GL_UNSIGNED_BYTE, 1, cx, arrayObj, arrayLen);
-
-    return NS_OK;
-}
-
-/* attribute unsigned long length; */
-NS_IMETHODIMP WebGLUnsignedByteArray::GetLength(PRUint32 *aLength)
-{
-    *aLength = mBuffer.length;
-    return NS_OK;
-}
-NS_IMETHODIMP WebGLUnsignedByteArray::SetLength(PRUint32 aLength)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedByteArray::NativeType()
-{
-    return mBuffer.type;
-}
-
-/* [noscript, notxpcom] voidPtr nativePointer (); */
-NS_IMETHODIMP_(void *) WebGLUnsignedByteArray::NativePointer()
-{
-    return mBuffer.data;
-}
-
-/* [noscript, notxpcom] unsigned long nativeSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedByteArray::NativeSize()
-{
-    return mBuffer.capacity;
-}
-
-/* [noscript, notxpcom] unsigned long nativeElementSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedByteArray::NativeElementSize()
-{
-    return mBuffer.ElementSize();
-}
-
-/* [noscript, notxpcom] unsigned long nativeCount (); */
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedByteArray::NativeCount()
-{
-    return mBuffer.length;
-}
-
-nsresult
-NS_NewCanvasShortArray(nsISupports **aResult)
-{
-    nsICanvasShortArray *wgsa = new WebGLShortArray();
-    if (!wgsa)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_ADDREF(*aResult = wgsa);
-    return NS_OK;
-}
-
-WebGLShortArray::WebGLShortArray() { }
-
-WebGLShortArray::WebGLShortArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
-{
-    mBuffer.InitFromJSArray(LOCAL_GL_SHORT, 1, cx, arrayObj, arrayLen);
-}
-
-NS_IMETHODIMP
-WebGLShortArray::Initialize(nsISupports *owner,
-                            JSContext *cx,
-                            JSObject *obj,
-                            PRUint32 argc,
-                            jsval *argv)
-{
-    JSObject *arrayObj;
-    jsuint arrayLen;
-
-    if (!::JS_ConvertArguments(cx, argc, argv, "o", &arrayObj) ||
-        arrayObj == NULL ||
-        !::JS_IsArrayObject(cx, arrayObj) ||
-        !::JS_GetArrayLength(cx, arrayObj, &arrayLen))
-    {
-        return NS_ERROR_DOM_SYNTAX_ERR;
-    }
-
-    mBuffer.InitFromJSArray(LOCAL_GL_SHORT, 1, cx, arrayObj, arrayLen);
-
-    return NS_OK;
-}
-
-/* attribute unsigned long length; */
-NS_IMETHODIMP WebGLShortArray::GetLength(PRUint32 *aLength)
-{
-    *aLength = mBuffer.length;
-    return NS_OK;
-}
-NS_IMETHODIMP WebGLShortArray::SetLength(PRUint32 aLength)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP_(PRUint32) WebGLShortArray::NativeType()
-{
-    return mBuffer.type;
-}
-
-/* [noscript, notxpcom] voidPtr nativePointer (); */
-NS_IMETHODIMP_(void *) WebGLShortArray::NativePointer()
-{
-    return mBuffer.data;
-}
-
-/* [noscript, notxpcom] unsigned long nativeSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLShortArray::NativeSize()
-{
-    return mBuffer.capacity;
-}
-
-/* [noscript, notxpcom] unsigned long nativeElementSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLShortArray::NativeElementSize()
-{
-    return mBuffer.ElementSize();
-}
-
-/* [noscript, notxpcom] unsigned long nativeCount (); */
-NS_IMETHODIMP_(PRUint32) WebGLShortArray::NativeCount()
-{
-    return mBuffer.length;
-}
-
-
-nsresult
-NS_NewCanvasUnsignedShortArray(nsISupports **aResult)
-{
-    nsICanvasUnsignedShortArray *wgusa = new WebGLUnsignedShortArray();
-    if (!wgusa)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_ADDREF(*aResult = wgusa);
-    return NS_OK;
-}
-
-WebGLUnsignedShortArray::WebGLUnsignedShortArray() { }
-
-WebGLUnsignedShortArray::WebGLUnsignedShortArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
-{
-    mBuffer.InitFromJSArray(LOCAL_GL_UNSIGNED_SHORT, 1, cx, arrayObj, arrayLen);
-}
-
-NS_IMETHODIMP
-WebGLUnsignedShortArray::Initialize(nsISupports *owner,
-                                   JSContext *cx,
-                                   JSObject *obj,
-                                   PRUint32 argc,
-                                   jsval *argv)
-{
-    JSObject *arrayObj;
-    jsuint arrayLen;
-
-    if (!::JS_ConvertArguments(cx, argc, argv, "o", &arrayObj) ||
-        arrayObj == NULL ||
-        !::JS_IsArrayObject(cx, arrayObj) ||
-        !::JS_GetArrayLength(cx, arrayObj, &arrayLen))
-    {
-        return NS_ERROR_DOM_SYNTAX_ERR;
-    }
-
-    mBuffer.InitFromJSArray(LOCAL_GL_UNSIGNED_SHORT, 1, cx, arrayObj, arrayLen);
-
-    return NS_OK;
-}
-
-/* attribute unsigned long length; */
-NS_IMETHODIMP WebGLUnsignedShortArray::GetLength(PRUint32 *aLength)
-{
-    *aLength = mBuffer.length;
-    return NS_OK;
-}
-NS_IMETHODIMP WebGLUnsignedShortArray::SetLength(PRUint32 aLength)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedShortArray::NativeType()
-{
-    return mBuffer.type;
-}
-
-/* [noscript, notxpcom] voidPtr nativePointer (); */
-NS_IMETHODIMP_(void *) WebGLUnsignedShortArray::NativePointer()
-{
-    return mBuffer.data;
-}
-
-/* [noscript, notxpcom] unsigned long nativeSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedShortArray::NativeSize()
-{
-    return mBuffer.capacity;
-}
-
-/* [noscript, notxpcom] unsigned long nativeElementSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedShortArray::NativeElementSize()
-{
-    return mBuffer.ElementSize();
-}
-
-/* [noscript, notxpcom] unsigned long nativeCount (); */
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedShortArray::NativeCount()
-{
-    return mBuffer.length;
-}
-
-nsresult
-NS_NewCanvasIntArray(nsISupports **aResult)
-{
-    nsICanvasIntArray *wgia = new WebGLIntArray();
-    if (!wgia)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_ADDREF(*aResult = wgia);
-    return NS_OK;
-}
-
-WebGLIntArray::WebGLIntArray() { }
-
-WebGLIntArray::WebGLIntArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
-{
-    mBuffer.InitFromJSArray(LOCAL_GL_INT, 1, cx, arrayObj, arrayLen);
-}
-
-NS_IMETHODIMP
-WebGLIntArray::Initialize(nsISupports *owner,
-                          JSContext *cx,
-                          JSObject *obj,
-                          PRUint32 argc,
-                          jsval *argv)
-{
-    JSObject *arrayObj;
-    jsuint arrayLen;
-
-    if (!::JS_ConvertArguments(cx, argc, argv, "o", &arrayObj) ||
-        arrayObj == NULL ||
-        !::JS_IsArrayObject(cx, arrayObj) ||
-        !::JS_GetArrayLength(cx, arrayObj, &arrayLen))
-    {
-        return NS_ERROR_DOM_SYNTAX_ERR;
-    }
-
-    mBuffer.InitFromJSArray(LOCAL_GL_INT, 1, cx, arrayObj, arrayLen);
-
-    return NS_OK;
-}
-
-
-/* attribute unsigned long length; */
-NS_IMETHODIMP WebGLIntArray::GetLength(PRUint32 *aLength)
-{
-    *aLength = mBuffer.length;
-    return NS_OK;
-}
-NS_IMETHODIMP WebGLIntArray::SetLength(PRUint32 aLength)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP_(PRUint32) WebGLIntArray::NativeType()
-{
-    return mBuffer.type;
-}
-
-/* [noscript, notxpcom] voidPtr nativePointer (); */
-NS_IMETHODIMP_(void *) WebGLIntArray::NativePointer()
-{
-    return mBuffer.data;
-}
-
-/* [noscript, notxpcom] unsigned long nativeSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLIntArray::NativeSize()
-{
-    return mBuffer.capacity;
-}
-
-/* [noscript, notxpcom] unsigned long nativeElementSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLIntArray::NativeElementSize()
-{
-    return mBuffer.ElementSize();
-}
-
-/* [noscript, notxpcom] unsigned long nativeCount (); */
-NS_IMETHODIMP_(PRUint32) WebGLIntArray::NativeCount()
-{
-    return mBuffer.length;
-}
-
-nsresult
-NS_NewCanvasUnsignedIntArray(nsISupports **aResult)
-{
-    nsICanvasUnsignedIntArray *wguia = new WebGLUnsignedIntArray();
-    if (!wguia)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_ADDREF(*aResult = wguia);
-    return NS_OK;
-}
-
-WebGLUnsignedIntArray::WebGLUnsignedIntArray() { }
-
-WebGLUnsignedIntArray::WebGLUnsignedIntArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen)
-{
-    mBuffer.InitFromJSArray(LOCAL_GL_UNSIGNED_INT, 1, cx, arrayObj, arrayLen);
-}
-
-NS_IMETHODIMP
-WebGLUnsignedIntArray::Initialize(nsISupports *owner,
-                                  JSContext *cx,
-                                  JSObject *obj,
-                                  PRUint32 argc,
-                                  jsval *argv)
-{
-    JSObject *arrayObj;
-    jsuint arrayLen;
-
-    if (!::JS_ConvertArguments(cx, argc, argv, "o", &arrayObj) ||
-        arrayObj == NULL ||
-        !::JS_IsArrayObject(cx, arrayObj) ||
-        !::JS_GetArrayLength(cx, arrayObj, &arrayLen))
-    {
-        return NS_ERROR_DOM_SYNTAX_ERR;
-    }
-
-    mBuffer.InitFromJSArray(LOCAL_GL_UNSIGNED_INT, 1, cx, arrayObj, arrayLen);
-
-    return NS_OK;
-}
-
-/* attribute unsigned long length; */
-NS_IMETHODIMP WebGLUnsignedIntArray::GetLength(PRUint32 *aLength)
-{
-    *aLength = mBuffer.length;
-    return NS_OK;
-}
-NS_IMETHODIMP WebGLUnsignedIntArray::SetLength(PRUint32 aLength)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedIntArray::NativeType()
-{
-    return mBuffer.type;
-}
-
-/* [noscript, notxpcom] voidPtr nativePointer (); */
-NS_IMETHODIMP_(void *) WebGLUnsignedIntArray::NativePointer()
-{
-    return mBuffer.data;
-}
-
-/* [noscript, notxpcom] unsigned long nativeSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedIntArray::NativeSize()
-{
-    return mBuffer.capacity;
-}
-
-/* [noscript, notxpcom] unsigned long nativeElementSize (); */
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedIntArray::NativeElementSize()
-{
-    return mBuffer.ElementSize();
-}
-
-/* [noscript, notxpcom] unsigned long nativeCount (); */
-NS_IMETHODIMP_(PRUint32) WebGLUnsignedIntArray::NativeCount()
-{
-    return mBuffer.length;
-}
-
 /* [noscript] attribute GLuint name; */
 NS_IMETHODIMP WebGLTexture::GetName(GLuint *aName)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 NS_IMETHODIMP WebGLTexture::SetName(GLuint aName)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -53,16 +53,18 @@
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsWeakReference.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIJSNativeInitializer.h"
 
 #include "SimpleBuffer.h"
 #include "nsGLPbuffer.h"
 
+#include "WebGLArrays.h"
+
 class nsIDocShell;
 
 namespace mozilla {
 
 class WebGLArray;
 class WebGLTexture;
 class WebGLBuffer;
 class WebGLProgram;
@@ -351,16 +353,20 @@ public:
     GLuint GLName() { return mName; }
 
     void Set(nsICanvasArray *na) {
         mGLType = na->NativeType();
         mElementSize = na->NativeElementSize();
         mCount = na->NativeCount();
     }
 
+    void SetCount(GLuint count) {
+        mCount = count;
+    }
+
     GLenum GLType() { return mGLType; }
     PRUint32 ByteCount() { return mElementSize * mCount; }
     PRUint32 Count() { return mCount; }
     PRUint32 ElementSize() { return mElementSize; }
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLBUFFER
 protected:
@@ -488,193 +494,11 @@ public:
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLRENDERBUFFER
 protected:
     GLuint mName;
     PRBool mDeleted;
 };
 
-//
-// array wrapper classes
-//
-
-class WebGLFloatArray :
-    public nsICanvasFloatArray,
-    public nsIJSNativeInitializer
-{
-public:
-    WebGLFloatArray();
-    WebGLFloatArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSICANVASARRAY
-    NS_DECL_NSICANVASFLOATARRAY
-
-    static nsresult NewCanvasFloatArray(nsISupports **aNewObject);
-
-    NS_IMETHOD Initialize(nsISupports* aOwner,
-                          JSContext* aCx,
-                          JSObject* aObj,
-                          PRUint32 aArgc,
-                          jsval* aArgv);
-
-protected:
-    SimpleBuffer mBuffer;
-    PRUint32 mLength;
-    PRUint32 mSize;
-    PRUint32 mElementSize;
-    PRUint32 mCount;
-};
-
-class WebGLByteArray :
-    public nsICanvasByteArray,
-    public nsIJSNativeInitializer
-{
-public:
-    WebGLByteArray();
-    WebGLByteArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSICANVASARRAY
-    NS_DECL_NSICANVASBYTEARRAY
-
-    NS_IMETHOD Initialize(nsISupports* aOwner,
-                          JSContext* aCx,
-                          JSObject* aObj,
-                          PRUint32 aArgc,
-                          jsval* aArgv);
-protected:
-    SimpleBuffer mBuffer;
-    PRUint32 mLength;
-    PRUint32 mSize;
-    PRUint32 mElementSize;
-    PRUint32 mCount;
-};
-
-class WebGLUnsignedByteArray :
-    public nsICanvasUnsignedByteArray,
-    public nsIJSNativeInitializer
-{
-public:
-    WebGLUnsignedByteArray();
-    WebGLUnsignedByteArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSICANVASARRAY
-    NS_DECL_NSICANVASUNSIGNEDBYTEARRAY
-
-    NS_IMETHOD Initialize(nsISupports* aOwner,
-                          JSContext* aCx,
-                          JSObject* aObj,
-                          PRUint32 aArgc,
-                          jsval* aArgv);
-protected:
-    SimpleBuffer mBuffer;
-    PRUint32 mLength;
-    PRUint32 mSize;
-    PRUint32 mElementSize;
-    PRUint32 mCount;
-};
-
-class WebGLShortArray :
-    public nsICanvasShortArray,
-    public nsIJSNativeInitializer
-{
-public:
-    WebGLShortArray();
-    WebGLShortArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSICANVASARRAY
-    NS_DECL_NSICANVASSHORTARRAY
-
-    NS_IMETHOD Initialize(nsISupports* aOwner,
-                          JSContext* aCx,
-                          JSObject* aObj,
-                          PRUint32 aArgc,
-                          jsval* aArgv);
-protected:
-    SimpleBuffer mBuffer;
-    PRUint32 mLength;
-    PRUint32 mSize;
-    PRUint32 mElementSize;
-    PRUint32 mCount;
-};
-
-class WebGLUnsignedShortArray :
-    public nsICanvasUnsignedShortArray,
-    public nsIJSNativeInitializer
-{
-public:
-    WebGLUnsignedShortArray();
-    WebGLUnsignedShortArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSICANVASARRAY
-    NS_DECL_NSICANVASUNSIGNEDSHORTARRAY
-
-    NS_IMETHOD Initialize(nsISupports* aOwner,
-                          JSContext* aCx,
-                          JSObject* aObj,
-                          PRUint32 aArgc,
-                          jsval* aArgv);
-protected:
-    SimpleBuffer mBuffer;
-    PRUint32 mLength;
-    PRUint32 mSize;
-    PRUint32 mElementSize;
-    PRUint32 mCount;
-};
-
-class WebGLIntArray :
-    public nsICanvasIntArray,
-    public nsIJSNativeInitializer
-{
-public:
-    WebGLIntArray();
-    WebGLIntArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSICANVASARRAY
-    NS_DECL_NSICANVASINTARRAY
-
-    NS_IMETHOD Initialize(nsISupports* aOwner,
-                          JSContext* aCx,
-                          JSObject* aObj,
-                          PRUint32 aArgc,
-                          jsval* aArgv);
-protected:
-    SimpleBuffer mBuffer;
-    PRUint32 mLength;
-    PRUint32 mSize;
-    PRUint32 mElementSize;
-    PRUint32 mCount;
-};
-
-class WebGLUnsignedIntArray :
-    public nsICanvasUnsignedIntArray,
-    public nsIJSNativeInitializer
-{
-public:
-    WebGLUnsignedIntArray();
-    WebGLUnsignedIntArray(JSContext *cx, JSObject *arrayObj, jsuint arrayLen);
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSICANVASARRAY
-    NS_DECL_NSICANVASUNSIGNEDINTARRAY
-
-    NS_IMETHOD Initialize(nsISupports* aOwner,
-                          JSContext* aCx,
-                          JSObject* aObj,
-                          PRUint32 aArgc,
-                          jsval* aArgv);
-protected:
-    SimpleBuffer mBuffer;
-    PRUint32 mLength;
-    PRUint32 mSize;
-    PRUint32 mElementSize;
-    PRUint32 mCount;
-};
-
 }
 
 #endif
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -349,16 +349,30 @@ WebGLContext::GetCurrentProgram(nsIWebGL
 
 /* void present (); */
 NS_IMETHODIMP
 WebGLContext::Present()
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+/* long sizeInBytes (in GLenum type); */
+NS_IMETHODIMP
+WebGLContext::SizeInBytes(GLenum type, PRInt32 *retval)
+{
+    if (type == LOCAL_GL_FLOAT) *retval = sizeof(float);
+    if (type == LOCAL_GL_SHORT) *retval = sizeof(short);
+    if (type == LOCAL_GL_UNSIGNED_SHORT) *retval = sizeof(unsigned short);
+    if (type == LOCAL_GL_BYTE) *retval = 1;
+    if (type == LOCAL_GL_UNSIGNED_BYTE) *retval = 1;
+    if (type == LOCAL_GL_INT) *retval = sizeof(int);
+    if (type == LOCAL_GL_UNSIGNED_INT) *retval = sizeof(unsigned int);
+    if (type == LOCAL_GL_DOUBLE) *retval = sizeof(double);
+    return NS_OK;
+}
 
 /* void GlActiveTexture (in PRUint32 texture); */
 NS_IMETHODIMP
 WebGLContext::ActiveTexture(PRUint32 texture)
 {
     if (texture < LOCAL_GL_TEXTURE0 || texture >= LOCAL_GL_TEXTURE0+mBound2DTextures.Length())
         return NS_ERROR_DOM_SYNTAX_ERR;
 
@@ -437,17 +451,18 @@ WebGLContext::BindFramebuffer(GLenum tar
     if (wfb && wfb->Deleted())
         return ErrorMessage("glBindFramebuffer: framebuffer has already been deleted!");
 
     MakeContextCurrent();
 
     if (target >= LOCAL_GL_COLOR_ATTACHMENT0 &&
         target < (LOCAL_GL_COLOR_ATTACHMENT0 + mBoundColorFramebuffers.Length()))
     {
-        mBoundColorFramebuffers[target] = wfb;
+        int targetOffset = target - LOCAL_GL_COLOR_ATTACHMENT0;
+        mBoundColorFramebuffers[targetOffset] = wfb;
     } else if (target == LOCAL_GL_DEPTH_ATTACHMENT) {
         mBoundDepthFramebuffer = wfb;
     } else if (target == LOCAL_GL_STENCIL_ATTACHMENT) {
         mBoundStencilFramebuffer = wfb;
     } else {
         return ErrorMessage("glBindFramebuffer: invalid target");
     }
 
@@ -503,92 +518,196 @@ GL_SAME_METHOD_1(BlendEquation, BlendEqu
 
 GL_SAME_METHOD_2(BlendEquationSeparate, BlendEquationSeparate, PRUint32, PRUint32)
 
 GL_SAME_METHOD_2(BlendFunc, BlendFunc, PRUint32, PRUint32)
 
 GL_SAME_METHOD_4(BlendFuncSeparate, BlendFuncSeparate, PRUint32, PRUint32, PRUint32, PRUint32)
 
 NS_IMETHODIMP
-WebGLContext::BufferData(GLenum target, nsICanvasArray *na, GLenum usage)
+WebGLContext::BufferData(GLenum target)
 {
+    // overloaded:
+    // void bufferData (in GLenum target, in GLsizei size, in GLenum usage);
+    // void bufferData (in GLenum target, in nsICanvasArray data, in GLenum usage);
+    // void bufferData (in GLenum target, in nsICanvasArrayBuffer data, in GLenum usage)
+
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    if (js.argc != 3)
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
     WebGLBuffer *boundBuffer = NULL;
 
     if (target == LOCAL_GL_ARRAY_BUFFER) {
         boundBuffer = mBoundArrayBuffer;
     } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
-        if (na->NativeType() != LOCAL_GL_UNSIGNED_SHORT)
-            return ErrorMessage("glBufferData: %x - GL_ELEMENT_ARRAY_BUFFER target must be used with UnsignedShortBuffer", na->NativeType());
+        // XXX fix type check
+        //if (na->NativeType() != LOCAL_GL_UNSIGNED_SHORT)
+        //    return ErrorMessage("glBufferData: %x - GL_ELEMENT_ARRAY_BUFFER target must be used with UnsignedShortBuffer", na->NativeType());
 
         boundBuffer = mBoundElementArrayBuffer;
     } else {
         return ErrorMessage("glBufferData: invalid target");
     }
 
     if (boundBuffer == NULL) {
         return ErrorMessage("glBufferData: no buffer bound!");
     }
 
+
     MakeContextCurrent();
 
-    boundBuffer->Set(na);
-
-    gl->fBufferData(target, na->NativeSize(), na->NativePointer(), usage);
+    uint32 usage;
+
+    if (!::JS_ValueToECMAUint32(js.ctx, js.argv[2], &usage)) {
+        return ErrorMessage("bufferData: invalid usage parameter");
+    }
+
+    if (JSVAL_IS_NUMBER(js.argv[1])) {
+        int32 size;
+        if (!::JS_ValueToECMAInt32(js.ctx, js.argv[1], &size)) {
+            return ErrorMessage("bufferData: invalid size parameter");
+        }
+        boundBuffer->SetCount(size);
+        gl->fBufferData(target, size, 0, usage);
+    } else if (JSVAL_IS_OBJECT(js.argv[1])) {
+        nsCOMPtr<nsICanvasArray> canvasArrayObj;
+        nsresult rv;
+
+        rv = nsContentUtils::XPConnect()->WrapJS(js.ctx, JSVAL_TO_OBJECT(js.argv[1]),
+                                                 NS_GET_IID(nsICanvasArray), getter_AddRefs(canvasArrayObj));
+        if (NS_FAILED(rv) || !canvasArrayObj) {
+            nsCOMPtr<nsICanvasArrayBuffer> arrayBuf;
+            rv = nsContentUtils::XPConnect()->WrapJS(js.ctx, JSVAL_TO_OBJECT(js.argv[1]),
+                                                     NS_GET_IID(nsICanvasArrayBuffer), getter_AddRefs(arrayBuf));
+            if (NS_FAILED(rv) || !arrayBuf)
+                return ErrorMessage("bufferData: need CanvasArray or CanvasArrayBuffer");
+
+            boundBuffer->SetCount(arrayBuf->NativeSize());
+            gl->fBufferData(target, arrayBuf->NativeSize(), arrayBuf->NativePointer(), usage);
+        } else {
+            boundBuffer->Set(canvasArrayObj);
+            gl->fBufferData(target, canvasArrayObj->NativeSize(), canvasArrayObj->NativePointer(), usage);
+        }
+    } else {
+        return ErrorMessage("bufferData: invalid data");
+    }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
-WebGLContext::BufferSubData(GLenum target, GLuint offset, nsICanvasArray *na)
+WebGLContext::BufferSubData(GLenum target, GLsizeiptr offset)
 {
+    // overloaded:
+    // void bufferSubData(in GLenum target, in GLsizeiptr offset, in CanvasArray data) 
+    // void bufferSubData(in GLenum target, in GLsizeiptr offset, in CanvasArrayBuffer data) 
+
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    if (js.argc != 3)
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
     WebGLBuffer *boundBuffer = NULL;
 
     if (target == LOCAL_GL_ARRAY_BUFFER) {
         boundBuffer = mBoundArrayBuffer;
     } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
         boundBuffer = mBoundElementArrayBuffer;
     } else {
         return ErrorMessage("glBufferSubData: invalid target");
     }
 
     if (boundBuffer == NULL) {
         return ErrorMessage("glBufferSubData: no buffer bound!");
     }
 
+    /* XXX FIXME 
     // check type
     if (na->NativeType() != boundBuffer->GLType()) {
         return ErrorMessage("glBufferSubData: existing buffer has different base type (0x%04x) the sub data (0x%04x)!", boundBuffer->GLType(), na->NativeType());
         return NS_ERROR_FAILURE;
     }
-
-    // check size
-    if ((offset + na->NativeCount()) > boundBuffer->Count()) {
-        return ErrorMessage("glBufferSubData: existing buffer is too small for additional data");
-        return NS_ERROR_FAILURE;
+    */
+
+    if (JSVAL_IS_OBJECT(js.argv[2])) {
+        nsCOMPtr<nsICanvasArray> canvasArrayObj;
+        nsresult rv;
+
+        rv = nsContentUtils::XPConnect()->WrapJS(js.ctx, JSVAL_TO_OBJECT(js.argv[2]),
+                                                 NS_GET_IID(nsICanvasArray), getter_AddRefs(canvasArrayObj));
+        if (NS_FAILED(rv) || !canvasArrayObj) {
+            nsCOMPtr<nsICanvasArrayBuffer> arrayBuf;
+            rv = nsContentUtils::XPConnect()->WrapJS(js.ctx, JSVAL_TO_OBJECT(js.argv[2]),
+                                                     NS_GET_IID(nsICanvasArrayBuffer), getter_AddRefs(arrayBuf));
+            if (NS_FAILED(rv) || !arrayBuf)
+                return ErrorMessage("bufferData: need CanvasArray or CanvasArrayBuffer");
+
+            // check size
+            // XXX should be bytes
+            if ((offset + arrayBuf->NativeSize()) > boundBuffer->Count()) {
+                return ErrorMessage("glBufferSubData: existing buffer is too small (%d) for data at offset (%d+%d)",
+                                    boundBuffer->Count(), offset, arrayBuf->NativeSize());
+                return NS_ERROR_FAILURE;
+            }
+#ifdef DEBUG
+            LogMessage("bufferSubData: buffer (%d) for data at offset (%d+%d)", boundBuffer->Count(), offset, arrayBuf->NativeSize());
+#endif
+            // all good
+
+            MakeContextCurrent();
+
+            gl->fBufferSubData(target, offset, arrayBuf->NativeSize(), arrayBuf->NativePointer());
+        } else {
+            // check size
+            // XXX should be bytes
+            if ((offset + canvasArrayObj->NativeCount()) > boundBuffer->Count()) {
+                return ErrorMessage("glBufferSubData: existing buffer is too small (%d) for data at offset (%d+%d)",
+                                    boundBuffer->Count(), offset, canvasArrayObj->NativeCount());
+                return NS_ERROR_FAILURE;
+            }
+#ifdef DEBUG
+            LogMessage("bufferSubData: buffer (%d) for data at offset (%d+%d)", boundBuffer->Count(), offset, canvasArrayObj->NativeSize());
+#endif
+            // all good
+
+            MakeContextCurrent();
+
+            gl->fBufferSubData(target, offset, canvasArrayObj->NativeSize(), canvasArrayObj->NativePointer());
+        }
+    } else {
+        return ErrorMessage("bufferData: invalid data");
     }
 
-    // all good
-
-    MakeContextCurrent();
-
-    gl->fBufferSubData(target, offset * na->NativeElementSize(), na->NativeSize(), na->NativePointer());
-
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::CheckFramebufferStatus(GLenum target, GLenum *retval)
 {
     MakeContextCurrent();
     // XXX check target
     *retval = gl->fCheckFramebufferStatus(target);
     return NS_OK;
 }
 
-GL_SAME_METHOD_1(Clear, Clear, PRUint32)
+NS_IMETHODIMP
+WebGLContext::Clear(PRUint32 mask)
+{
+    MakeContextCurrent();
+    gl->fClear(mask);
+    Invalidate();
+
+    return NS_OK;
+}
 
 GL_SAME_METHOD_4(ClearColor, ClearColor, float, float, float, float)
 
 #ifdef USE_GLES2
 GL_SAME_METHOD_1(ClearDepthf, ClearDepth, float)
 #else
 GL_SAME_METHOD_1(ClearDepth, ClearDepth, float)
 #endif
@@ -965,17 +1084,17 @@ WebGLContext::DrawElements(GLenum mode, 
         maxindex = PR_MAX(maxindex, *ubuf++);
 
     gl->fUnmapBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER);
 
     if (!ValidateBuffers(maxindex))
         return ErrorMessage("glDrawElements: ValidateBuffers failed");
 #endif
     // XXX uh, is this offset, or offset * elementsize?
-    gl->fDrawElements(mode, count, type, (GLvoid*) (offset * mBoundElementArrayBuffer->ElementSize()));
+    gl->fDrawElements(mode, count, type, (GLvoid*) (offset));
 
     Invalidate();
 
     return NS_OK;
 }
 
 // XXX definitely need to validate this
 GL_SAME_METHOD_1(Enable, Enable, PRUint32)
@@ -2395,17 +2514,17 @@ GL_SAME_METHOD_5(Uniform4i, Uniform4i, G
 GL_SAME_METHOD_2(Uniform1f, Uniform1f, GLint, GLfloat)
 GL_SAME_METHOD_3(Uniform2f, Uniform2f, GLint, GLfloat, GLfloat)
 GL_SAME_METHOD_4(Uniform3f, Uniform3f, GLint, GLfloat, GLfloat, GLfloat)
 GL_SAME_METHOD_5(Uniform4f, Uniform4f, GLint, GLfloat, GLfloat, GLfloat, GLfloat)
 
 // one uint arg followed by an array of c elements of glTypeConst.
 #define GL_SIMPLE_ARRAY_METHOD(glname, name, c, glTypeConst, ptrType)             \
 NS_IMETHODIMP                                                                     \
-WebGLContext::name(GLint idx, nsICanvasArray *v)                                   \
+WebGLContext::name(GLint idx, nsICanvasArray *v)                                  \
 {                                                                                 \
     NativeJSContext js;                                                           \
     if (NS_FAILED(js.error))                                                      \
         return js.error;                                                          \
     JSObject *arrayObj;                                                           \
     jsuint arrayLen;                                                              \
     if (js.argc != 2)                                                             \
         return NS_ERROR_INVALID_ARG;                                              \
@@ -2418,42 +2537,40 @@ WebGLContext::name(GLint idx, nsICanvasA
             return NS_ERROR_FAILURE;                                              \
         MakeContextCurrent();                                                     \
         gl->f##glname(idx, arrayLen / c, ( ptrType *)sbuffer.data);               \
     } else {                                                                      \
         if (glTypeConst == LOCAL_GL_INT) {                                        \
             if (v->NativeType() != LOCAL_GL_INT) {                                \
                 return ErrorMessage(#name ": arg not an array");                  \
             }                                                                     \
-            WebGLIntArray *wga = static_cast<WebGLIntArray*>(v);                  \
-            if (wga->NativeCount() % c != 0) {                                    \
+            if (v->NativeCount() % c != 0) {                                      \
                 return ErrorMessage(#name ": array length not divisible by " #c); \
             }                                                                     \
             MakeContextCurrent();                                                 \
-            gl->f##glname(idx, wga->NativeCount() / c, ( ptrType *)wga->NativePointer()); \
+            gl->f##glname(idx, v->NativeCount() / c, ( ptrType *)v->NativePointer()); \
         } else if (glTypeConst == LOCAL_GL_FLOAT) {                               \
             if (v->NativeType() != LOCAL_GL_FLOAT) {                              \
                 return ErrorMessage(#name ": arg not an array");                  \
             }                                                                     \
-            WebGLFloatArray *wga = static_cast<WebGLFloatArray*>(v);              \
-            if (wga->NativeCount() % c != 0) {                                    \
+            if (v->NativeCount() % c != 0) {                                      \
                 return ErrorMessage(#name ": array length not divisible by " #c); \
             }                                                                     \
             MakeContextCurrent();                                                 \
-            gl->f##glname(idx, wga->NativeCount() / c, ( ptrType *)wga->NativePointer()); \
+            gl->f##glname(idx, v->NativeCount() / c, ( ptrType *)v->NativePointer()); \
         } else {                                                                  \
             return ErrorMessage("Unhandled glTypeConst"); /* need compiler fail */\
         }                                                                         \
     }                                                                             \
     return NS_OK;                                                                 \
 }
 
 #define GL_SIMPLE_ARRAY_METHOD_NO_COUNT(glname, name, c, glTypeConst, ptrType)    \
 NS_IMETHODIMP                                                                     \
-WebGLContext::name(GLuint idx, nsICanvasArray *v)                                  \
+WebGLContext::name(GLuint idx, nsICanvasArray *v)                                 \
 {                                                                                 \
     NativeJSContext js;                                                           \
     if (NS_FAILED(js.error))                                                      \
         return js.error;                                                          \
     JSObject *arrayObj;                                                           \
     jsuint arrayLen;                                                              \
     if (js.argc != 2)                                                             \
         return NS_ERROR_INVALID_ARG;                                              \
@@ -2466,42 +2583,40 @@ WebGLContext::name(GLuint idx, nsICanvas
             return NS_ERROR_FAILURE;                                              \
         MakeContextCurrent();                                                     \
         gl->f##glname(idx, ( ptrType *)sbuffer.data);                             \
     } else {                                                                      \
         if (glTypeConst == LOCAL_GL_INT) {                                        \
             if (v->NativeType() != LOCAL_GL_INT) {                                \
                 return ErrorMessage(#name ": arg not an array");                  \
             }                                                                     \
-            WebGLIntArray *wga = static_cast<WebGLIntArray*>(v);                  \
-            if (wga->NativeCount() % c != 0) {                                    \
-                return ErrorMessage(#name ": array wrong size %d, expected " #c, wga->NativeCount()); \
+            if (v->NativeCount() % c != 0) {                                      \
+                return ErrorMessage(#name ": array wrong size %d, expected " #c, v->NativeCount()); \
             }                                                                     \
             MakeContextCurrent();                                                 \
-            gl->f##glname(idx, ( ptrType *)wga->NativePointer());                 \
+            gl->f##glname(idx, ( ptrType *)v->NativePointer());                   \
         } else if (glTypeConst == LOCAL_GL_FLOAT) {                               \
             if (v->NativeType() != LOCAL_GL_FLOAT) {                              \
                 return ErrorMessage(#name ": arg not an array");                  \
             }                                                                     \
-            WebGLFloatArray *wga = static_cast<WebGLFloatArray*>(v);              \
-            if (wga->NativeCount() % c != 0) {                                    \
-                return ErrorMessage(#name ": array wrong size %d, expected " #c, wga->NativeCount()); \
+            if (v->NativeCount() % c != 0) {                                      \
+                return ErrorMessage(#name ": array wrong size %d, expected " #c, v->NativeCount()); \
             }                                                                     \
             MakeContextCurrent();                                                 \
-            gl->f##glname(idx, ( ptrType *)wga->NativePointer());                 \
+            gl->f##glname(idx, ( ptrType *)v->NativePointer());                   \
         } else {                                                                  \
             return ErrorMessage("Unhandled glTypeConst"); /* need compiler fail */\
         }                                                                         \
     }                                                                             \
     return NS_OK;                                                                 \
 }
 
 #define GL_SIMPLE_MATRIX_METHOD(glname, name, c, glTypeConst, ptrType)            \
 NS_IMETHODIMP                                                                     \
-WebGLContext::name(GLint location, GLboolean transpose, nsICanvasArray *value)     \
+WebGLContext::name(GLint location, GLboolean transpose, nsICanvasArray *value)    \
 {                                                                                 \
     NativeJSContext js;                                                           \
     if (NS_FAILED(js.error))                                                      \
         return js.error;                                                          \
     JSObject *arrayObj;                                                           \
     jsuint arrayLen;                                                              \
     if (js.argc != 3)                                                             \
         return NS_ERROR_INVALID_ARG;                                              \
@@ -2514,22 +2629,21 @@ WebGLContext::name(GLint location, GLboo
             return NS_ERROR_FAILURE;                                              \
         MakeContextCurrent();                                                     \
         gl->f##glname(location, arrayLen / c, transpose, ( ptrType *)sbuffer.data); \
     } else {                                                                      \
         if (glTypeConst == LOCAL_GL_FLOAT) {                                      \
             if (value->NativeType() != LOCAL_GL_FLOAT) {                          \
                 return ErrorMessage(#name ": arg not an array");                  \
             }                                                                     \
-            WebGLFloatArray *wga = static_cast<WebGLFloatArray*>(value);          \
-            if (wga->NativeCount() % c != 0) {                                    \
-                return ErrorMessage(#name ": array wrong size %d, expected " #c, wga->NativeCount());     \
+            if (value->NativeCount() % c != 0) {                                  \
+                return ErrorMessage(#name ": array wrong size %d, expected " #c, value->NativeCount());     \
             }                                                                     \
             MakeContextCurrent();                                                 \
-            gl->f##glname(location, wga->NativeCount() / c, transpose, ( ptrType *)wga->NativePointer()); \
+            gl->f##glname(location, value->NativeCount() / c, transpose, ( ptrType *)value->NativePointer()); \
         } else {                                                                  \
             return ErrorMessage("Unhandled glTypeConst"); /* need compiler fail */\
         }                                                                         \
     }                                                                             \
     return NS_OK;                                                                 \
 }
 
 GL_SIMPLE_ARRAY_METHOD(Uniform1iv, Uniform1iv, 1, LOCAL_GL_INT, GLint)
@@ -2775,35 +2889,37 @@ WebGLContext::VertexAttribPointer(GLuint
         return ErrorMessage("glvertexattribpointer: must have GL_ARRAY_BUFFER binding!");
 
     if (index >= mAttribBuffers.Length())
         return ErrorMessage("glVertexAttribPointer: index out of range - %d >= %d", index, mAttribBuffers.Length());
 
     if (size < 1 || size > 4)
         return ErrorMessage("glVertexAttribPointer: invalid element size");
 
+    /* XXX make work with bufferSubData & heterogeneous types 
     if (type != mBoundArrayBuffer->GLType())
         return ErrorMessage("glVertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType());
+    */
 
     // XXX 0 stride?
     //if (stride < (GLuint) size)
     //    return ErrorMessage("glVertexAttribPointer: stride must be >= size!");
 
     WebGLVertexAttribData &vd = mAttribBuffers[index];
 
     vd.buf = mBoundArrayBuffer;
     vd.stride = stride;
     vd.size = size;
     vd.offset = offset;
 
     MakeContextCurrent();
 
     gl->fVertexAttribPointer(index, size, type, normalized,
-                             stride * mBoundArrayBuffer->ElementSize(),
-                             (void*) (offset * mBoundArrayBuffer->ElementSize()));
+                             stride,
+                             (void*) (offset));
 
     return NS_OK;
 }
 
 PRBool
 WebGLContext::ValidateGL()
 {
     // make sure that the opengl stuff that we need is supported
--- a/content/canvas/src/WebGLContextNotSupported.cpp
+++ b/content/canvas/src/WebGLContextNotSupported.cpp
@@ -44,8 +44,9 @@
 DUMMY(NS_NewCanvasRenderingContextWebGL, nsICanvasRenderingContextWebGL)
 DUMMY(NS_NewCanvasFloatArray, nsISupports)
 DUMMY(NS_NewCanvasByteArray, nsISupports)
 DUMMY(NS_NewCanvasUnsignedByteArray, nsISupports)
 DUMMY(NS_NewCanvasShortArray, nsISupports)
 DUMMY(NS_NewCanvasUnsignedShortArray, nsISupports)
 DUMMY(NS_NewCanvasIntArray, nsISupports)
 DUMMY(NS_NewCanvasUnsignedIntArray, nsISupports)
+DUMMY(NS_NewCanvasArrayBuffer, nsISupports)
--- a/content/canvas/src/localgl.h
+++ b/content/canvas/src/localgl.h
@@ -61,18 +61,18 @@ typedef unsigned char GLubyte;
 typedef unsigned short GLushort;
 typedef float GLfloat;
 typedef float GLclampf;
 typedef double GLdouble;
 typedef double GLclampd;
 typedef void GLvoid;
 
 typedef char GLchar;
-typedef ptrdiff_t GLsizeiptr;
-typedef ptrdiff_t GLintptr;
+typedef PRInt32 GLsizeiptr;
+typedef PRInt32 GLintptr;
 
 #ifndef GLAPIENTRY
 # ifdef WIN32
 #  define GLAPIENTRY APIENTRY
 #  define GLAPI
 # else
 #  define GLAPIENTRY
 #  define GLAPI
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1330,16 +1330,18 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(WebGLProgram, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(WebGLShader, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(WebGLFramebuffer, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(WebGLRenderbuffer, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(CanvasArrayBuffer, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CanvasFloatArray, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CanvasByteArray, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CanvasUnsignedByteArray, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CanvasShortArray, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -1391,16 +1393,17 @@ struct nsConstructorFuncMapData
 #define NS_DEFINE_CONSTRUCTOR_FUNC_DATA(_class, _func)                        \
   { eDOMClassInfo_##_class##_id, _func },
 
 static const nsConstructorFuncMapData kConstructorFuncMap[] =
 {
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Worker, nsDOMWorker::NewWorker)
 
   // WebGL Array Types
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(CanvasArrayBuffer, NS_NewCanvasArrayBuffer)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(CanvasFloatArray, NS_NewCanvasFloatArray)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(CanvasByteArray, NS_NewCanvasByteArray)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(CanvasUnsignedByteArray, NS_NewCanvasUnsignedByteArray)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(CanvasShortArray, NS_NewCanvasShortArray)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(CanvasUnsignedShortArray, NS_NewCanvasUnsignedShortArray)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(CanvasIntArray, NS_NewCanvasIntArray)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(CanvasUnsignedIntArray, NS_NewCanvasUnsignedIntArray)
 };
@@ -3717,16 +3720,20 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(WebGLFramebuffer, nsIWebGLFramebuffer)
     DOM_CLASSINFO_MAP_ENTRY(nsIWebGLFramebuffer)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(WebGLRenderbuffer, nsIWebGLRenderbuffer)
     DOM_CLASSINFO_MAP_ENTRY(nsIWebGLRenderbuffer)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(CanvasArrayBuffer, nsICanvasArrayBuffer)
+    DOM_CLASSINFO_MAP_ENTRY(nsICanvasArrayBuffer)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(CanvasFloatArray, nsICanvasFloatArray)
     DOM_CLASSINFO_MAP_ENTRY(nsICanvasFloatArray)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CanvasByteArray, nsICanvasByteArray)
     DOM_CLASSINFO_MAP_ENTRY(nsICanvasByteArray)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoID.h
+++ b/dom/base/nsDOMClassInfoID.h
@@ -468,16 +468,17 @@ enum nsDOMClassInfoID {
   eDOMClassInfo_WebGLBuffer_id,
   eDOMClassInfo_WebGLTexture_id,
   eDOMClassInfo_WebGLProgram_id,
   eDOMClassInfo_WebGLShader_id,
   eDOMClassInfo_WebGLFramebuffer_id,
   eDOMClassInfo_WebGLRenderbuffer_id,
 
   // WebGL Buffers
+  eDOMClassInfo_CanvasArrayBuffer_id,
   eDOMClassInfo_CanvasFloatArray_id,
   eDOMClassInfo_CanvasByteArray_id,
   eDOMClassInfo_CanvasUnsignedByteArray_id,
   eDOMClassInfo_CanvasShortArray_id,
   eDOMClassInfo_CanvasUnsignedShortArray_id,
   eDOMClassInfo_CanvasIntArray_id,
   eDOMClassInfo_CanvasUnsignedIntArray_id,
 
--- a/dom/interfaces/canvas/nsICanvasRenderingContextWebGL.idl
+++ b/dom/interfaces/canvas/nsICanvasRenderingContextWebGL.idl
@@ -54,67 +54,125 @@ typedef unsigned long  GLuint;
 typedef float          GLfloat;
 typedef float          GLclampf;
 typedef long           GLfixed;
 
 // XPIDL doesn't have a signed byte?
 //typedef signed octet GLbyte;
 
 //typedef unsigned long  GLintptr;
-//typedef unsigned long  GLsizeiptr;
+typedef long  GLsizeiptr;
 
+%{C++
+namespace mozilla {
+    class WebGLArrayBuffer;
+}
+%}
+[ptr] native WebGLArrayBufferPtr (mozilla::WebGLArrayBuffer);
 //
 // Array types
 //
+[scriptable, uuid(34b6cf8e-47da-458e-ab42-0451a3533ee5)]
+interface nsICanvasArrayBuffer : nsISupports
+{
+  readonly attribute unsigned long byteLength;
+
+  [noscript, notxpcom] WebGLArrayBufferPtr GetNativeArrayBuffer();
+  [noscript, notxpcom] voidPtr nativePointer();
+  [noscript, notxpcom] unsigned long nativeSize();
+};
 
 [scriptable, uuid(84ba4e98-8173-7c10-dca0-b5ba7809fcf3)]
 interface nsICanvasArray : nsISupports
 {
-  attribute unsigned long length;
+  readonly attribute nsICanvasArrayBuffer buffer;
+  readonly attribute unsigned long byteOffset;
+  readonly attribute unsigned long byteLength;
+  readonly attribute unsigned long length;
+
+  // XXX kill this.
+  unsigned long alignedSizeInBytes();
+
+  nsICanvasArray slice(in unsigned long offset, in unsigned long length);
 
   [noscript, notxpcom] unsigned long nativeType();
   [noscript, notxpcom] voidPtr nativePointer();
   [noscript, notxpcom] unsigned long nativeSize();
   [noscript, notxpcom] unsigned long nativeElementSize();
   [noscript, notxpcom] unsigned long nativeCount();
 };
 
 [scriptable, Uuid(0f6d0e7b-bcfc-9305-6a1d-a9653b5e8c80)]
 interface nsICanvasFloatArray : nsICanvasArray
 {
+  [IndexGetter] float get(in unsigned long index);
+  //[IndexSetter] void set(in unsigned long index, in float value);
+  //void set(in CanvasFloatArray array, [Optional] in unsigned long offset);
+  //void set(in sequence<float> array, [Optional] in unsigned long offset);
+  void set();
 };
 
 [scriptable, uuid(b29db7cf-fa58-435f-8d45-611cc50979ad)]
 interface nsICanvasByteArray : nsICanvasArray
 {
+  [IndexGetter] long get(in unsigned long index);
+  //[IndexSetter] void set(in unsigned long index, in long value);
+  //void set(in nsICanvasByteArray array, [Optional] in unsigned long offset);
+  //void set(in sequence<long> array, [Optional] in unsigned long offset);
+  void set();
 };
 
 [scriptable, uuid(3daa67fa-e743-2cbd-a212-805c2fc520cc)]
 interface nsICanvasUnsignedByteArray : nsICanvasArray
 {
+  [IndexGetter] unsigned long get(in unsigned long index);
+  //[IndexSetter] void set(in unsigned long index, in unsigned long value);
+  //void set(in CanvasUnsignedByteArray array, [Optional] in unsigned long offset);
+  //void set(in sequence<unsigned long> array, [Optional] in unsigned long offset);
+  void set();
 };
 
 [scriptable, uuid(a8a982e3-3977-7364-f012-c497a5ab7681)]
 interface nsICanvasShortArray : nsICanvasArray
 {
+  [IndexGetter] long get(in unsigned long index);
+  //[IndexSetter] void set(in unsigned long index, in long value);
+  //void set(in CanvasShortArray array, [Optional] in unsigned long offset);
+  //void set(in sequence<long> array, [Optional] in unsigned long offset);
+  void set();
 };
 
 [scriptable, uuid(8b9c67cc-c7be-a062-84b0-76a910a5c1e6)]
 interface nsICanvasUnsignedShortArray : nsICanvasArray
 {
+  [IndexGetter] unsigned long get(in unsigned long index);
+  //[IndexSetter] void set(in unsigned long index, in unsigned long value);
+  //void set(in CanvasUnsignedShortArray array, [Optional] in unsigned long offset);
+  //void set(in sequence<unsigned long> array, [Optional] in unsigned long offset);
+  void set();
 };
 
 [scriptable, uuid(b9b2e861-3a28-4311-993c-799e4f77dcba)]
 interface nsICanvasIntArray : nsICanvasArray
 {
+  [IndexGetter] long get(in unsigned long index);
+  //[IndexSetter] void set(in unsigned long index, in long value);
+  //void set(in CanvasIntArray array, [Optional] in unsigned long offset);
+  //void set(in sequence<long> array, [Optional] in unsigned long offset);
+  void set();
 };
 
 [scriptable, uuid(0d6ee3f8-71b6-460d-b05a-d579cc55edbe)]
 interface nsICanvasUnsignedIntArray : nsICanvasArray
 {
+  [IndexGetter] unsigned long get(in unsigned long index);
+  //[IndexSetter] void set(in unsigned long index, in unsigned long value);
+  //void set(in CanvasUnsignedIntArray array, [Optional] in unsigned long offset);
+  //void set(in sequence<unsigned long> array, [Optional] in unsigned long offset);
+  void set();
 };
 
 //
 // OpenGL object wrappers
 //
 
 [scriptable, uuid(3b43762a-8305-11de-98ab-000c29206271)]
 interface nsIWebGLTexture : nsISupports
@@ -619,36 +677,41 @@ interface nsICanvasRenderingContextWebGL
   readonly attribute nsIWebGLTexture currentTextureBinding2D;
   readonly attribute nsIWebGLTexture currentTextureBindingCubeMap;
   readonly attribute nsIWebGLProgram currentProgram;
 
   //
   //  METHODS
   //
   void present();
+  long sizeInBytes(in GLenum type);
 
   void activeTexture (in GLenum texture);
   void attachShader (in nsIWebGLProgram program, in nsIWebGLShader shader);
   void bindAttribLocation (in nsIWebGLProgram program, in GLuint index, in DOMString name);
   void bindBuffer (in GLenum target, in nsIWebGLBuffer buffer);
   void bindFramebuffer (in GLenum target, in nsIWebGLFramebuffer framebuffer);
   void bindRenderbuffer (in GLenum target, in nsIWebGLRenderbuffer renderbuffer);
   void bindTexture (in GLenum target, in nsIWebGLTexture texture);
   void blendColor (in GLclampf red, in GLclampf green, in GLclampf blue, in GLclampf alpha);
   void blendEquation (in GLenum mode);
   void blendEquationSeparate (in GLenum modeRGB, in GLenum modeAlpha);
   void blendFunc (in GLenum sfactor, in GLenum dfactor);
   void blendFuncSeparate (in GLenum srcRGB, in GLenum dstRGB, in GLenum srcAlpha, in GLenum dstAlpha);
 
   // Modified: void glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage);
   // void bufferData (in GLenum target, in GLsizei size, in GLenum usage);
-  void bufferData (in GLenum target, in nsICanvasArray data, in GLenum usage);
+  // void bufferData (in GLenum target, in nsICanvasArray data, in GLenum usage);
+  // void bufferData (in GLenum target, in nsICanvasArrayBuffer data, in GLenum usage);
+  void bufferData (in GLenum target);
 
   // Modified: void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
-  void bufferSubData (in GLenum target, in GLuint offset, in nsICanvasArray data);
+  // void bufferSubData (in GLenum target, in GLsizeiptr offset, in nsICanvasArray data);
+  // void bufferSubData (in GLenum target, in GLsizeiptr offset, in CanvasArrayBuffer data);
+  void bufferSubData (in GLenum target, in GLsizeiptr offset);
 
   GLenum checkFramebufferStatus (in GLenum target);
   void clear (in GLbitfield mask);
   void clearColor (in GLclampf red, in GLclampf green, in GLclampf blue, in GLclampf alpha);
   void clearDepth (in GLclampf depth);
   void clearStencil (in GLint s);
   void colorMask (in GLboolean red, in GLboolean green, in GLboolean blue, in GLboolean alpha);
   void compileShader (in nsIWebGLShader shader);
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -1072,16 +1072,21 @@ static const nsModuleComponentInfo gComp
   { "Canvas 2D Rendering Context",
     NS_CANVASRENDERINGCONTEXT2D_CID,
     "@mozilla.org/content/canvas-rendering-context;1?id=2d",
     CreateCanvasRenderingContext2D },
   { "Canvas WebGL Rendering Context",
     NS_CANVASRENDERINGCONTEXTWEBGL_CID,
     "@mozilla.org/content/canvas-rendering-context;1?id=moz-webgl",
     CreateCanvasRenderingContextWebGL },
+  { "Canvas WebGL Rendering Context",
+    NS_CANVASRENDERINGCONTEXTWEBGL_CID,
+    "@mozilla.org/content/canvas-rendering-context;1?id=experimental-webgl",
+    CreateCanvasRenderingContextWebGL },
+
 
   { "XML document encoder",
     NS_TEXT_ENCODER_CID,
     NS_DOC_ENCODER_CONTRACTID_BASE "text/xml",
     CreateTextEncoder },
 
   { "XML document encoder",
     NS_TEXT_ENCODER_CID,