Home | History | Annotate | Download | only in custom
      1 /*
      2  * Copyright (C) 2009 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions areV8ClassIndex::WEBGL
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 
     33 #if ENABLE(3D_CANVAS)
     34 
     35 #include "V8WebGLRenderingContext.h"
     36 
     37 #include "ExceptionCode.h"
     38 
     39 #include "NotImplemented.h"
     40 
     41 #include <wtf/FastMalloc.h>
     42 
     43 #include "V8Binding.h"
     44 #include "V8WebGLArray.h"
     45 #include "V8WebGLBuffer.h"
     46 #include "V8WebGLByteArray.h"
     47 #include "V8WebGLFloatArray.h"
     48 #include "V8WebGLFramebuffer.h"
     49 #include "V8WebGLIntArray.h"
     50 #include "V8WebGLProgram.h"
     51 #include "V8WebGLRenderbuffer.h"
     52 #include "V8WebGLShader.h"
     53 #include "V8WebGLShortArray.h"
     54 #include "V8WebGLTexture.h"
     55 #include "V8WebGLUniformLocation.h"
     56 #include "V8WebGLUnsignedByteArray.h"
     57 #include "V8WebGLUnsignedIntArray.h"
     58 #include "V8WebGLUnsignedShortArray.h"
     59 #include "V8HTMLCanvasElement.h"
     60 #include "V8HTMLImageElement.h"
     61 #include "V8HTMLVideoElement.h"
     62 #include "V8ImageData.h"
     63 #include "V8Proxy.h"
     64 #include "WebGLRenderingContext.h"
     65 
     66 namespace WebCore {
     67 
     68 // Allocates new storage via tryFastMalloc.
     69 // Returns NULL if array failed to convert for any reason.
     70 static float* jsArrayToFloatArray(v8::Handle<v8::Array> array, uint32_t len)
     71 {
     72     // Convert the data element-by-element.
     73     float* data;
     74     if (!tryFastMalloc(len * sizeof(float)).getValue(data))
     75         return 0;
     76     for (uint32_t i = 0; i < len; i++) {
     77         v8::Local<v8::Value> val = array->Get(v8::Integer::New(i));
     78         if (!val->IsNumber()) {
     79             fastFree(data);
     80             return 0;
     81         }
     82         data[i] = toFloat(val);
     83     }
     84     return data;
     85 }
     86 
     87 // Allocates new storage via tryFastMalloc.
     88 // Returns NULL if array failed to convert for any reason.
     89 static int* jsArrayToIntArray(v8::Handle<v8::Array> array, uint32_t len)
     90 {
     91     // Convert the data element-by-element.
     92     int* data;
     93     if (!tryFastMalloc(len * sizeof(int)).getValue(data))
     94         return 0;
     95     for (uint32_t i = 0; i < len; i++) {
     96         v8::Local<v8::Value> val = array->Get(v8::Integer::New(i));
     97         bool ok;
     98         int ival = toInt32(val, ok);
     99         if (!ok) {
    100             fastFree(data);
    101             return 0;
    102         }
    103         data[i] = ival;
    104     }
    105     return data;
    106 }
    107 
    108 v8::Handle<v8::Value> V8WebGLRenderingContext::bufferDataCallback(const v8::Arguments& args)
    109 {
    110     INC_STATS("DOM.WebGLRenderingContext.bufferData()");
    111 
    112     // Forms:
    113     // * bufferData(GLenum target, WebGLArray data, GLenum usage);
    114     //   - Sets the buffer's data from the given WebGLArray
    115     // * bufferData(GLenum target, GLsizeiptr size, GLenum usage);
    116     //   - Sets the size of the buffer to the given size in bytes
    117     if (args.Length() != 3) {
    118         V8Proxy::setDOMException(SYNTAX_ERR);
    119         return notHandledByInterceptor();
    120     }
    121 
    122     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    123     bool ok;
    124     int target = toInt32(args[0], ok);
    125     if (!ok) {
    126         V8Proxy::setDOMException(SYNTAX_ERR);
    127         return notHandledByInterceptor();
    128     }
    129     int usage = toInt32(args[2], ok);
    130     if (!ok) {
    131         V8Proxy::setDOMException(SYNTAX_ERR);
    132         return notHandledByInterceptor();
    133     }
    134     if (args[1]->IsInt32()) {
    135         int size = toInt32(args[1]);
    136         ExceptionCode exceptionCode;
    137         context->bufferData(target, size, usage, exceptionCode);
    138     } else if (V8WebGLArray::HasInstance(args[1])) {
    139         WebGLArray* array = V8WebGLArray::toNative(args[1]->ToObject());
    140         ExceptionCode exceptionCode;
    141         context->bufferData(target, array, usage, exceptionCode);
    142     } else {
    143         V8Proxy::setDOMException(SYNTAX_ERR);
    144         return notHandledByInterceptor();
    145     }
    146     return v8::Undefined();
    147 }
    148 
    149 v8::Handle<v8::Value> V8WebGLRenderingContext::bufferSubDataCallback(const v8::Arguments& args)
    150 {
    151     INC_STATS("DOM.WebGLRenderingContext.bufferSubData()");
    152 
    153     // Forms:
    154     // * bufferSubData(GLenum target, GLintptr offset, WebGLArray data);
    155     if (args.Length() != 3) {
    156         V8Proxy::setDOMException(SYNTAX_ERR);
    157         return notHandledByInterceptor();
    158     }
    159 
    160     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    161     bool ok;
    162     int target = toInt32(args[0], ok);
    163     if (!ok) {
    164         V8Proxy::setDOMException(SYNTAX_ERR);
    165         return notHandledByInterceptor();
    166     }
    167     int offset = toInt32(args[1], ok);
    168     if (!ok) {
    169         V8Proxy::setDOMException(SYNTAX_ERR);
    170         return notHandledByInterceptor();
    171     }
    172     if (!V8WebGLArray::HasInstance(args[2])) {
    173         V8Proxy::setDOMException(SYNTAX_ERR);
    174         return notHandledByInterceptor();
    175     }
    176     WebGLArray* array = V8WebGLArray::toNative(args[2]->ToObject());
    177     ExceptionCode exceptionCode;
    178     context->bufferSubData(target, offset, array, exceptionCode);
    179     return v8::Undefined();
    180 }
    181 
    182 static v8::Handle<v8::Value> toV8Object(const WebGLGetInfo& info)
    183 {
    184     switch (info.getType()) {
    185     case WebGLGetInfo::kTypeBool:
    186         return v8::Boolean::New(info.getBool());
    187     case WebGLGetInfo::kTypeFloat:
    188         return v8::Number::New(info.getFloat());
    189     case WebGLGetInfo::kTypeLong:
    190         return v8::Integer::New(info.getLong());
    191     case WebGLGetInfo::kTypeNull:
    192         return v8::Null();
    193     case WebGLGetInfo::kTypeString:
    194         return v8::String::New(fromWebCoreString(info.getString()), info.getString().length());
    195     case WebGLGetInfo::kTypeUnsignedLong:
    196         return v8::Integer::NewFromUnsigned(info.getUnsignedLong());
    197     case WebGLGetInfo::kTypeWebGLBuffer:
    198         return toV8(info.getWebGLBuffer());
    199     case WebGLGetInfo::kTypeWebGLFloatArray:
    200         return toV8(info.getWebGLFloatArray());
    201     case WebGLGetInfo::kTypeWebGLFramebuffer:
    202         return toV8(info.getWebGLFramebuffer());
    203     case WebGLGetInfo::kTypeWebGLIntArray:
    204         return toV8(info.getWebGLIntArray());
    205     // FIXME: implement WebGLObjectArray
    206     // case WebGLGetInfo::kTypeWebGLObjectArray:
    207     case WebGLGetInfo::kTypeWebGLProgram:
    208         return toV8(info.getWebGLProgram());
    209     case WebGLGetInfo::kTypeWebGLRenderbuffer:
    210         return toV8(info.getWebGLRenderbuffer());
    211     case WebGLGetInfo::kTypeWebGLTexture:
    212         return toV8(info.getWebGLTexture());
    213     case WebGLGetInfo::kTypeWebGLUnsignedByteArray:
    214         return toV8(info.getWebGLUnsignedByteArray());
    215     default:
    216         notImplemented();
    217         return v8::Undefined();
    218     }
    219 }
    220 
    221 enum ObjectType {
    222     kBuffer, kRenderbuffer, kTexture, kVertexAttrib
    223 };
    224 
    225 static v8::Handle<v8::Value> getObjectParameter(const v8::Arguments& args, ObjectType objectType)
    226 {
    227     if (args.Length() != 2) {
    228         V8Proxy::setDOMException(SYNTAX_ERR);
    229         return notHandledByInterceptor();
    230     }
    231 
    232     ExceptionCode ec = 0;
    233     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    234     bool ok;
    235     unsigned target = toInt32(args[0], ok);
    236     if (!ok) {
    237         V8Proxy::setDOMException(SYNTAX_ERR);
    238         return notHandledByInterceptor();
    239     }
    240     unsigned pname = toInt32(args[1], ok);
    241     if (!ok) {
    242         V8Proxy::setDOMException(SYNTAX_ERR);
    243         return notHandledByInterceptor();
    244     }
    245     WebGLGetInfo info;
    246     switch (objectType) {
    247     case kBuffer:
    248         info = context->getBufferParameter(target, pname, ec);
    249         break;
    250     case kRenderbuffer:
    251         info = context->getRenderbufferParameter(target, pname, ec);
    252         break;
    253     case kTexture:
    254         info = context->getTexParameter(target, pname, ec);
    255         break;
    256     case kVertexAttrib:
    257         // target => index
    258         info = context->getVertexAttrib(target, pname, ec);
    259         break;
    260     default:
    261         notImplemented();
    262         break;
    263     }
    264     if (ec) {
    265         V8Proxy::setDOMException(ec);
    266         return v8::Undefined();
    267     }
    268     return toV8Object(info);
    269 }
    270 
    271 static WebGLUniformLocation* toWebGLUniformLocation(v8::Handle<v8::Value> value, bool& ok)
    272 {
    273     ok = false;
    274     WebGLUniformLocation* location = 0;
    275     if (V8WebGLUniformLocation::HasInstance(value)) {
    276         location = V8WebGLUniformLocation::toNative(value->ToObject());
    277         ok = true;
    278     }
    279     return location;
    280 }
    281 
    282 enum WhichProgramCall {
    283     kProgramParameter, kUniform
    284 };
    285 
    286 v8::Handle<v8::Value> V8WebGLRenderingContext::getBufferParameterCallback(const v8::Arguments& args)
    287 {
    288     INC_STATS("DOM.WebGLRenderingContext.getBufferParameter()");
    289     return getObjectParameter(args, kBuffer);
    290 }
    291 
    292 v8::Handle<v8::Value> V8WebGLRenderingContext::getFramebufferAttachmentParameterCallback(const v8::Arguments& args)
    293 {
    294     INC_STATS("DOM.WebGLRenderingContext.getFramebufferAttachmentParameter()");
    295 
    296     if (args.Length() != 3) {
    297         V8Proxy::setDOMException(SYNTAX_ERR);
    298         return notHandledByInterceptor();
    299     }
    300 
    301     ExceptionCode ec = 0;
    302     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    303     bool ok;
    304     unsigned target = toInt32(args[0], ok);
    305     if (!ok) {
    306         V8Proxy::setDOMException(SYNTAX_ERR);
    307         return notHandledByInterceptor();
    308     }
    309     unsigned attachment = toInt32(args[1], ok);
    310     if (!ok) {
    311         V8Proxy::setDOMException(SYNTAX_ERR);
    312         return notHandledByInterceptor();
    313     }
    314     unsigned pname = toInt32(args[2], ok);
    315     if (!ok) {
    316         V8Proxy::setDOMException(SYNTAX_ERR);
    317         return notHandledByInterceptor();
    318     }
    319     WebGLGetInfo info = context->getFramebufferAttachmentParameter(target, attachment, pname, ec);
    320     if (ec) {
    321         V8Proxy::setDOMException(ec);
    322         return v8::Undefined();
    323     }
    324     return toV8Object(info);
    325 }
    326 
    327 v8::Handle<v8::Value> V8WebGLRenderingContext::getParameterCallback(const v8::Arguments& args)
    328 {
    329     INC_STATS("DOM.WebGLRenderingContext.getParameter()");
    330 
    331     if (args.Length() != 1) {
    332         V8Proxy::setDOMException(SYNTAX_ERR);
    333         return notHandledByInterceptor();
    334     }
    335 
    336     ExceptionCode ec = 0;
    337     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    338     bool ok;
    339     unsigned pname = toInt32(args[0], ok);
    340     if (!ok) {
    341         V8Proxy::setDOMException(SYNTAX_ERR);
    342         return notHandledByInterceptor();
    343     }
    344     WebGLGetInfo info = context->getParameter(pname, ec);
    345     if (ec) {
    346         V8Proxy::setDOMException(ec);
    347         return v8::Undefined();
    348     }
    349     return toV8Object(info);
    350 }
    351 
    352 v8::Handle<v8::Value> V8WebGLRenderingContext::getProgramParameterCallback(const v8::Arguments& args)
    353 {
    354     INC_STATS("DOM.WebGLRenderingContext.getProgramParameter()");
    355 
    356     if (args.Length() != 2) {
    357         V8Proxy::setDOMException(SYNTAX_ERR);
    358         return notHandledByInterceptor();
    359     }
    360 
    361     ExceptionCode ec = 0;
    362     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    363     WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
    364     bool ok;
    365     unsigned pname = toInt32(args[1], ok);
    366     if (!ok) {
    367         V8Proxy::setDOMException(SYNTAX_ERR);
    368         return notHandledByInterceptor();
    369     }
    370     WebGLGetInfo info = context->getProgramParameter(program, pname, ec);
    371     if (ec) {
    372         V8Proxy::setDOMException(ec);
    373         return v8::Undefined();
    374     }
    375     return toV8Object(info);
    376 }
    377 
    378 v8::Handle<v8::Value> V8WebGLRenderingContext::getRenderbufferParameterCallback(const v8::Arguments& args)
    379 {
    380     INC_STATS("DOM.WebGLRenderingContext.getRenderbufferParameter()");
    381     return getObjectParameter(args, kRenderbuffer);
    382 }
    383 
    384 v8::Handle<v8::Value> V8WebGLRenderingContext::getShaderParameterCallback(const v8::Arguments& args)
    385 {
    386     INC_STATS("DOM.WebGLRenderingContext.getShaderParameter()");
    387 
    388     if (args.Length() != 2) {
    389         V8Proxy::setDOMException(SYNTAX_ERR);
    390         return notHandledByInterceptor();
    391     }
    392 
    393     ExceptionCode ec = 0;
    394     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    395     WebGLShader* shader = V8WebGLShader::HasInstance(args[0]) ? V8WebGLShader::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
    396     bool ok;
    397     unsigned pname = toInt32(args[1], ok);
    398     if (!ok) {
    399         V8Proxy::setDOMException(SYNTAX_ERR);
    400         return notHandledByInterceptor();
    401     }
    402     WebGLGetInfo info = context->getShaderParameter(shader, pname, ec);
    403     if (ec) {
    404         V8Proxy::setDOMException(ec);
    405         return v8::Undefined();
    406     }
    407     return toV8Object(info);
    408 }
    409 
    410 v8::Handle<v8::Value> V8WebGLRenderingContext::getTexParameterCallback(const v8::Arguments& args)
    411 {
    412     INC_STATS("DOM.WebGLRenderingContext.getTexParameter()");
    413     return getObjectParameter(args, kTexture);
    414 }
    415 
    416 v8::Handle<v8::Value> V8WebGLRenderingContext::getUniformCallback(const v8::Arguments& args)
    417 {
    418     INC_STATS("DOM.WebGLRenderingContext.getUniform()");
    419 
    420     if (args.Length() != 2) {
    421         V8Proxy::setDOMException(SYNTAX_ERR);
    422         return notHandledByInterceptor();
    423     }
    424 
    425     ExceptionCode ec = 0;
    426     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    427     WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
    428 
    429     bool ok = false;
    430     WebGLUniformLocation* location = toWebGLUniformLocation(args[1], ok);
    431 
    432     if (!ok) {
    433         V8Proxy::setDOMException(SYNTAX_ERR);
    434         return notHandledByInterceptor();
    435     }
    436     WebGLGetInfo info = context->getUniform(program, location, ec);
    437     if (ec) {
    438         V8Proxy::setDOMException(ec);
    439         return v8::Undefined();
    440     }
    441     return toV8Object(info);
    442 }
    443 
    444 v8::Handle<v8::Value> V8WebGLRenderingContext::getVertexAttribCallback(const v8::Arguments& args)
    445 {
    446     INC_STATS("DOM.WebGLRenderingContext.getVertexAttrib()");
    447     return getObjectParameter(args, kVertexAttrib);
    448 }
    449 
    450 v8::Handle<v8::Value> V8WebGLRenderingContext::texImage2DCallback(const v8::Arguments& args)
    451 {
    452     INC_STATS("DOM.WebGLRenderingContext.texImage2D()");
    453 
    454     // Currently supported forms:
    455     // * void texImage2D(in GLenum target, in GLint level,
    456     //                   in GLint internalformat,
    457     //                   in GLsizei width, in GLsizei height, in GLint border,
    458     //                   in GLenum format, in GLenum type, in WebGLArray pixels);
    459     // * void texImage2D(in GLenum target, in GLint level, in ImageData pixels,
    460     //                   [Optional] in GLboolean flipY, [Optional] in GLboolean premulitplyAlpha);
    461     // * void texImage2D(in GLenum target, in GLint level, in HTMLImageElement image,
    462     //                   [Optional] in GLboolean flipY, [Optional] in GLboolean premultiplyAlpha);
    463     // * void texImage2D(in GLenum target, in GLint level, in HTMLCanvasElement image,
    464     //                   [Optional] in GLboolean flipY, [Optional] in GLboolean premultiplyAlpha);
    465     // * void texImage2D(in GLenum target, in GLint level, in HTMLVideoElement image,
    466     //                   [Optional] in GLboolean flipY, [Optional] in GLboolean premultiplyAlpha);
    467     if (args.Length() != 3 &&
    468         args.Length() != 4 &&
    469         args.Length() != 5 &&
    470         args.Length() != 9) {
    471         V8Proxy::setDOMException(SYNTAX_ERR);
    472         return notHandledByInterceptor();
    473     }
    474 
    475     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    476     bool ok;
    477     int target = toInt32(args[0], ok);
    478     if (!ok) {
    479         V8Proxy::setDOMException(SYNTAX_ERR);
    480         return notHandledByInterceptor();
    481     }
    482     int level = toInt32(args[1], ok);
    483     if (!ok) {
    484         V8Proxy::setDOMException(SYNTAX_ERR);
    485         return notHandledByInterceptor();
    486     }
    487 
    488     ExceptionCode ec = 0;
    489     if (args.Length() == 3 ||
    490         args.Length() == 4 ||
    491         args.Length() == 5) {
    492         bool flipY = false;
    493         bool premultiplyAlpha = false;
    494         if (args.Length() >= 4)
    495             flipY = args[3]->BooleanValue();
    496         if (args.Length() >= 5)
    497             premultiplyAlpha = args[4]->BooleanValue();
    498 
    499         v8::Handle<v8::Value> arg = args[2];
    500         if (V8HTMLImageElement::HasInstance(arg)) {
    501             HTMLImageElement* element = V8HTMLImageElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    502             context->texImage2D(target, level, element, flipY, premultiplyAlpha, ec);
    503         } else if (V8HTMLCanvasElement::HasInstance(arg)) {
    504             HTMLCanvasElement* element = V8HTMLCanvasElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    505             context->texImage2D(target, level, element, flipY, premultiplyAlpha, ec);
    506         } else if(V8ImageData::HasInstance(arg)) {
    507             ImageData* imageElement = V8ImageData::toNative(v8::Handle<v8::Object>::Cast(arg));
    508             context->texImage2D(target, level, imageElement, flipY, premultiplyAlpha, ec);
    509         } else if (V8HTMLVideoElement::HasInstance(arg)) {
    510             HTMLVideoElement* element = V8HTMLVideoElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    511             context->texImage2D(target, level, element, flipY, premultiplyAlpha, ec);
    512         }
    513         else {
    514             // FIXME: consider different / better exception type.
    515             V8Proxy::setDOMException(SYNTAX_ERR);
    516             return notHandledByInterceptor();
    517         }
    518         // Fall through
    519     } else if (args.Length() == 9) {
    520         int internalformat = toInt32(args[2], ok);
    521         if (!ok) {
    522             V8Proxy::setDOMException(SYNTAX_ERR);
    523             return notHandledByInterceptor();
    524         }
    525         int width = toInt32(args[3], ok);
    526         if (!ok) {
    527             V8Proxy::setDOMException(SYNTAX_ERR);
    528             return notHandledByInterceptor();
    529         }
    530         int height = toInt32(args[4], ok);
    531         if (!ok) {
    532             V8Proxy::setDOMException(SYNTAX_ERR);
    533             return notHandledByInterceptor();
    534         }
    535         int border = toInt32(args[5], ok);
    536         if (!ok) {
    537             V8Proxy::setDOMException(SYNTAX_ERR);
    538             return notHandledByInterceptor();
    539         }
    540         int format = toInt32(args[6], ok);
    541         if (!ok) {
    542             V8Proxy::setDOMException(SYNTAX_ERR);
    543             return notHandledByInterceptor();
    544         }
    545         int type = toInt32(args[7], ok);
    546         if (!ok) {
    547             V8Proxy::setDOMException(SYNTAX_ERR);
    548             return notHandledByInterceptor();
    549         }
    550         v8::Handle<v8::Value> arg = args[8];
    551         if (!arg->IsObject())
    552         // Assume that the user is passing null for texture
    553             context->texImage2D(target,
    554                                 level,
    555                                 internalformat,
    556                                 width,
    557                                 height,
    558                                 border,
    559                                 format,
    560                                 type,
    561                                 0,
    562                                 ec);
    563      else if (V8WebGLArray::HasInstance(arg)) {
    564             WebGLArray* array = V8WebGLArray::toNative(arg->ToObject());
    565             context->texImage2D(target,
    566                                 level,
    567                                 internalformat,
    568                                 width,
    569                                 height,
    570                                 border,
    571                                 format,
    572                                 type,
    573                                 array,
    574                                 ec);
    575             // Fall through
    576         } else {
    577             V8Proxy::setDOMException(SYNTAX_ERR);
    578             return notHandledByInterceptor();
    579         }
    580     } else {
    581         ASSERT_NOT_REACHED();
    582         V8Proxy::setDOMException(SYNTAX_ERR);
    583         return notHandledByInterceptor();
    584     }
    585     if (ec) {
    586         V8Proxy::setDOMException(ec);
    587         return v8::Handle<v8::Value>();
    588     }
    589     return v8::Undefined();
    590 }
    591 
    592 v8::Handle<v8::Value> V8WebGLRenderingContext::texSubImage2DCallback(const v8::Arguments& args)
    593 {
    594     INC_STATS("DOM.WebGLRenderingContext.texSubImage2D()");
    595 
    596     // Currently supported forms:
    597     // * void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset,
    598     //                      in GLsizei width, in GLsizei height,
    599     //                      in GLenum format, in GLenum type, in WebGLArray pixels);
    600     // * void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset,
    601     //                      in ImageData pixels, [Optional] GLboolean flipY, [Optional] in premultiplyAlpha);
    602     // * void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset,
    603     //                      in HTMLImageElement image, [Optional] GLboolean flipY, [Optional] in premultiplyAlpha);
    604     // * void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset,
    605     //                      in HTMLCanvasElement canvas, [Optional] GLboolean flipY, [Optional] in premultiplyAlpha);
    606     // * void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset,
    607     //                      in HTMLVideoElement video, [Optional] GLboolean flipY, [Optional] in premultiplyAlpha);
    608 
    609     if (args.Length() != 5 &&
    610         args.Length() != 6 &&
    611         args.Length() != 7 &&
    612         args.Length() != 9) {
    613         V8Proxy::setDOMException(SYNTAX_ERR);
    614         return notHandledByInterceptor();
    615     }
    616 
    617     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    618     bool ok;
    619     int target = toInt32(args[0], ok);
    620     if (!ok) {
    621         V8Proxy::setDOMException(SYNTAX_ERR);
    622         return notHandledByInterceptor();
    623     }
    624     int level = toInt32(args[1], ok);
    625     if (!ok) {
    626         V8Proxy::setDOMException(SYNTAX_ERR);
    627         return notHandledByInterceptor();
    628     }
    629     int xoff = toInt32(args[2], ok);
    630     if (!ok) {
    631         V8Proxy::setDOMException(SYNTAX_ERR);
    632         return notHandledByInterceptor();
    633     }
    634     int yoff = toInt32(args[3], ok);
    635     if (!ok) {
    636         V8Proxy::setDOMException(SYNTAX_ERR);
    637         return notHandledByInterceptor();
    638     }
    639 
    640     ExceptionCode ec = 0;
    641     if (args.Length() == 5 ||
    642         args.Length() == 6 ||
    643         args.Length() == 7) {
    644         bool flipY = false;
    645         bool premultiplyAlpha = false;
    646         if (args.Length() >= 6)
    647             flipY = args[5]->BooleanValue();
    648         if (args.Length() >= 7)
    649             premultiplyAlpha = args[6]->BooleanValue();
    650 
    651         v8::Handle<v8::Value> arg = args[4];
    652         if (V8HTMLImageElement::HasInstance(arg)) {
    653             HTMLImageElement* element = V8HTMLImageElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    654             context->texSubImage2D(target, level, xoff, yoff, element, flipY, premultiplyAlpha, ec);
    655         } else if (V8HTMLCanvasElement::HasInstance(arg)) {
    656             HTMLCanvasElement* element = V8HTMLCanvasElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    657             context->texSubImage2D(target, level, xoff, yoff, element, flipY, premultiplyAlpha, ec);
    658         } else if(V8ImageData::HasInstance(arg)) {
    659             ImageData* imageElement = V8ImageData::toNative(v8::Handle<v8::Object>::Cast(arg));
    660             context->texSubImage2D(target, level, xoff, yoff, imageElement, flipY, premultiplyAlpha, ec);
    661         } else if (V8HTMLVideoElement::HasInstance(arg)) {
    662             HTMLVideoElement* element = V8HTMLVideoElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    663             context->texSubImage2D(target, level, xoff, yoff, element, flipY, premultiplyAlpha, ec);
    664         }
    665         else {
    666             // FIXME: consider different / better exception type.
    667             V8Proxy::setDOMException(SYNTAX_ERR);
    668             return notHandledByInterceptor();
    669         }
    670         // Fall through
    671     } else if (args.Length() == 9) {
    672         int width = toInt32(args[4], ok);
    673         if (!ok) {
    674             V8Proxy::setDOMException(SYNTAX_ERR);
    675             return notHandledByInterceptor();
    676         }
    677         int height = toInt32(args[5], ok);
    678         if (!ok) {
    679             V8Proxy::setDOMException(SYNTAX_ERR);
    680             return notHandledByInterceptor();
    681         }
    682         int format = toInt32(args[6], ok);
    683         if (!ok) {
    684             V8Proxy::setDOMException(SYNTAX_ERR);
    685             return notHandledByInterceptor();
    686         }
    687         int type = toInt32(args[7], ok);
    688         if (!ok) {
    689             V8Proxy::setDOMException(SYNTAX_ERR);
    690             return notHandledByInterceptor();
    691         }
    692         v8::Handle<v8::Value> arg = args[8];
    693         if (!arg->IsObject())
    694         // Assume that the user is passing null for texture
    695             context->texSubImage2D(target,
    696                                    level,
    697                                    xoff,
    698                                    yoff,
    699                                    width,
    700                                    height,
    701                                    format,
    702                                    type,
    703                                    0,
    704                                    ec);
    705      else if (V8WebGLArray::HasInstance(arg)) {
    706             WebGLArray* array = V8WebGLArray::toNative(arg->ToObject());
    707             context->texSubImage2D(target,
    708                                    level,
    709                                    xoff,
    710                                    yoff,
    711                                    width,
    712                                    height,
    713                                    format,
    714                                    type,
    715                                    array,
    716                                    ec);
    717             // Fall through
    718         } else {
    719             V8Proxy::setDOMException(SYNTAX_ERR);
    720             return notHandledByInterceptor();
    721         }
    722     } else {
    723         ASSERT_NOT_REACHED();
    724         V8Proxy::setDOMException(SYNTAX_ERR);
    725         return notHandledByInterceptor();
    726     }
    727     if (ec) {
    728         V8Proxy::setDOMException(ec);
    729         return v8::Handle<v8::Value>();
    730     }
    731     return v8::Undefined();
    732 }
    733 
    734 enum FunctionToCall {
    735     kUniform1v, kUniform2v, kUniform3v, kUniform4v,
    736     kVertexAttrib1v, kVertexAttrib2v, kVertexAttrib3v, kVertexAttrib4v
    737 };
    738 
    739 bool isFunctionToCallForAttribute(FunctionToCall functionToCall)
    740 {
    741     switch (functionToCall) {
    742     case kVertexAttrib1v:
    743     case kVertexAttrib2v:
    744     case kVertexAttrib3v:
    745     case kVertexAttrib4v:
    746         return true;
    747     default:
    748         break;
    749     }
    750     return false;
    751 }
    752 
    753 static v8::Handle<v8::Value> vertexAttribAndUniformHelperf(const v8::Arguments& args,
    754                                                            FunctionToCall functionToCall) {
    755     // Forms:
    756     // * glUniform1fv(WebGLUniformLocation location, Array data);
    757     // * glUniform1fv(WebGLUniformLocation location, WebGLFloatArray data);
    758     // * glUniform2fv(WebGLUniformLocation location, Array data);
    759     // * glUniform2fv(WebGLUniformLocation location, WebGLFloatArray data);
    760     // * glUniform3fv(WebGLUniformLocation location, Array data);
    761     // * glUniform3fv(WebGLUniformLocation location, WebGLFloatArray data);
    762     // * glUniform4fv(WebGLUniformLocation location, Array data);
    763     // * glUniform4fv(WebGLUniformLocation location, WebGLFloatArray data);
    764     // * glVertexAttrib1fv(GLint index, Array data);
    765     // * glVertexAttrib1fv(GLint index, WebGLFloatArray data);
    766     // * glVertexAttrib2fv(GLint index, Array data);
    767     // * glVertexAttrib2fv(GLint index, WebGLFloatArray data);
    768     // * glVertexAttrib3fv(GLint index, Array data);
    769     // * glVertexAttrib3fv(GLint index, WebGLFloatArray data);
    770     // * glVertexAttrib4fv(GLint index, Array data);
    771     // * glVertexAttrib4fv(GLint index, WebGLFloatArray data);
    772 
    773     if (args.Length() != 2) {
    774         V8Proxy::setDOMException(SYNTAX_ERR);
    775         return notHandledByInterceptor();
    776     }
    777 
    778     bool ok = false;
    779     int index = -1;
    780     WebGLUniformLocation* location = 0;
    781 
    782     if (isFunctionToCallForAttribute(functionToCall))
    783         index = toInt32(args[0], ok);
    784     else
    785         location = toWebGLUniformLocation(args[0], ok);
    786 
    787     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    788 
    789     if (!ok) {
    790         V8Proxy::setDOMException(SYNTAX_ERR);
    791         return notHandledByInterceptor();
    792     }
    793     if (V8WebGLFloatArray::HasInstance(args[1])) {
    794         WebGLFloatArray* array = V8WebGLFloatArray::toNative(args[1]->ToObject());
    795         ASSERT(array != NULL);
    796         ExceptionCode ec = 0;
    797         switch (functionToCall) {
    798             case kUniform1v: context->uniform1fv(location, array, ec); break;
    799             case kUniform2v: context->uniform2fv(location, array, ec); break;
    800             case kUniform3v: context->uniform3fv(location, array, ec); break;
    801             case kUniform4v: context->uniform4fv(location, array, ec); break;
    802             case kVertexAttrib1v: context->vertexAttrib1fv(index, array); break;
    803             case kVertexAttrib2v: context->vertexAttrib2fv(index, array); break;
    804             case kVertexAttrib3v: context->vertexAttrib3fv(index, array); break;
    805             case kVertexAttrib4v: context->vertexAttrib4fv(index, array); break;
    806             default: ASSERT_NOT_REACHED(); break;
    807         }
    808         if (ec)
    809             V8Proxy::setDOMException(ec);
    810         return v8::Undefined();
    811     }
    812 
    813     v8::Handle<v8::Array> array =
    814       v8::Local<v8::Array>::Cast(args[1]);
    815     if (array.IsEmpty()) {
    816         V8Proxy::setDOMException(SYNTAX_ERR);
    817         return notHandledByInterceptor();
    818     }
    819     uint32_t len = array->Length();
    820     float* data = jsArrayToFloatArray(array, len);
    821     if (!data) {
    822         // FIXME: consider different / better exception type.
    823         V8Proxy::setDOMException(SYNTAX_ERR);
    824         return notHandledByInterceptor();
    825     }
    826     ExceptionCode ec = 0;
    827     switch (functionToCall) {
    828         case kUniform1v: context->uniform1fv(location, data, len, ec); break;
    829         case kUniform2v: context->uniform2fv(location, data, len, ec); break;
    830         case kUniform3v: context->uniform3fv(location, data, len, ec); break;
    831         case kUniform4v: context->uniform4fv(location, data, len, ec); break;
    832         case kVertexAttrib1v: context->vertexAttrib1fv(index, data, len); break;
    833         case kVertexAttrib2v: context->vertexAttrib2fv(index, data, len); break;
    834         case kVertexAttrib3v: context->vertexAttrib3fv(index, data, len); break;
    835         case kVertexAttrib4v: context->vertexAttrib4fv(index, data, len); break;
    836         default: ASSERT_NOT_REACHED(); break;
    837     }
    838     fastFree(data);
    839     if (ec)
    840         V8Proxy::setDOMException(ec);
    841     return v8::Undefined();
    842 }
    843 
    844 static v8::Handle<v8::Value> uniformHelperi(const v8::Arguments& args,
    845                                             FunctionToCall functionToCall) {
    846     // Forms:
    847     // * glUniform1iv(GLUniformLocation location, Array data);
    848     // * glUniform1iv(GLUniformLocation location, WebGLIntArray data);
    849     // * glUniform2iv(GLUniformLocation location, Array data);
    850     // * glUniform2iv(GLUniformLocation location, WebGLIntArray data);
    851     // * glUniform3iv(GLUniformLocation location, Array data);
    852     // * glUniform3iv(GLUniformLocation location, WebGLIntArray data);
    853     // * glUniform4iv(GLUniformLocation location, Array data);
    854     // * glUniform4iv(GLUniformLocation location, WebGLIntArray data);
    855 
    856     if (args.Length() != 2) {
    857         V8Proxy::setDOMException(SYNTAX_ERR);
    858         return notHandledByInterceptor();
    859     }
    860 
    861     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    862     bool ok = false;
    863     WebGLUniformLocation* location = toWebGLUniformLocation(args[0], ok);
    864 
    865     if (!ok) {
    866         V8Proxy::setDOMException(SYNTAX_ERR);
    867         return notHandledByInterceptor();
    868     }
    869     if (V8WebGLIntArray::HasInstance(args[1])) {
    870         WebGLIntArray* array = V8WebGLIntArray::toNative(args[1]->ToObject());
    871         ASSERT(array != NULL);
    872         ExceptionCode ec = 0;
    873         switch (functionToCall) {
    874             case kUniform1v: context->uniform1iv(location, array, ec); break;
    875             case kUniform2v: context->uniform2iv(location, array, ec); break;
    876             case kUniform3v: context->uniform3iv(location, array, ec); break;
    877             case kUniform4v: context->uniform4iv(location, array, ec); break;
    878             default: ASSERT_NOT_REACHED(); break;
    879         }
    880         if (ec)
    881             V8Proxy::setDOMException(ec);
    882         return v8::Undefined();
    883     }
    884 
    885     v8::Handle<v8::Array> array =
    886       v8::Local<v8::Array>::Cast(args[1]);
    887     if (array.IsEmpty()) {
    888         V8Proxy::setDOMException(SYNTAX_ERR);
    889         return notHandledByInterceptor();
    890     }
    891     uint32_t len = array->Length();
    892     int* data = jsArrayToIntArray(array, len);
    893     if (!data) {
    894         // FIXME: consider different / better exception type.
    895         V8Proxy::setDOMException(SYNTAX_ERR);
    896         return notHandledByInterceptor();
    897     }
    898     ExceptionCode ec = 0;
    899     switch (functionToCall) {
    900         case kUniform1v: context->uniform1iv(location, data, len, ec); break;
    901         case kUniform2v: context->uniform2iv(location, data, len, ec); break;
    902         case kUniform3v: context->uniform3iv(location, data, len, ec); break;
    903         case kUniform4v: context->uniform4iv(location, data, len, ec); break;
    904         default: ASSERT_NOT_REACHED(); break;
    905     }
    906     fastFree(data);
    907     if (ec)
    908         V8Proxy::setDOMException(ec);
    909     return v8::Undefined();
    910 }
    911 
    912 v8::Handle<v8::Value> V8WebGLRenderingContext::uniform1fvCallback(const v8::Arguments& args)
    913 {
    914     INC_STATS("DOM.WebGLRenderingContext.uniform1fv()");
    915     return vertexAttribAndUniformHelperf(args, kUniform1v);
    916 }
    917 
    918 v8::Handle<v8::Value> V8WebGLRenderingContext::uniform1ivCallback(const v8::Arguments& args)
    919 {
    920     INC_STATS("DOM.WebGLRenderingContext.uniform1iv()");
    921     return uniformHelperi(args, kUniform1v);
    922 }
    923 
    924 v8::Handle<v8::Value> V8WebGLRenderingContext::uniform2fvCallback(const v8::Arguments& args)
    925 {
    926     INC_STATS("DOM.WebGLRenderingContext.uniform2fv()");
    927     return vertexAttribAndUniformHelperf(args, kUniform2v);
    928 }
    929 
    930 v8::Handle<v8::Value> V8WebGLRenderingContext::uniform2ivCallback(const v8::Arguments& args)
    931 {
    932     INC_STATS("DOM.WebGLRenderingContext.uniform2iv()");
    933     return uniformHelperi(args, kUniform2v);
    934 }
    935 
    936 v8::Handle<v8::Value> V8WebGLRenderingContext::uniform3fvCallback(const v8::Arguments& args)
    937 {
    938     INC_STATS("DOM.WebGLRenderingContext.uniform3fv()");
    939     return vertexAttribAndUniformHelperf(args, kUniform3v);
    940 }
    941 
    942 v8::Handle<v8::Value> V8WebGLRenderingContext::uniform3ivCallback(const v8::Arguments& args)
    943 {
    944     INC_STATS("DOM.WebGLRenderingContext.uniform3iv()");
    945     return uniformHelperi(args, kUniform3v);
    946 }
    947 
    948 v8::Handle<v8::Value> V8WebGLRenderingContext::uniform4fvCallback(const v8::Arguments& args)
    949 {
    950     INC_STATS("DOM.WebGLRenderingContext.uniform4fv()");
    951     return vertexAttribAndUniformHelperf(args, kUniform4v);
    952 }
    953 
    954 v8::Handle<v8::Value> V8WebGLRenderingContext::uniform4ivCallback(const v8::Arguments& args)
    955 {
    956     INC_STATS("DOM.WebGLRenderingContext.uniform4iv()");
    957     return uniformHelperi(args, kUniform4v);
    958 }
    959 
    960 static v8::Handle<v8::Value> uniformMatrixHelper(const v8::Arguments& args,
    961                                                  int matrixSize)
    962 {
    963     // Forms:
    964     // * glUniformMatrix2fv(GLint location, GLboolean transpose, Array data);
    965     // * glUniformMatrix2fv(GLint location, GLboolean transpose, WebGLFloatArray data);
    966     // * glUniformMatrix3fv(GLint location, GLboolean transpose, Array data);
    967     // * glUniformMatrix3fv(GLint location, GLboolean transpose, WebGLFloatArray data);
    968     // * glUniformMatrix4fv(GLint location, GLboolean transpose, Array data);
    969     // * glUniformMatrix4fv(GLint location, GLboolean transpose, WebGLFloatArray data);
    970     //
    971     // FIXME: need to change to accept WebGLFloatArray as well.
    972     if (args.Length() != 3) {
    973         V8Proxy::setDOMException(SYNTAX_ERR);
    974         return notHandledByInterceptor();
    975     }
    976 
    977     WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
    978 
    979     bool ok = false;
    980     WebGLUniformLocation* location = toWebGLUniformLocation(args[0], ok);
    981 
    982     if (!ok) {
    983         V8Proxy::setDOMException(SYNTAX_ERR);
    984         return notHandledByInterceptor();
    985     }
    986     bool transpose = args[1]->BooleanValue();
    987     if (V8WebGLFloatArray::HasInstance(args[2])) {
    988         WebGLFloatArray* array = V8WebGLFloatArray::toNative(args[2]->ToObject());
    989         ASSERT(array != NULL);
    990         ExceptionCode ec = 0;
    991         switch (matrixSize) {
    992             case 2: context->uniformMatrix2fv(location, transpose, array, ec); break;
    993             case 3: context->uniformMatrix3fv(location, transpose, array, ec); break;
    994             case 4: context->uniformMatrix4fv(location, transpose, array, ec); break;
    995             default: ASSERT_NOT_REACHED(); break;
    996         }
    997         if (ec)
    998             V8Proxy::setDOMException(ec);
    999         return v8::Undefined();
   1000     }
   1001 
   1002     v8::Handle<v8::Array> array =
   1003       v8::Local<v8::Array>::Cast(args[2]);
   1004     if (array.IsEmpty()) {
   1005         V8Proxy::setDOMException(SYNTAX_ERR);
   1006         return notHandledByInterceptor();
   1007     }
   1008     uint32_t len = array->Length();
   1009     float* data = jsArrayToFloatArray(array, len);
   1010     if (!data) {
   1011         // FIXME: consider different / better exception type.
   1012         V8Proxy::setDOMException(SYNTAX_ERR);
   1013         return notHandledByInterceptor();
   1014     }
   1015     ExceptionCode ec = 0;
   1016     switch (matrixSize) {
   1017         case 2: context->uniformMatrix2fv(location, transpose, data, len, ec); break;
   1018         case 3: context->uniformMatrix3fv(location, transpose, data, len, ec); break;
   1019         case 4: context->uniformMatrix4fv(location, transpose, data, len, ec); break;
   1020         default: ASSERT_NOT_REACHED(); break;
   1021     }
   1022     fastFree(data);
   1023     if (ec)
   1024         V8Proxy::setDOMException(ec);
   1025     return v8::Undefined();
   1026 }
   1027 
   1028 v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix2fvCallback(const v8::Arguments& args)
   1029 {
   1030     INC_STATS("DOM.WebGLRenderingContext.uniformMatrix2fv()");
   1031     return uniformMatrixHelper(args, 2);
   1032 }
   1033 
   1034 v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix3fvCallback(const v8::Arguments& args)
   1035 {
   1036     INC_STATS("DOM.WebGLRenderingContext.uniformMatrix3fv()");
   1037     return uniformMatrixHelper(args, 3);
   1038 }
   1039 
   1040 v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix4fvCallback(const v8::Arguments& args)
   1041 {
   1042     INC_STATS("DOM.WebGLRenderingContext.uniformMatrix4fv()");
   1043     return uniformMatrixHelper(args, 4);
   1044 }
   1045 
   1046 v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib1fvCallback(const v8::Arguments& args)
   1047 {
   1048     INC_STATS("DOM.WebGLRenderingContext.vertexAttrib1fv()");
   1049     return vertexAttribAndUniformHelperf(args, kVertexAttrib1v);
   1050 }
   1051 
   1052 v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib2fvCallback(const v8::Arguments& args)
   1053 {
   1054     INC_STATS("DOM.WebGLRenderingContext.vertexAttrib2fv()");
   1055     return vertexAttribAndUniformHelperf(args, kVertexAttrib2v);
   1056 }
   1057 
   1058 v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib3fvCallback(const v8::Arguments& args)
   1059 {
   1060     INC_STATS("DOM.WebGLRenderingContext.vertexAttrib3fv()");
   1061     return vertexAttribAndUniformHelperf(args, kVertexAttrib3v);
   1062 }
   1063 
   1064 v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib4fvCallback(const v8::Arguments& args)
   1065 {
   1066     INC_STATS("DOM.WebGLRenderingContext.vertexAttrib4fv()");
   1067     return vertexAttribAndUniformHelperf(args, kVertexAttrib4v);
   1068 }
   1069 
   1070 } // namespace WebCore
   1071 
   1072 #endif // ENABLE(3D_CANVAS)
   1073