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 66namespace WebCore { 67 68// Allocates new storage via tryFastMalloc. 69// Returns NULL if array failed to convert for any reason. 70static 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. 89static 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 108v8::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 149v8::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 182static 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 221enum ObjectType { 222 kBuffer, kRenderbuffer, kTexture, kVertexAttrib 223}; 224 225static 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 271static 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 282enum WhichProgramCall { 283 kProgramParameter, kUniform 284}; 285 286v8::Handle<v8::Value> V8WebGLRenderingContext::getBufferParameterCallback(const v8::Arguments& args) 287{ 288 INC_STATS("DOM.WebGLRenderingContext.getBufferParameter()"); 289 return getObjectParameter(args, kBuffer); 290} 291 292v8::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 327v8::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 352v8::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 378v8::Handle<v8::Value> V8WebGLRenderingContext::getRenderbufferParameterCallback(const v8::Arguments& args) 379{ 380 INC_STATS("DOM.WebGLRenderingContext.getRenderbufferParameter()"); 381 return getObjectParameter(args, kRenderbuffer); 382} 383 384v8::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 410v8::Handle<v8::Value> V8WebGLRenderingContext::getTexParameterCallback(const v8::Arguments& args) 411{ 412 INC_STATS("DOM.WebGLRenderingContext.getTexParameter()"); 413 return getObjectParameter(args, kTexture); 414} 415 416v8::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 444v8::Handle<v8::Value> V8WebGLRenderingContext::getVertexAttribCallback(const v8::Arguments& args) 445{ 446 INC_STATS("DOM.WebGLRenderingContext.getVertexAttrib()"); 447 return getObjectParameter(args, kVertexAttrib); 448} 449 450v8::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 592v8::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 734enum FunctionToCall { 735 kUniform1v, kUniform2v, kUniform3v, kUniform4v, 736 kVertexAttrib1v, kVertexAttrib2v, kVertexAttrib3v, kVertexAttrib4v 737}; 738 739bool 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 753static 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 844static 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 912v8::Handle<v8::Value> V8WebGLRenderingContext::uniform1fvCallback(const v8::Arguments& args) 913{ 914 INC_STATS("DOM.WebGLRenderingContext.uniform1fv()"); 915 return vertexAttribAndUniformHelperf(args, kUniform1v); 916} 917 918v8::Handle<v8::Value> V8WebGLRenderingContext::uniform1ivCallback(const v8::Arguments& args) 919{ 920 INC_STATS("DOM.WebGLRenderingContext.uniform1iv()"); 921 return uniformHelperi(args, kUniform1v); 922} 923 924v8::Handle<v8::Value> V8WebGLRenderingContext::uniform2fvCallback(const v8::Arguments& args) 925{ 926 INC_STATS("DOM.WebGLRenderingContext.uniform2fv()"); 927 return vertexAttribAndUniformHelperf(args, kUniform2v); 928} 929 930v8::Handle<v8::Value> V8WebGLRenderingContext::uniform2ivCallback(const v8::Arguments& args) 931{ 932 INC_STATS("DOM.WebGLRenderingContext.uniform2iv()"); 933 return uniformHelperi(args, kUniform2v); 934} 935 936v8::Handle<v8::Value> V8WebGLRenderingContext::uniform3fvCallback(const v8::Arguments& args) 937{ 938 INC_STATS("DOM.WebGLRenderingContext.uniform3fv()"); 939 return vertexAttribAndUniformHelperf(args, kUniform3v); 940} 941 942v8::Handle<v8::Value> V8WebGLRenderingContext::uniform3ivCallback(const v8::Arguments& args) 943{ 944 INC_STATS("DOM.WebGLRenderingContext.uniform3iv()"); 945 return uniformHelperi(args, kUniform3v); 946} 947 948v8::Handle<v8::Value> V8WebGLRenderingContext::uniform4fvCallback(const v8::Arguments& args) 949{ 950 INC_STATS("DOM.WebGLRenderingContext.uniform4fv()"); 951 return vertexAttribAndUniformHelperf(args, kUniform4v); 952} 953 954v8::Handle<v8::Value> V8WebGLRenderingContext::uniform4ivCallback(const v8::Arguments& args) 955{ 956 INC_STATS("DOM.WebGLRenderingContext.uniform4iv()"); 957 return uniformHelperi(args, kUniform4v); 958} 959 960static 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 1028v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix2fvCallback(const v8::Arguments& args) 1029{ 1030 INC_STATS("DOM.WebGLRenderingContext.uniformMatrix2fv()"); 1031 return uniformMatrixHelper(args, 2); 1032} 1033 1034v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix3fvCallback(const v8::Arguments& args) 1035{ 1036 INC_STATS("DOM.WebGLRenderingContext.uniformMatrix3fv()"); 1037 return uniformMatrixHelper(args, 3); 1038} 1039 1040v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix4fvCallback(const v8::Arguments& args) 1041{ 1042 INC_STATS("DOM.WebGLRenderingContext.uniformMatrix4fv()"); 1043 return uniformMatrixHelper(args, 4); 1044} 1045 1046v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib1fvCallback(const v8::Arguments& args) 1047{ 1048 INC_STATS("DOM.WebGLRenderingContext.vertexAttrib1fv()"); 1049 return vertexAttribAndUniformHelperf(args, kVertexAttrib1v); 1050} 1051 1052v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib2fvCallback(const v8::Arguments& args) 1053{ 1054 INC_STATS("DOM.WebGLRenderingContext.vertexAttrib2fv()"); 1055 return vertexAttribAndUniformHelperf(args, kVertexAttrib2v); 1056} 1057 1058v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib3fvCallback(const v8::Arguments& args) 1059{ 1060 INC_STATS("DOM.WebGLRenderingContext.vertexAttrib3fv()"); 1061 return vertexAttribAndUniformHelperf(args, kVertexAttrib3v); 1062} 1063 1064v8::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