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 are 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(WEBGL) 34 35#include "V8WebGLRenderingContext.h" 36 37#include "ExceptionCode.h" 38#include "NotImplemented.h" 39#include "V8ArrayBufferView.h" 40#include "V8Binding.h" 41#include "V8BindingMacros.h" 42#include "V8WebKitLoseContext.h" 43#include "V8Float32Array.h" 44#include "V8HTMLCanvasElement.h" 45#include "V8HTMLImageElement.h" 46#include "V8HTMLVideoElement.h" 47#include "V8ImageData.h" 48#include "V8Int16Array.h" 49#include "V8Int32Array.h" 50#include "V8Int8Array.h" 51#include "V8OESStandardDerivatives.h" 52#include "V8OESTextureFloat.h" 53#include "V8OESVertexArrayObject.h" 54#include "V8Proxy.h" 55#include "V8Uint16Array.h" 56#include "V8Uint32Array.h" 57#include "V8Uint8Array.h" 58#include "V8WebGLBuffer.h" 59#include "V8WebGLFramebuffer.h" 60#include "V8WebGLProgram.h" 61#include "V8WebGLRenderbuffer.h" 62#include "V8WebGLShader.h" 63#include "V8WebGLTexture.h" 64#include "V8WebGLUniformLocation.h" 65#include "V8WebGLVertexArrayObjectOES.h" 66#include "WebGLRenderingContext.h" 67#include <wtf/FastMalloc.h> 68 69namespace WebCore { 70 71// Allocates new storage via tryFastMalloc. 72// Returns NULL if array failed to convert for any reason. 73static float* jsArrayToFloatArray(v8::Handle<v8::Array> array, uint32_t len) 74{ 75 // Convert the data element-by-element. 76 float* data; 77 if (!tryFastMalloc(len * sizeof(float)).getValue(data)) 78 return 0; 79 for (uint32_t i = 0; i < len; i++) { 80 v8::Local<v8::Value> val = array->Get(v8::Integer::New(i)); 81 if (!val->IsNumber()) { 82 fastFree(data); 83 return 0; 84 } 85 data[i] = toFloat(val); 86 } 87 return data; 88} 89 90// Allocates new storage via tryFastMalloc. 91// Returns NULL if array failed to convert for any reason. 92static int* jsArrayToIntArray(v8::Handle<v8::Array> array, uint32_t len) 93{ 94 // Convert the data element-by-element. 95 int* data; 96 if (!tryFastMalloc(len * sizeof(int)).getValue(data)) 97 return 0; 98 for (uint32_t i = 0; i < len; i++) { 99 v8::Local<v8::Value> val = array->Get(v8::Integer::New(i)); 100 bool ok; 101 int ival = toInt32(val, ok); 102 if (!ok) { 103 fastFree(data); 104 return 0; 105 } 106 data[i] = ival; 107 } 108 return data; 109} 110 111static v8::Handle<v8::Value> toV8Object(const WebGLGetInfo& info) 112{ 113 switch (info.getType()) { 114 case WebGLGetInfo::kTypeBool: 115 return v8::Boolean::New(info.getBool()); 116 case WebGLGetInfo::kTypeBoolArray: { 117 const Vector<bool>& value = info.getBoolArray(); 118 v8::Local<v8::Array> array = v8::Array::New(value.size()); 119 for (size_t ii = 0; ii < value.size(); ++ii) 120 array->Set(v8::Integer::New(ii), v8::Boolean::New(value[ii])); 121 return array; 122 } 123 case WebGLGetInfo::kTypeFloat: 124 return v8::Number::New(info.getFloat()); 125 case WebGLGetInfo::kTypeInt: 126 return v8::Integer::New(info.getInt()); 127 case WebGLGetInfo::kTypeNull: 128 return v8::Null(); 129 case WebGLGetInfo::kTypeString: 130 return v8::String::New(fromWebCoreString(info.getString()), info.getString().length()); 131 case WebGLGetInfo::kTypeUnsignedInt: 132 return v8::Integer::NewFromUnsigned(info.getUnsignedInt()); 133 case WebGLGetInfo::kTypeWebGLBuffer: 134 return toV8(info.getWebGLBuffer()); 135 case WebGLGetInfo::kTypeWebGLFloatArray: 136 return toV8(info.getWebGLFloatArray()); 137 case WebGLGetInfo::kTypeWebGLFramebuffer: 138 return toV8(info.getWebGLFramebuffer()); 139 case WebGLGetInfo::kTypeWebGLIntArray: 140 return toV8(info.getWebGLIntArray()); 141 // FIXME: implement WebGLObjectArray 142 // case WebGLGetInfo::kTypeWebGLObjectArray: 143 case WebGLGetInfo::kTypeWebGLProgram: 144 return toV8(info.getWebGLProgram()); 145 case WebGLGetInfo::kTypeWebGLRenderbuffer: 146 return toV8(info.getWebGLRenderbuffer()); 147 case WebGLGetInfo::kTypeWebGLTexture: 148 return toV8(info.getWebGLTexture()); 149 case WebGLGetInfo::kTypeWebGLUnsignedByteArray: 150 return toV8(info.getWebGLUnsignedByteArray()); 151 case WebGLGetInfo::kTypeWebGLVertexArrayObjectOES: 152 return toV8(info.getWebGLVertexArrayObjectOES()); 153 default: 154 notImplemented(); 155 return v8::Undefined(); 156 } 157} 158 159static v8::Handle<v8::Value> toV8Object(WebGLExtension* extension, v8::Handle<v8::Object> contextObject) 160{ 161 if (!extension) 162 return v8::Null(); 163 v8::Handle<v8::Value> extensionObject; 164 const char* referenceName; 165 switch (extension->getName()) { 166 case WebGLExtension::WebKitLoseContextName: 167 extensionObject = toV8(static_cast<WebKitLoseContext*>(extension)); 168 referenceName = "webKitLoseContextName"; 169 break; 170 case WebGLExtension::OESStandardDerivativesName: 171 extensionObject = toV8(static_cast<OESStandardDerivatives*>(extension)); 172 referenceName = "oesStandardDerivativesName"; 173 break; 174 case WebGLExtension::OESTextureFloatName: 175 extensionObject = toV8(static_cast<OESTextureFloat*>(extension)); 176 referenceName = "oesTextureFloatName"; 177 break; 178 case WebGLExtension::OESVertexArrayObjectName: 179 extensionObject = toV8(static_cast<OESVertexArrayObject*>(extension)); 180 referenceName = "oesVertexArrayObjectName"; 181 break; 182 } 183 ASSERT(!extensionObject.IsEmpty()); 184 V8DOMWrapper::setNamedHiddenReference(contextObject, referenceName, extensionObject); 185 return extensionObject; 186} 187 188enum ObjectType { 189 kBuffer, kRenderbuffer, kTexture, kVertexAttrib 190}; 191 192static v8::Handle<v8::Value> getObjectParameter(const v8::Arguments& args, ObjectType objectType) 193{ 194 if (args.Length() != 2) { 195 V8Proxy::setDOMException(SYNTAX_ERR); 196 return notHandledByInterceptor(); 197 } 198 199 ExceptionCode ec = 0; 200 WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); 201 unsigned target = toInt32(args[0]); 202 unsigned pname = toInt32(args[1]); 203 WebGLGetInfo info; 204 switch (objectType) { 205 case kBuffer: 206 info = context->getBufferParameter(target, pname, ec); 207 break; 208 case kRenderbuffer: 209 info = context->getRenderbufferParameter(target, pname, ec); 210 break; 211 case kTexture: 212 info = context->getTexParameter(target, pname, ec); 213 break; 214 case kVertexAttrib: 215 // target => index 216 info = context->getVertexAttrib(target, pname, ec); 217 break; 218 default: 219 notImplemented(); 220 break; 221 } 222 if (ec) { 223 V8Proxy::setDOMException(ec); 224 return v8::Undefined(); 225 } 226 return toV8Object(info); 227} 228 229static WebGLUniformLocation* toWebGLUniformLocation(v8::Handle<v8::Value> value, bool& ok) 230{ 231 ok = false; 232 WebGLUniformLocation* location = 0; 233 if (V8WebGLUniformLocation::HasInstance(value)) { 234 location = V8WebGLUniformLocation::toNative(value->ToObject()); 235 ok = true; 236 } 237 return location; 238} 239 240enum WhichProgramCall { 241 kProgramParameter, kUniform 242}; 243 244v8::Handle<v8::Value> V8WebGLRenderingContext::getAttachedShadersCallback(const v8::Arguments& args) 245{ 246 INC_STATS("DOM.WebGLRenderingContext.getAttachedShaders()"); 247 248 if (args.Length() < 1) { 249 V8Proxy::setDOMException(SYNTAX_ERR); 250 return notHandledByInterceptor(); 251 } 252 253 ExceptionCode ec = 0; 254 WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); 255 if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLProgram::HasInstance(args[0])) { 256 V8Proxy::throwTypeError(); 257 return notHandledByInterceptor(); 258 } 259 WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0; 260 Vector<WebGLShader*> shaders; 261 bool succeed = context->getAttachedShaders(program, shaders, ec); 262 if (ec) { 263 V8Proxy::setDOMException(ec); 264 return v8::Null(); 265 } 266 if (!succeed) 267 return v8::Null(); 268 v8::Local<v8::Array> array = v8::Array::New(shaders.size()); 269 for (size_t ii = 0; ii < shaders.size(); ++ii) 270 array->Set(v8::Integer::New(ii), toV8(shaders[ii])); 271 return array; 272} 273 274v8::Handle<v8::Value> V8WebGLRenderingContext::getBufferParameterCallback(const v8::Arguments& args) 275{ 276 INC_STATS("DOM.WebGLRenderingContext.getBufferParameter()"); 277 return getObjectParameter(args, kBuffer); 278} 279 280v8::Handle<v8::Value> V8WebGLRenderingContext::getExtensionCallback(const v8::Arguments& args) 281{ 282 INC_STATS("DOM.WebGLRenderingContext.getExtensionCallback()"); 283 WebGLRenderingContext* imp = V8WebGLRenderingContext::toNative(args.Holder()); 284 if (args.Length() < 1) { 285 V8Proxy::setDOMException(SYNTAX_ERR); 286 return notHandledByInterceptor(); 287 } 288 STRING_TO_V8PARAMETER_EXCEPTION_BLOCK(V8Parameter<>, name, args[0]); 289 WebGLExtension* extension = imp->getExtension(name); 290 return toV8Object(extension, args.Holder()); 291} 292 293v8::Handle<v8::Value> V8WebGLRenderingContext::getFramebufferAttachmentParameterCallback(const v8::Arguments& args) 294{ 295 INC_STATS("DOM.WebGLRenderingContext.getFramebufferAttachmentParameter()"); 296 297 if (args.Length() != 3) { 298 V8Proxy::setDOMException(SYNTAX_ERR); 299 return notHandledByInterceptor(); 300 } 301 302 ExceptionCode ec = 0; 303 WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); 304 unsigned target = toInt32(args[0]); 305 unsigned attachment = toInt32(args[1]); 306 unsigned pname = toInt32(args[2]); 307 WebGLGetInfo info = context->getFramebufferAttachmentParameter(target, attachment, pname, ec); 308 if (ec) { 309 V8Proxy::setDOMException(ec); 310 return v8::Undefined(); 311 } 312 return toV8Object(info); 313} 314 315v8::Handle<v8::Value> V8WebGLRenderingContext::getParameterCallback(const v8::Arguments& args) 316{ 317 INC_STATS("DOM.WebGLRenderingContext.getParameter()"); 318 319 if (args.Length() != 1) { 320 V8Proxy::setDOMException(SYNTAX_ERR); 321 return notHandledByInterceptor(); 322 } 323 324 ExceptionCode ec = 0; 325 WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); 326 unsigned pname = toInt32(args[0]); 327 WebGLGetInfo info = context->getParameter(pname, ec); 328 if (ec) { 329 V8Proxy::setDOMException(ec); 330 return v8::Undefined(); 331 } 332 return toV8Object(info); 333} 334 335v8::Handle<v8::Value> V8WebGLRenderingContext::getProgramParameterCallback(const v8::Arguments& args) 336{ 337 INC_STATS("DOM.WebGLRenderingContext.getProgramParameter()"); 338 339 if (args.Length() != 2) { 340 V8Proxy::setDOMException(SYNTAX_ERR); 341 return notHandledByInterceptor(); 342 } 343 344 ExceptionCode ec = 0; 345 WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); 346 if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLProgram::HasInstance(args[0])) { 347 V8Proxy::throwTypeError(); 348 return notHandledByInterceptor(); 349 } 350 WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0; 351 unsigned pname = toInt32(args[1]); 352 WebGLGetInfo info = context->getProgramParameter(program, pname, ec); 353 if (ec) { 354 V8Proxy::setDOMException(ec); 355 return v8::Undefined(); 356 } 357 return toV8Object(info); 358} 359 360v8::Handle<v8::Value> V8WebGLRenderingContext::getRenderbufferParameterCallback(const v8::Arguments& args) 361{ 362 INC_STATS("DOM.WebGLRenderingContext.getRenderbufferParameter()"); 363 return getObjectParameter(args, kRenderbuffer); 364} 365 366v8::Handle<v8::Value> V8WebGLRenderingContext::getShaderParameterCallback(const v8::Arguments& args) 367{ 368 INC_STATS("DOM.WebGLRenderingContext.getShaderParameter()"); 369 370 if (args.Length() != 2) { 371 V8Proxy::setDOMException(SYNTAX_ERR); 372 return notHandledByInterceptor(); 373 } 374 375 ExceptionCode ec = 0; 376 WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); 377 if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLShader::HasInstance(args[0])) { 378 V8Proxy::throwTypeError(); 379 return notHandledByInterceptor(); 380 } 381 WebGLShader* shader = V8WebGLShader::HasInstance(args[0]) ? V8WebGLShader::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0; 382 unsigned pname = toInt32(args[1]); 383 WebGLGetInfo info = context->getShaderParameter(shader, pname, ec); 384 if (ec) { 385 V8Proxy::setDOMException(ec); 386 return v8::Undefined(); 387 } 388 return toV8Object(info); 389} 390 391v8::Handle<v8::Value> V8WebGLRenderingContext::getSupportedExtensionsCallback(const v8::Arguments& args) 392{ 393 INC_STATS("DOM.WebGLRenderingContext.getSupportedExtensionsCallback()"); 394 WebGLRenderingContext* imp = V8WebGLRenderingContext::toNative(args.Holder()); 395 if (imp->isContextLost()) 396 return v8::Null(); 397 398 Vector<String> value = imp->getSupportedExtensions(); 399 v8::Local<v8::Array> array = v8::Array::New(value.size()); 400 for (size_t ii = 0; ii < value.size(); ++ii) 401 array->Set(v8::Integer::New(ii), v8::String::New(fromWebCoreString(value[ii]), value[ii].length())); 402 return array; 403} 404 405v8::Handle<v8::Value> V8WebGLRenderingContext::getTexParameterCallback(const v8::Arguments& args) 406{ 407 INC_STATS("DOM.WebGLRenderingContext.getTexParameter()"); 408 return getObjectParameter(args, kTexture); 409} 410 411v8::Handle<v8::Value> V8WebGLRenderingContext::getUniformCallback(const v8::Arguments& args) 412{ 413 INC_STATS("DOM.WebGLRenderingContext.getUniform()"); 414 415 if (args.Length() != 2) { 416 V8Proxy::setDOMException(SYNTAX_ERR); 417 return notHandledByInterceptor(); 418 } 419 420 ExceptionCode ec = 0; 421 WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); 422 if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLProgram::HasInstance(args[0])) { 423 V8Proxy::throwTypeError(); 424 return notHandledByInterceptor(); 425 } 426 WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0; 427 428 if (args.Length() > 1 && !isUndefinedOrNull(args[1]) && !V8WebGLUniformLocation::HasInstance(args[1])) { 429 V8Proxy::throwTypeError(); 430 return notHandledByInterceptor(); 431 } 432 bool ok = false; 433 WebGLUniformLocation* location = toWebGLUniformLocation(args[1], ok); 434 435 WebGLGetInfo info = context->getUniform(program, location, ec); 436 if (ec) { 437 V8Proxy::setDOMException(ec); 438 return v8::Undefined(); 439 } 440 return toV8Object(info); 441} 442 443v8::Handle<v8::Value> V8WebGLRenderingContext::getVertexAttribCallback(const v8::Arguments& args) 444{ 445 INC_STATS("DOM.WebGLRenderingContext.getVertexAttrib()"); 446 return getObjectParameter(args, kVertexAttrib); 447} 448 449enum FunctionToCall { 450 kUniform1v, kUniform2v, kUniform3v, kUniform4v, 451 kVertexAttrib1v, kVertexAttrib2v, kVertexAttrib3v, kVertexAttrib4v 452}; 453 454bool isFunctionToCallForAttribute(FunctionToCall functionToCall) 455{ 456 switch (functionToCall) { 457 case kVertexAttrib1v: 458 case kVertexAttrib2v: 459 case kVertexAttrib3v: 460 case kVertexAttrib4v: 461 return true; 462 default: 463 break; 464 } 465 return false; 466} 467 468static v8::Handle<v8::Value> vertexAttribAndUniformHelperf(const v8::Arguments& args, 469 FunctionToCall functionToCall) { 470 // Forms: 471 // * glUniform1fv(WebGLUniformLocation location, Array data); 472 // * glUniform1fv(WebGLUniformLocation location, Float32Array data); 473 // * glUniform2fv(WebGLUniformLocation location, Array data); 474 // * glUniform2fv(WebGLUniformLocation location, Float32Array data); 475 // * glUniform3fv(WebGLUniformLocation location, Array data); 476 // * glUniform3fv(WebGLUniformLocation location, Float32Array data); 477 // * glUniform4fv(WebGLUniformLocation location, Array data); 478 // * glUniform4fv(WebGLUniformLocation location, Float32Array data); 479 // * glVertexAttrib1fv(GLint index, Array data); 480 // * glVertexAttrib1fv(GLint index, Float32Array data); 481 // * glVertexAttrib2fv(GLint index, Array data); 482 // * glVertexAttrib2fv(GLint index, Float32Array data); 483 // * glVertexAttrib3fv(GLint index, Array data); 484 // * glVertexAttrib3fv(GLint index, Float32Array data); 485 // * glVertexAttrib4fv(GLint index, Array data); 486 // * glVertexAttrib4fv(GLint index, Float32Array data); 487 488 if (args.Length() != 2) { 489 V8Proxy::setDOMException(SYNTAX_ERR); 490 return notHandledByInterceptor(); 491 } 492 493 bool ok = false; 494 int index = -1; 495 WebGLUniformLocation* location = 0; 496 497 if (isFunctionToCallForAttribute(functionToCall)) 498 index = toInt32(args[0]); 499 else { 500 if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLUniformLocation::HasInstance(args[0])) { 501 V8Proxy::throwTypeError(); 502 return notHandledByInterceptor(); 503 } 504 location = toWebGLUniformLocation(args[0], ok); 505 } 506 507 WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); 508 509 if (V8Float32Array::HasInstance(args[1])) { 510 Float32Array* array = V8Float32Array::toNative(args[1]->ToObject()); 511 ASSERT(array != NULL); 512 ExceptionCode ec = 0; 513 switch (functionToCall) { 514 case kUniform1v: context->uniform1fv(location, array, ec); break; 515 case kUniform2v: context->uniform2fv(location, array, ec); break; 516 case kUniform3v: context->uniform3fv(location, array, ec); break; 517 case kUniform4v: context->uniform4fv(location, array, ec); break; 518 case kVertexAttrib1v: context->vertexAttrib1fv(index, array); break; 519 case kVertexAttrib2v: context->vertexAttrib2fv(index, array); break; 520 case kVertexAttrib3v: context->vertexAttrib3fv(index, array); break; 521 case kVertexAttrib4v: context->vertexAttrib4fv(index, array); break; 522 default: ASSERT_NOT_REACHED(); break; 523 } 524 if (ec) 525 V8Proxy::setDOMException(ec); 526 return v8::Undefined(); 527 } 528 529 if (args[1].IsEmpty() || !args[1]->IsArray()) { 530 V8Proxy::throwTypeError(); 531 return notHandledByInterceptor(); 532 } 533 v8::Handle<v8::Array> array = 534 v8::Local<v8::Array>::Cast(args[1]); 535 uint32_t len = array->Length(); 536 float* data = jsArrayToFloatArray(array, len); 537 if (!data) { 538 // FIXME: consider different / better exception type. 539 V8Proxy::setDOMException(SYNTAX_ERR); 540 return notHandledByInterceptor(); 541 } 542 ExceptionCode ec = 0; 543 switch (functionToCall) { 544 case kUniform1v: context->uniform1fv(location, data, len, ec); break; 545 case kUniform2v: context->uniform2fv(location, data, len, ec); break; 546 case kUniform3v: context->uniform3fv(location, data, len, ec); break; 547 case kUniform4v: context->uniform4fv(location, data, len, ec); break; 548 case kVertexAttrib1v: context->vertexAttrib1fv(index, data, len); break; 549 case kVertexAttrib2v: context->vertexAttrib2fv(index, data, len); break; 550 case kVertexAttrib3v: context->vertexAttrib3fv(index, data, len); break; 551 case kVertexAttrib4v: context->vertexAttrib4fv(index, data, len); break; 552 default: ASSERT_NOT_REACHED(); break; 553 } 554 fastFree(data); 555 if (ec) 556 V8Proxy::setDOMException(ec); 557 return v8::Undefined(); 558} 559 560static v8::Handle<v8::Value> uniformHelperi(const v8::Arguments& args, 561 FunctionToCall functionToCall) { 562 // Forms: 563 // * glUniform1iv(GLUniformLocation location, Array data); 564 // * glUniform1iv(GLUniformLocation location, Int32Array data); 565 // * glUniform2iv(GLUniformLocation location, Array data); 566 // * glUniform2iv(GLUniformLocation location, Int32Array data); 567 // * glUniform3iv(GLUniformLocation location, Array data); 568 // * glUniform3iv(GLUniformLocation location, Int32Array data); 569 // * glUniform4iv(GLUniformLocation location, Array data); 570 // * glUniform4iv(GLUniformLocation location, Int32Array data); 571 572 if (args.Length() != 2) { 573 V8Proxy::setDOMException(SYNTAX_ERR); 574 return notHandledByInterceptor(); 575 } 576 577 WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); 578 if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLUniformLocation::HasInstance(args[0])) { 579 V8Proxy::throwTypeError(); 580 return notHandledByInterceptor(); 581 } 582 bool ok = false; 583 WebGLUniformLocation* location = toWebGLUniformLocation(args[0], ok); 584 585 if (V8Int32Array::HasInstance(args[1])) { 586 Int32Array* array = V8Int32Array::toNative(args[1]->ToObject()); 587 ASSERT(array != NULL); 588 ExceptionCode ec = 0; 589 switch (functionToCall) { 590 case kUniform1v: context->uniform1iv(location, array, ec); break; 591 case kUniform2v: context->uniform2iv(location, array, ec); break; 592 case kUniform3v: context->uniform3iv(location, array, ec); break; 593 case kUniform4v: context->uniform4iv(location, array, ec); break; 594 default: ASSERT_NOT_REACHED(); break; 595 } 596 if (ec) 597 V8Proxy::setDOMException(ec); 598 return v8::Undefined(); 599 } 600 601 if (args[1].IsEmpty() || !args[1]->IsArray()) { 602 V8Proxy::throwTypeError(); 603 return notHandledByInterceptor(); 604 } 605 v8::Handle<v8::Array> array = 606 v8::Local<v8::Array>::Cast(args[1]); 607 uint32_t len = array->Length(); 608 int* data = jsArrayToIntArray(array, len); 609 if (!data) { 610 // FIXME: consider different / better exception type. 611 V8Proxy::setDOMException(SYNTAX_ERR); 612 return notHandledByInterceptor(); 613 } 614 ExceptionCode ec = 0; 615 switch (functionToCall) { 616 case kUniform1v: context->uniform1iv(location, data, len, ec); break; 617 case kUniform2v: context->uniform2iv(location, data, len, ec); break; 618 case kUniform3v: context->uniform3iv(location, data, len, ec); break; 619 case kUniform4v: context->uniform4iv(location, data, len, ec); break; 620 default: ASSERT_NOT_REACHED(); break; 621 } 622 fastFree(data); 623 if (ec) 624 V8Proxy::setDOMException(ec); 625 return v8::Undefined(); 626} 627 628v8::Handle<v8::Value> V8WebGLRenderingContext::uniform1fvCallback(const v8::Arguments& args) 629{ 630 INC_STATS("DOM.WebGLRenderingContext.uniform1fv()"); 631 return vertexAttribAndUniformHelperf(args, kUniform1v); 632} 633 634v8::Handle<v8::Value> V8WebGLRenderingContext::uniform1ivCallback(const v8::Arguments& args) 635{ 636 INC_STATS("DOM.WebGLRenderingContext.uniform1iv()"); 637 return uniformHelperi(args, kUniform1v); 638} 639 640v8::Handle<v8::Value> V8WebGLRenderingContext::uniform2fvCallback(const v8::Arguments& args) 641{ 642 INC_STATS("DOM.WebGLRenderingContext.uniform2fv()"); 643 return vertexAttribAndUniformHelperf(args, kUniform2v); 644} 645 646v8::Handle<v8::Value> V8WebGLRenderingContext::uniform2ivCallback(const v8::Arguments& args) 647{ 648 INC_STATS("DOM.WebGLRenderingContext.uniform2iv()"); 649 return uniformHelperi(args, kUniform2v); 650} 651 652v8::Handle<v8::Value> V8WebGLRenderingContext::uniform3fvCallback(const v8::Arguments& args) 653{ 654 INC_STATS("DOM.WebGLRenderingContext.uniform3fv()"); 655 return vertexAttribAndUniformHelperf(args, kUniform3v); 656} 657 658v8::Handle<v8::Value> V8WebGLRenderingContext::uniform3ivCallback(const v8::Arguments& args) 659{ 660 INC_STATS("DOM.WebGLRenderingContext.uniform3iv()"); 661 return uniformHelperi(args, kUniform3v); 662} 663 664v8::Handle<v8::Value> V8WebGLRenderingContext::uniform4fvCallback(const v8::Arguments& args) 665{ 666 INC_STATS("DOM.WebGLRenderingContext.uniform4fv()"); 667 return vertexAttribAndUniformHelperf(args, kUniform4v); 668} 669 670v8::Handle<v8::Value> V8WebGLRenderingContext::uniform4ivCallback(const v8::Arguments& args) 671{ 672 INC_STATS("DOM.WebGLRenderingContext.uniform4iv()"); 673 return uniformHelperi(args, kUniform4v); 674} 675 676static v8::Handle<v8::Value> uniformMatrixHelper(const v8::Arguments& args, 677 int matrixSize) 678{ 679 // Forms: 680 // * glUniformMatrix2fv(GLint location, GLboolean transpose, Array data); 681 // * glUniformMatrix2fv(GLint location, GLboolean transpose, Float32Array data); 682 // * glUniformMatrix3fv(GLint location, GLboolean transpose, Array data); 683 // * glUniformMatrix3fv(GLint location, GLboolean transpose, Float32Array data); 684 // * glUniformMatrix4fv(GLint location, GLboolean transpose, Array data); 685 // * glUniformMatrix4fv(GLint location, GLboolean transpose, Float32Array data); 686 // 687 // FIXME: need to change to accept Float32Array as well. 688 if (args.Length() != 3) { 689 V8Proxy::setDOMException(SYNTAX_ERR); 690 return notHandledByInterceptor(); 691 } 692 693 WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder()); 694 695 if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLUniformLocation::HasInstance(args[0])) { 696 V8Proxy::throwTypeError(); 697 return notHandledByInterceptor(); 698 } 699 bool ok = false; 700 WebGLUniformLocation* location = toWebGLUniformLocation(args[0], ok); 701 702 bool transpose = args[1]->BooleanValue(); 703 if (V8Float32Array::HasInstance(args[2])) { 704 Float32Array* array = V8Float32Array::toNative(args[2]->ToObject()); 705 ASSERT(array != NULL); 706 ExceptionCode ec = 0; 707 switch (matrixSize) { 708 case 2: context->uniformMatrix2fv(location, transpose, array, ec); break; 709 case 3: context->uniformMatrix3fv(location, transpose, array, ec); break; 710 case 4: context->uniformMatrix4fv(location, transpose, array, ec); break; 711 default: ASSERT_NOT_REACHED(); break; 712 } 713 if (ec) 714 V8Proxy::setDOMException(ec); 715 return v8::Undefined(); 716 } 717 718 if (args[2].IsEmpty() || !args[2]->IsArray()) { 719 V8Proxy::throwTypeError(); 720 return notHandledByInterceptor(); 721 } 722 v8::Handle<v8::Array> array = 723 v8::Local<v8::Array>::Cast(args[2]); 724 uint32_t len = array->Length(); 725 float* data = jsArrayToFloatArray(array, len); 726 if (!data) { 727 // FIXME: consider different / better exception type. 728 V8Proxy::setDOMException(SYNTAX_ERR); 729 return notHandledByInterceptor(); 730 } 731 ExceptionCode ec = 0; 732 switch (matrixSize) { 733 case 2: context->uniformMatrix2fv(location, transpose, data, len, ec); break; 734 case 3: context->uniformMatrix3fv(location, transpose, data, len, ec); break; 735 case 4: context->uniformMatrix4fv(location, transpose, data, len, ec); break; 736 default: ASSERT_NOT_REACHED(); break; 737 } 738 fastFree(data); 739 if (ec) 740 V8Proxy::setDOMException(ec); 741 return v8::Undefined(); 742} 743 744v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix2fvCallback(const v8::Arguments& args) 745{ 746 INC_STATS("DOM.WebGLRenderingContext.uniformMatrix2fv()"); 747 return uniformMatrixHelper(args, 2); 748} 749 750v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix3fvCallback(const v8::Arguments& args) 751{ 752 INC_STATS("DOM.WebGLRenderingContext.uniformMatrix3fv()"); 753 return uniformMatrixHelper(args, 3); 754} 755 756v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix4fvCallback(const v8::Arguments& args) 757{ 758 INC_STATS("DOM.WebGLRenderingContext.uniformMatrix4fv()"); 759 return uniformMatrixHelper(args, 4); 760} 761 762v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib1fvCallback(const v8::Arguments& args) 763{ 764 INC_STATS("DOM.WebGLRenderingContext.vertexAttrib1fv()"); 765 return vertexAttribAndUniformHelperf(args, kVertexAttrib1v); 766} 767 768v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib2fvCallback(const v8::Arguments& args) 769{ 770 INC_STATS("DOM.WebGLRenderingContext.vertexAttrib2fv()"); 771 return vertexAttribAndUniformHelperf(args, kVertexAttrib2v); 772} 773 774v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib3fvCallback(const v8::Arguments& args) 775{ 776 INC_STATS("DOM.WebGLRenderingContext.vertexAttrib3fv()"); 777 return vertexAttribAndUniformHelperf(args, kVertexAttrib3v); 778} 779 780v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib4fvCallback(const v8::Arguments& args) 781{ 782 INC_STATS("DOM.WebGLRenderingContext.vertexAttrib4fv()"); 783 return vertexAttribAndUniformHelperf(args, kVertexAttrib4v); 784} 785 786} // namespace WebCore 787 788#endif // ENABLE(WEBGL) 789