57b7a52f8bd09675c42486087cdda431e5a570b3
[WebKit-https.git] / Source / WebCore / bindings / js / JSWebGLRenderingContextBaseCustom.cpp
1 /*
2  * Copyright (C) 2015-2016 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(WEBGL)
29 #include "JSWebGLRenderingContextBase.h"
30
31 #include "ANGLEInstancedArrays.h"
32 #include "EXTBlendMinMax.h"
33 #include "EXTFragDepth.h"
34 #include "EXTShaderTextureLOD.h"
35 #include "EXTTextureFilterAnisotropic.h"
36 #include "EXTsRGB.h"
37 #include "ExceptionCode.h"
38 #include "HTMLCanvasElement.h"
39 #include "HTMLImageElement.h"
40 #include "JSANGLEInstancedArrays.h"
41 #include "JSEXTBlendMinMax.h"
42 #include "JSEXTFragDepth.h"
43 #include "JSEXTShaderTextureLOD.h"
44 #include "JSEXTTextureFilterAnisotropic.h"
45 #include "JSEXTsRGB.h"
46 #include "JSHTMLCanvasElement.h"
47 #include "JSHTMLImageElement.h"
48 #include "JSImageData.h"
49 #include "JSOESElementIndexUint.h"
50 #include "JSOESStandardDerivatives.h"
51 #include "JSOESTextureFloat.h"
52 #include "JSOESTextureFloatLinear.h"
53 #include "JSOESTextureHalfFloat.h"
54 #include "JSOESTextureHalfFloatLinear.h"
55 #include "JSOESVertexArrayObject.h"
56 #include "JSWebGLBuffer.h"
57 #include "JSWebGLCompressedTextureATC.h"
58 #include "JSWebGLCompressedTexturePVRTC.h"
59 #include "JSWebGLCompressedTextureS3TC.h"
60 #include "JSWebGLDebugRendererInfo.h"
61 #include "JSWebGLDebugShaders.h"
62 #include "JSWebGLDepthTexture.h"
63 #include "JSWebGLDrawBuffers.h"
64 #include "JSWebGLFramebuffer.h"
65 #include "JSWebGLLoseContext.h"
66 #include "JSWebGLProgram.h"
67 #include "JSWebGLRenderbuffer.h"
68 #include "JSWebGLRenderingContext.h"
69 #include "JSWebGLShader.h"
70 #include "JSWebGLTexture.h"
71 #include "JSWebGLUniformLocation.h"
72 #include "JSWebGLVertexArrayObject.h"
73 #include "JSWebGLVertexArrayObjectOES.h"
74 #include "JSWebKitCSSMatrix.h"
75 #include "NotImplemented.h"
76 #include "OESElementIndexUint.h"
77 #include "OESStandardDerivatives.h"
78 #include "OESTextureFloat.h"
79 #include "OESTextureFloatLinear.h"
80 #include "OESTextureHalfFloat.h"
81 #include "OESTextureHalfFloatLinear.h"
82 #include "OESVertexArrayObject.h"
83 #include "WebGLBuffer.h"
84 #include "WebGLCompressedTextureATC.h"
85 #include "WebGLCompressedTexturePVRTC.h"
86 #include "WebGLCompressedTextureS3TC.h"
87 #include "WebGLDebugRendererInfo.h"
88 #include "WebGLDebugShaders.h"
89 #include "WebGLDepthTexture.h"
90 #include "WebGLDrawBuffers.h"
91 #include "WebGLExtension.h"
92 #include "WebGLFramebuffer.h"
93 #include "WebGLGetInfo.h"
94 #include "WebGLLoseContext.h"
95 #include "WebGLProgram.h"
96 #include "WebGLRenderingContextBase.h"
97 #include "WebGLVertexArrayObject.h"
98 #include "WebGLVertexArrayObjectOES.h"
99 #include <runtime/Error.h>
100 #include <runtime/JSObjectInlines.h>
101 #include <runtime/JSTypedArrays.h>
102 #include <runtime/TypedArrayInlines.h>
103 #include <runtime/TypedArrays.h>
104 #include <wtf/FastMalloc.h>
105
106 #if ENABLE(VIDEO)
107 #include "HTMLVideoElement.h"
108 #include "JSHTMLVideoElement.h"
109 #endif
110
111 #if ENABLE(WEBGL2)
112 #include "JSWebGL2RenderingContext.h"
113 #endif
114
115 using namespace JSC;
116
117 namespace WebCore {
118
119 JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject* globalObject, Ref<WebGLRenderingContextBase>&& object)
120 {
121 #if ENABLE(WEBGL2)
122     if (is<WebGL2RenderingContext>(object))
123         return createWrapper<WebGL2RenderingContext>(globalObject, WTFMove(object));
124 #endif
125     return createWrapper<WebGLRenderingContext>(globalObject, WTFMove(object));
126 }
127
128 JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, WebGLRenderingContextBase& object)
129 {
130     return wrap(state, globalObject, object);
131 }
132     
133 static JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, const WebGLGetInfo& info)
134 {
135     switch (info.getType()) {
136     case WebGLGetInfo::kTypeBool:
137         return jsBoolean(info.getBool());
138     case WebGLGetInfo::kTypeBoolArray: {
139         MarkedArgumentBuffer list;
140         const Vector<bool>& value = info.getBoolArray();
141         for (size_t ii = 0; ii < value.size(); ++ii)
142             list.append(jsBoolean(value[ii]));
143         return constructArray(exec, 0, globalObject, list);
144     }
145     case WebGLGetInfo::kTypeFloat:
146         return jsNumber(info.getFloat());
147     case WebGLGetInfo::kTypeInt:
148         return jsNumber(info.getInt());
149     case WebGLGetInfo::kTypeNull:
150         return jsNull();
151     case WebGLGetInfo::kTypeString:
152         return jsStringWithCache(exec, info.getString());
153     case WebGLGetInfo::kTypeUnsignedInt:
154         return jsNumber(info.getUnsignedInt());
155     case WebGLGetInfo::kTypeWebGLBuffer:
156         return toJS(exec, globalObject, info.getWebGLBuffer());
157     case WebGLGetInfo::kTypeWebGLFloatArray:
158         return toJS(exec, globalObject, info.getWebGLFloatArray());
159     case WebGLGetInfo::kTypeWebGLFramebuffer:
160         return toJS(exec, globalObject, info.getWebGLFramebuffer());
161     case WebGLGetInfo::kTypeWebGLIntArray:
162         return toJS(exec, globalObject, info.getWebGLIntArray());
163         // FIXME: implement WebGLObjectArray
164         // case WebGLGetInfo::kTypeWebGLObjectArray:
165     case WebGLGetInfo::kTypeWebGLProgram:
166         return toJS(exec, globalObject, info.getWebGLProgram());
167     case WebGLGetInfo::kTypeWebGLRenderbuffer:
168         return toJS(exec, globalObject, info.getWebGLRenderbuffer());
169     case WebGLGetInfo::kTypeWebGLTexture:
170         return toJS(exec, globalObject, info.getWebGLTexture());
171     case WebGLGetInfo::kTypeWebGLUnsignedByteArray:
172         return toJS(exec, globalObject, info.getWebGLUnsignedByteArray());
173     case WebGLGetInfo::kTypeWebGLUnsignedIntArray:
174         return toJS(exec, globalObject, info.getWebGLUnsignedIntArray());
175 #if ENABLE(WEBGL2)
176     case WebGLGetInfo::kTypeWebGLVertexArrayObject:
177         return toJS(exec, globalObject, info.getWebGLVertexArrayObject());
178 #endif
179     case WebGLGetInfo::kTypeWebGLVertexArrayObjectOES:
180         return toJS(exec, globalObject, info.getWebGLVertexArrayObjectOES());
181     default:
182         notImplemented();
183         return jsUndefined();
184     }
185 }
186
187 enum ObjectType {
188     kBuffer, kRenderbuffer, kTexture, kVertexAttrib
189 };
190
191 static JSValue getObjectParameter(JSWebGLRenderingContextBase* obj, ExecState& state, ObjectType objectType)
192 {
193     VM& vm = state.vm();
194     auto scope = DECLARE_THROW_SCOPE(vm);
195
196     if (state.argumentCount() != 2)
197         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
198     
199     ExceptionCode ec = 0;
200     WebGLRenderingContextBase& context = obj->wrapped();
201     unsigned target = state.uncheckedArgument(0).toInt32(&state);
202     RETURN_IF_EXCEPTION(scope, JSValue());
203     unsigned pname = state.uncheckedArgument(1).toInt32(&state);
204     RETURN_IF_EXCEPTION(scope, JSValue());
205     WebGLGetInfo info;
206     switch (objectType) {
207     case kBuffer:
208         info = context.getBufferParameter(target, pname);
209         break;
210     case kRenderbuffer:
211         info = context.getRenderbufferParameter(target, pname);
212         break;
213     case kTexture:
214         info = context.getTexParameter(target, pname);
215         break;
216     case kVertexAttrib:
217         // target => index
218         info = context.getVertexAttrib(target, pname);
219         break;
220     default:
221         notImplemented();
222         break;
223     }
224     if (ec) {
225         setDOMException(&state, ec);
226         return jsUndefined();
227     }
228     return toJS(&state, obj->globalObject(), info);
229 }
230
231 enum WhichProgramCall {
232     kProgramParameter, kUniform
233 };
234
235 static JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, WebGLExtension* extension)
236 {
237     if (!extension)
238         return jsNull();
239     switch (extension->getName()) {
240     case WebGLExtension::WebGLLoseContextName:
241         return toJS(exec, globalObject, static_cast<WebGLLoseContext*>(extension));
242     case WebGLExtension::EXTShaderTextureLODName:
243         return toJS(exec, globalObject, static_cast<EXTShaderTextureLOD*>(extension));
244     case WebGLExtension::EXTTextureFilterAnisotropicName:
245         return toJS(exec, globalObject, static_cast<EXTTextureFilterAnisotropic*>(extension));
246     case WebGLExtension::EXTsRGBName:
247         return toJS(exec, globalObject, static_cast<EXTsRGB*>(extension));
248     case WebGLExtension::EXTFragDepthName:
249         return toJS(exec, globalObject, static_cast<EXTFragDepth*>(extension));
250     case WebGLExtension::EXTBlendMinMaxName:
251         return toJS(exec, globalObject, static_cast<EXTBlendMinMax*>(extension));
252     case WebGLExtension::OESStandardDerivativesName:
253         return toJS(exec, globalObject, static_cast<OESStandardDerivatives*>(extension));
254     case WebGLExtension::OESTextureFloatName:
255         return toJS(exec, globalObject, static_cast<OESTextureFloat*>(extension));
256     case WebGLExtension::OESTextureFloatLinearName:
257         return toJS(exec, globalObject, static_cast<OESTextureFloatLinear*>(extension));
258     case WebGLExtension::OESTextureHalfFloatName:
259         return toJS(exec, globalObject, static_cast<OESTextureHalfFloat*>(extension));
260     case WebGLExtension::OESTextureHalfFloatLinearName:
261         return toJS(exec, globalObject, static_cast<OESTextureHalfFloatLinear*>(extension));
262     case WebGLExtension::OESVertexArrayObjectName:
263         return toJS(exec, globalObject, static_cast<OESVertexArrayObject*>(extension));
264     case WebGLExtension::OESElementIndexUintName:
265         return toJS(exec, globalObject, static_cast<OESElementIndexUint*>(extension));
266     case WebGLExtension::WebGLDebugRendererInfoName:
267         return toJS(exec, globalObject, static_cast<WebGLDebugRendererInfo*>(extension));
268     case WebGLExtension::WebGLDebugShadersName:
269         return toJS(exec, globalObject, static_cast<WebGLDebugShaders*>(extension));
270     case WebGLExtension::WebGLCompressedTextureATCName:
271         return toJS(exec, globalObject, static_cast<WebGLCompressedTextureATC*>(extension));
272     case WebGLExtension::WebGLCompressedTexturePVRTCName:
273         return toJS(exec, globalObject, static_cast<WebGLCompressedTexturePVRTC*>(extension));
274     case WebGLExtension::WebGLCompressedTextureS3TCName:
275         return toJS(exec, globalObject, static_cast<WebGLCompressedTextureS3TC*>(extension));
276     case WebGLExtension::WebGLDepthTextureName:
277         return toJS(exec, globalObject, static_cast<WebGLDepthTexture*>(extension));
278     case WebGLExtension::WebGLDrawBuffersName:
279         return toJS(exec, globalObject, static_cast<WebGLDrawBuffers*>(extension));
280     case WebGLExtension::ANGLEInstancedArraysName:
281         return toJS(exec, globalObject, static_cast<ANGLEInstancedArrays*>(extension));
282     }
283     ASSERT_NOT_REACHED();
284     return jsNull();
285 }
286
287 bool JSWebGLRenderingContextBaseOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
288 {
289     JSWebGLRenderingContextBase* jsWebGLRenderingContext = jsCast<JSWebGLRenderingContextBase*>(handle.slot()->asCell());
290     void* root = WebCore::root(jsWebGLRenderingContext->wrapped().canvas());
291     return visitor.containsOpaqueRoot(root);
292 }
293
294 void JSWebGLRenderingContextBase::visitAdditionalChildren(SlotVisitor& visitor)
295 {
296     visitor.addOpaqueRoot(&wrapped());
297     visitor.addOpaqueRoot(root(wrapped().canvas()));
298 }
299
300 JSValue JSWebGLRenderingContextBase::getAttachedShaders(ExecState& state)
301 {
302     VM& vm = state.vm();
303     auto scope = DECLARE_THROW_SCOPE(vm);
304
305     if (state.argumentCount() < 1)
306         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
307     ExceptionCode ec = 0;
308     WebGLRenderingContextBase& context = wrapped();
309     WebGLProgram* program = JSWebGLProgram::toWrapped(state.uncheckedArgument(0));
310     if (!program && !state.uncheckedArgument(0).isUndefinedOrNull())
311         return throwTypeError(&state, scope);
312     Vector<RefPtr<WebGLShader>> shaders;
313     bool succeed = context.getAttachedShaders(program, shaders);
314     if (ec) {
315         setDOMException(&state, ec);
316         return jsNull();
317     }
318     if (!succeed)
319         return jsNull();
320     JSC::MarkedArgumentBuffer list;
321     for (size_t ii = 0; ii < shaders.size(); ++ii)
322         list.append(toJS(&state, globalObject(), shaders[ii].get()));
323     return constructArray(&state, 0, globalObject(), list);
324 }
325
326 JSValue JSWebGLRenderingContextBase::getExtension(ExecState& state)
327 {
328     VM& vm = state.vm();
329     auto scope = DECLARE_THROW_SCOPE(vm);
330
331     if (state.argumentCount() < 1)
332         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
333     
334     WebGLRenderingContextBase& context = wrapped();
335     const String name = state.uncheckedArgument(0).toString(&state)->value(&state);
336     RETURN_IF_EXCEPTION(scope, JSValue());
337     WebGLExtension* extension = context.getExtension(name);
338     return toJS(&state, globalObject(), extension);
339 }
340
341 JSValue JSWebGLRenderingContextBase::getBufferParameter(ExecState& state)
342 {
343     return getObjectParameter(this, state, kBuffer);
344 }
345
346 JSValue JSWebGLRenderingContextBase::getFramebufferAttachmentParameter(ExecState& state)
347 {
348     VM& vm = state.vm();
349     auto scope = DECLARE_THROW_SCOPE(vm);
350
351     if (state.argumentCount() != 3)
352         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
353     
354     ExceptionCode ec = 0;
355     WebGLRenderingContextBase& context = wrapped();
356     unsigned target = state.uncheckedArgument(0).toInt32(&state);
357     RETURN_IF_EXCEPTION(scope, JSValue());
358     unsigned attachment = state.uncheckedArgument(1).toInt32(&state);
359     RETURN_IF_EXCEPTION(scope, JSValue());
360     unsigned pname = state.uncheckedArgument(2).toInt32(&state);
361     RETURN_IF_EXCEPTION(scope, JSValue());
362     WebGLGetInfo info = context.getFramebufferAttachmentParameter(target, attachment, pname, ec);
363     if (ec) {
364         setDOMException(&state, ec);
365         return jsUndefined();
366     }
367     return toJS(&state, globalObject(), info);
368 }
369
370 JSValue JSWebGLRenderingContextBase::getParameter(ExecState& state)
371 {
372     VM& vm = state.vm();
373     auto scope = DECLARE_THROW_SCOPE(vm);
374
375     if (state.argumentCount() != 1)
376         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
377     
378     ExceptionCode ec = 0;
379     WebGLRenderingContextBase& context = wrapped();
380     unsigned pname = state.uncheckedArgument(0).toInt32(&state);
381     RETURN_IF_EXCEPTION(scope, JSValue());
382     WebGLGetInfo info = context.getParameter(pname, ec);
383     if (ec) {
384         setDOMException(&state, ec);
385         return jsUndefined();
386     }
387     return toJS(&state, globalObject(), info);
388 }
389
390 JSValue JSWebGLRenderingContextBase::getProgramParameter(ExecState& state)
391 {
392     VM& vm = state.vm();
393     auto scope = DECLARE_THROW_SCOPE(vm);
394
395     if (state.argumentCount() != 2)
396         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
397     
398     ExceptionCode ec = 0;
399     WebGLRenderingContextBase& context = wrapped();
400     WebGLProgram* program = JSWebGLProgram::toWrapped(state.uncheckedArgument(0));
401     if (!program && !state.uncheckedArgument(0).isUndefinedOrNull())
402         return throwTypeError(&state, scope);
403     unsigned pname = state.uncheckedArgument(1).toInt32(&state);
404     RETURN_IF_EXCEPTION(scope, JSValue());
405     WebGLGetInfo info = context.getProgramParameter(program, pname);
406     if (ec) {
407         setDOMException(&state, ec);
408         return jsUndefined();
409     }
410     return toJS(&state, globalObject(), info);
411 }
412
413 JSValue JSWebGLRenderingContextBase::getRenderbufferParameter(ExecState& state)
414 {
415     return getObjectParameter(this, state, kRenderbuffer);
416 }
417
418 JSValue JSWebGLRenderingContextBase::getShaderParameter(ExecState& state)
419 {
420     VM& vm = state.vm();
421     auto scope = DECLARE_THROW_SCOPE(vm);
422
423     if (state.argumentCount() != 2)
424         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
425     
426     ExceptionCode ec = 0;
427     WebGLRenderingContextBase& context = wrapped();
428     if (!state.uncheckedArgument(0).isUndefinedOrNull() && !state.uncheckedArgument(0).inherits(JSWebGLShader::info()))
429         return throwTypeError(&state, scope);
430     WebGLShader* shader = JSWebGLShader::toWrapped(state.uncheckedArgument(0));
431     unsigned pname = state.uncheckedArgument(1).toInt32(&state);
432     RETURN_IF_EXCEPTION(scope, JSValue());
433     WebGLGetInfo info = context.getShaderParameter(shader, pname);
434     if (ec) {
435         setDOMException(&state, ec);
436         return jsUndefined();
437     }
438     return toJS(&state, globalObject(), info);
439 }
440
441 JSValue JSWebGLRenderingContextBase::getSupportedExtensions(ExecState& state)
442 {
443     WebGLRenderingContextBase& context = wrapped();
444     if (context.isContextLost())
445         return jsNull();
446     Vector<String> value = context.getSupportedExtensions();
447     MarkedArgumentBuffer list;
448     for (size_t ii = 0; ii < value.size(); ++ii)
449         list.append(jsStringWithCache(&state, value[ii]));
450     return constructArray(&state, 0, globalObject(), list);
451 }
452
453 JSValue JSWebGLRenderingContextBase::getTexParameter(ExecState& state)
454 {
455     return getObjectParameter(this, state, kTexture);
456 }
457
458 JSValue JSWebGLRenderingContextBase::getUniform(ExecState& state)
459 {
460     VM& vm = state.vm();
461     auto scope = DECLARE_THROW_SCOPE(vm);
462
463     if (state.argumentCount() != 2)
464         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
465     
466     ExceptionCode ec = 0;
467     WebGLRenderingContextBase& context = wrapped();
468     WebGLProgram* program = JSWebGLProgram::toWrapped(state.uncheckedArgument(0));
469     if (!program && !state.uncheckedArgument(0).isUndefinedOrNull())
470         return throwTypeError(&state, scope);
471     WebGLUniformLocation* location = JSWebGLUniformLocation::toWrapped(state.uncheckedArgument(1));
472     if (!location && !state.uncheckedArgument(1).isUndefinedOrNull())
473         return throwTypeError(&state, scope);
474     WebGLGetInfo info = context.getUniform(program, location);
475     if (ec) {
476         setDOMException(&state, ec);
477         return jsUndefined();
478     }
479     return toJS(&state, globalObject(), info);
480 }
481
482 JSValue JSWebGLRenderingContextBase::getVertexAttrib(ExecState& state)
483 {
484     return getObjectParameter(this, state, kVertexAttrib);
485 }
486
487 template<typename T, size_t inlineCapacity>
488 bool toVector(JSC::ExecState& state, JSC::JSValue value, Vector<T, inlineCapacity>& vector)
489 {
490     VM& vm = state.vm();
491     auto scope = DECLARE_THROW_SCOPE(vm);
492
493     if (!value.isObject())
494         return false;
495     
496     JSC::JSObject* object = asObject(value);
497     int32_t length = object->get(&state, state.vm().propertyNames->length).toInt32(&state);
498     
499     if (!vector.tryReserveCapacity(length))
500         return false;
501     vector.resize(length);
502     
503     for (int32_t i = 0; i < length; ++i) {
504         JSC::JSValue v = object->get(&state, i);
505         RETURN_IF_EXCEPTION(scope, false);
506         vector[i] = static_cast<T>(v.toNumber(&state));
507     }
508     
509     return true;
510 }
511
512 enum DataFunctionToCall {
513     f_uniform1v, f_uniform2v, f_uniform3v, f_uniform4v,
514     f_vertexAttrib1v, f_vertexAttrib2v, f_vertexAttrib3v, f_vertexAttrib4v
515 };
516
517 enum DataFunctionMatrixToCall {
518     f_uniformMatrix2fv, f_uniformMatrix3fv, f_uniformMatrix4fv
519 };
520
521 static bool functionForUniform(DataFunctionToCall f)
522 {
523     switch (f) {
524     case f_uniform1v:
525     case f_uniform2v:
526     case f_uniform3v:
527     case f_uniform4v:
528         return true;
529     default: break;
530     }
531     return false;
532 }
533
534 static JSC::JSValue dataFunctionf(DataFunctionToCall f, JSC::ExecState& state, WebGLRenderingContextBase& context)
535 {
536     VM& vm = state.vm();
537     auto scope = DECLARE_THROW_SCOPE(vm);
538
539     if (state.argumentCount() != 2)
540         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
541     
542     WebGLUniformLocation* location = 0;
543     long index = -1;
544     
545     if (functionForUniform(f)) {
546         location = JSWebGLUniformLocation::toWrapped(state.uncheckedArgument(0));
547         if (!location && !state.uncheckedArgument(0).isUndefinedOrNull())
548             return throwTypeError(&state, scope);
549     } else
550         index = state.uncheckedArgument(0).toInt32(&state);
551     
552     RETURN_IF_EXCEPTION(scope, JSValue());
553     
554     RefPtr<Float32Array> webGLArray = toFloat32Array(state.uncheckedArgument(1));
555     RETURN_IF_EXCEPTION(scope, JSValue());
556     
557     ExceptionCode ec = 0;
558     if (webGLArray) {
559         switch (f) {
560         case f_uniform1v:
561             context.uniform1fv(location, *webGLArray);
562             break;
563         case f_uniform2v:
564             context.uniform2fv(location, *webGLArray);
565             break;
566         case f_uniform3v:
567             context.uniform3fv(location, *webGLArray);
568             break;
569         case f_uniform4v:
570             context.uniform4fv(location, *webGLArray);
571             break;
572         case f_vertexAttrib1v:
573             context.vertexAttrib1fv(index, *webGLArray);
574             break;
575         case f_vertexAttrib2v:
576             context.vertexAttrib2fv(index, *webGLArray);
577             break;
578         case f_vertexAttrib3v:
579             context.vertexAttrib3fv(index, *webGLArray);
580             break;
581         case f_vertexAttrib4v:
582             context.vertexAttrib4fv(index, *webGLArray);
583             break;
584         }
585         
586         setDOMException(&state, ec);
587         return jsUndefined();
588     }
589     
590     Vector<float, 64> array;
591     if (!toVector(state, state.uncheckedArgument(1), array))
592         return throwTypeError(&state, scope);
593     
594     switch (f) {
595     case f_uniform1v:
596         context.uniform1fv(location, array.data(), array.size());
597         break;
598     case f_uniform2v:
599         context.uniform2fv(location, array.data(), array.size());
600         break;
601     case f_uniform3v:
602         context.uniform3fv(location, array.data(), array.size());
603         break;
604     case f_uniform4v:
605         context.uniform4fv(location, array.data(), array.size());
606         break;
607     case f_vertexAttrib1v:
608         context.vertexAttrib1fv(index, array.data(), array.size());
609         break;
610     case f_vertexAttrib2v:
611         context.vertexAttrib2fv(index, array.data(), array.size());
612         break;
613     case f_vertexAttrib3v:
614         context.vertexAttrib3fv(index, array.data(), array.size());
615         break;
616     case f_vertexAttrib4v:
617         context.vertexAttrib4fv(index, array.data(), array.size());
618         break;
619     }
620     
621     setDOMException(&state, ec);
622     return jsUndefined();
623 }
624
625 static JSC::JSValue dataFunctioni(DataFunctionToCall f, JSC::ExecState& state, WebGLRenderingContextBase& context)
626 {
627     VM& vm = state.vm();
628     auto scope = DECLARE_THROW_SCOPE(vm);
629
630     if (state.argumentCount() != 2)
631         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
632     
633     WebGLUniformLocation* location = JSWebGLUniformLocation::toWrapped(state.uncheckedArgument(0));
634     if (!location && !state.uncheckedArgument(0).isUndefinedOrNull())
635         return throwTypeError(&state, scope);
636     
637     RefPtr<Int32Array> webGLArray = toInt32Array(state.uncheckedArgument(1));
638     
639     ExceptionCode ec = 0;
640     if (webGLArray) {
641         switch (f) {
642         case f_uniform1v:
643             context.uniform1iv(location, *webGLArray);
644             break;
645         case f_uniform2v:
646             context.uniform2iv(location, *webGLArray);
647             break;
648         case f_uniform3v:
649             context.uniform3iv(location, *webGLArray);
650             break;
651         case f_uniform4v:
652             context.uniform4iv(location, *webGLArray);
653             break;
654         default:
655             break;
656         }
657         
658         setDOMException(&state, ec);
659         return jsUndefined();
660     }
661     
662     
663     Vector<int, 64> array;
664     if (!toVector(state, state.uncheckedArgument(1), array))
665         return throwTypeError(&state, scope);
666     
667     switch (f) {
668     case f_uniform1v:
669         context.uniform1iv(location, array.data(), array.size());
670         break;
671     case f_uniform2v:
672         context.uniform2iv(location, array.data(), array.size());
673         break;
674     case f_uniform3v:
675         context.uniform3iv(location, array.data(), array.size());
676         break;
677     case f_uniform4v:
678         context.uniform4iv(location, array.data(), array.size());
679         break;
680     default:
681         break;
682     }
683     
684     setDOMException(&state, ec);
685     return jsUndefined();
686 }
687
688 static JSC::JSValue dataFunctionMatrix(DataFunctionMatrixToCall f, JSC::ExecState& state, WebGLRenderingContextBase& context)
689 {
690     VM& vm = state.vm();
691     auto scope = DECLARE_THROW_SCOPE(vm);
692
693     if (state.argumentCount() != 3)
694         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
695     
696     WebGLUniformLocation* location = JSWebGLUniformLocation::toWrapped(state.uncheckedArgument(0));
697     if (!location && !state.uncheckedArgument(0).isUndefinedOrNull())
698         return throwTypeError(&state, scope);
699     
700     bool transpose = state.uncheckedArgument(1).toBoolean(&state);
701     RETURN_IF_EXCEPTION(scope, JSValue());
702     
703     RefPtr<Float32Array> webGLArray = toFloat32Array(state.uncheckedArgument(2));
704
705     if (webGLArray) {
706         switch (f) {
707         case f_uniformMatrix2fv:
708             context.uniformMatrix2fv(location, transpose, *webGLArray);
709             break;
710         case f_uniformMatrix3fv:
711             context.uniformMatrix3fv(location, transpose, *webGLArray);
712             break;
713         case f_uniformMatrix4fv:
714             context.uniformMatrix4fv(location, transpose, *webGLArray);
715             break;
716         }
717
718         ExceptionCode ec = 0;
719         setDOMException(&state, ec);
720         return jsUndefined();
721     }
722     
723     Vector<float, 64> array;
724     if (!toVector(state, state.uncheckedArgument(2), array))
725         return throwTypeError(&state, scope);
726     
727     switch (f) {
728     case f_uniformMatrix2fv:
729         context.uniformMatrix2fv(location, transpose, array.data(), array.size());
730         break;
731     case f_uniformMatrix3fv:
732         context.uniformMatrix3fv(location, transpose, array.data(), array.size());
733         break;
734     case f_uniformMatrix4fv:
735         context.uniformMatrix4fv(location, transpose, array.data(), array.size());
736         break;
737     }
738
739     ExceptionCode ec = 0;
740     setDOMException(&state, ec);
741     return jsUndefined();
742 }
743
744 JSC::JSValue JSWebGLRenderingContextBase::uniform1fv(JSC::ExecState& state)
745 {
746     return dataFunctionf(f_uniform1v, state, wrapped());
747 }
748
749 JSC::JSValue JSWebGLRenderingContextBase::uniform1iv(JSC::ExecState& state)
750 {
751     return dataFunctioni(f_uniform1v, state, wrapped());
752 }
753
754 JSC::JSValue JSWebGLRenderingContextBase::uniform2fv(JSC::ExecState& state)
755 {
756     return dataFunctionf(f_uniform2v, state, wrapped());
757 }
758
759 JSC::JSValue JSWebGLRenderingContextBase::uniform2iv(JSC::ExecState& state)
760 {
761     return dataFunctioni(f_uniform2v, state, wrapped());
762 }
763
764 JSC::JSValue JSWebGLRenderingContextBase::uniform3fv(JSC::ExecState& state)
765 {
766     return dataFunctionf(f_uniform3v, state, wrapped());
767 }
768
769 JSC::JSValue JSWebGLRenderingContextBase::uniform3iv(JSC::ExecState& state)
770 {
771     return dataFunctioni(f_uniform3v, state, wrapped());
772 }
773
774 JSC::JSValue JSWebGLRenderingContextBase::uniform4fv(JSC::ExecState& state)
775 {
776     return dataFunctionf(f_uniform4v, state, wrapped());
777 }
778
779 JSC::JSValue JSWebGLRenderingContextBase::uniform4iv(JSC::ExecState& state)
780 {
781     return dataFunctioni(f_uniform4v, state, wrapped());
782 }
783
784 JSC::JSValue JSWebGLRenderingContextBase::uniformMatrix2fv(JSC::ExecState& state)
785 {
786     return dataFunctionMatrix(f_uniformMatrix2fv, state, wrapped());
787 }
788
789 JSC::JSValue JSWebGLRenderingContextBase::uniformMatrix3fv(JSC::ExecState& state)
790 {
791     return dataFunctionMatrix(f_uniformMatrix3fv, state, wrapped());
792 }
793
794 JSC::JSValue JSWebGLRenderingContextBase::uniformMatrix4fv(JSC::ExecState& state)
795 {
796     return dataFunctionMatrix(f_uniformMatrix4fv, state, wrapped());
797 }
798
799 JSC::JSValue JSWebGLRenderingContextBase::vertexAttrib1fv(JSC::ExecState& state)
800 {
801     return dataFunctionf(f_vertexAttrib1v, state, wrapped());
802 }
803
804 JSC::JSValue JSWebGLRenderingContextBase::vertexAttrib2fv(JSC::ExecState& state)
805 {
806     return dataFunctionf(f_vertexAttrib2v, state, wrapped());
807 }
808
809 JSC::JSValue JSWebGLRenderingContextBase::vertexAttrib3fv(JSC::ExecState& state)
810 {
811     return dataFunctionf(f_vertexAttrib3v, state, wrapped());
812 }
813
814 JSC::JSValue JSWebGLRenderingContextBase::vertexAttrib4fv(JSC::ExecState& state)
815 {
816     return dataFunctionf(f_vertexAttrib4v, state, wrapped());
817 }
818
819 } // namespace WebCore
820
821 #endif // ENABLE(WEBGL)