1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Mozilla Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2009
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Vladimir Vukicevic <vladimir@pobox.com> (original author)
24 : * Mark Steele <mwsteele@gmail.com>
25 : * Cedric Vivier <cedricv@neonux.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "WebGLContext.h"
42 :
43 : #include "nsString.h"
44 : #include "nsDebug.h"
45 :
46 : #include "gfxImageSurface.h"
47 : #include "gfxContext.h"
48 : #include "gfxPlatform.h"
49 : //#include "nsIDOMHTMLCanvasElement.h"
50 :
51 : #include "nsContentUtils.h"
52 : #include "nsDOMError.h"
53 : #include "nsLayoutUtils.h"
54 :
55 : #include "CanvasUtils.h"
56 :
57 : #include "jstypedarray.h"
58 :
59 : #if defined(USE_ANGLE)
60 : // shader translator
61 : #include "angle/ShaderLang.h"
62 : #endif
63 :
64 : #include "WebGLTexelConversions.h"
65 : #include "WebGLValidateStrings.h"
66 :
67 : // needed to check if current OS is lower than 10.7
68 : #if defined(MOZ_WIDGET_COCOA)
69 : #include "nsCocoaFeatures.h"
70 : #endif
71 :
72 : using namespace mozilla;
73 : using namespace mozilla::dom;
74 :
75 : static bool BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *unitSize);
76 : static WebGLenum InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2);
77 :
78 : /* Helper macros for when we're just wrapping a gl method, so that
79 : * we can avoid having to type this 500 times. Note that these MUST
80 : * NOT BE USED if we need to check any of the parameters.
81 : */
82 :
83 : #define GL_SAME_METHOD_0(glname, name) \
84 : NS_IMETHODIMP WebGLContext::name() { \
85 : if (!IsContextStable()) { return NS_OK; } \
86 : MakeContextCurrent(); gl->f##glname(); return NS_OK; \
87 : }
88 :
89 : #define GL_SAME_METHOD_1(glname, name, t1) \
90 : NS_IMETHODIMP WebGLContext::name(t1 a1) { \
91 : if (!IsContextStable()) { return NS_OK; } \
92 : MakeContextCurrent(); gl->f##glname(a1); return NS_OK; \
93 : }
94 :
95 : #define GL_SAME_METHOD_2(glname, name, t1, t2) \
96 : NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2) { \
97 : if (!IsContextStable()) { return NS_OK; } \
98 : MakeContextCurrent(); gl->f##glname(a1,a2); return NS_OK; \
99 : }
100 :
101 : #define GL_SAME_METHOD_3(glname, name, t1, t2, t3) \
102 : NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3) { \
103 : if (!IsContextStable()) { return NS_OK; } \
104 : MakeContextCurrent(); gl->f##glname(a1,a2,a3); return NS_OK; \
105 : }
106 :
107 : #define GL_SAME_METHOD_4(glname, name, t1, t2, t3, t4) \
108 : NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4) { \
109 : if (!IsContextStable()) { return NS_OK; } \
110 : MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4); return NS_OK; \
111 : }
112 :
113 : #define GL_SAME_METHOD_5(glname, name, t1, t2, t3, t4, t5) \
114 : NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) { \
115 : if (!IsContextStable()) { return NS_OK; } \
116 : MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4,a5); return NS_OK; \
117 : }
118 :
119 : #define GL_SAME_METHOD_6(glname, name, t1, t2, t3, t4, t5, t6) \
120 : NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) { \
121 : if (!IsContextStable()) { return NS_OK; } \
122 : MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4,a5,a6); return NS_OK; \
123 : }
124 :
125 : //
126 : // WebGL API
127 : //
128 :
129 :
130 : /* void GlActiveTexture (in GLenum texture); */
131 : NS_IMETHODIMP
132 0 : WebGLContext::ActiveTexture(WebGLenum texture)
133 : {
134 0 : if (!IsContextStable())
135 0 : return NS_OK;
136 :
137 0 : if (texture < LOCAL_GL_TEXTURE0 || texture >= LOCAL_GL_TEXTURE0 + mBound2DTextures.Length())
138 : return ErrorInvalidEnum("ActiveTexture: texture unit %d out of range (0..%d)",
139 0 : texture, mBound2DTextures.Length()-1);
140 :
141 0 : MakeContextCurrent();
142 0 : mActiveTexture = texture - LOCAL_GL_TEXTURE0;
143 0 : gl->fActiveTexture(texture);
144 0 : return NS_OK;
145 : }
146 :
147 : NS_IMETHODIMP
148 0 : WebGLContext::AttachShader(nsIWebGLProgram *pobj, nsIWebGLShader *shobj)
149 : {
150 0 : if (!IsContextStable())
151 0 : return NS_OK;
152 :
153 : // if pobj or shobj are null/not specified, it's an error
154 0 : if (pobj == nsnull || shobj == nsnull)
155 0 : return ErrorInvalidValue("attachShader");
156 :
157 : WebGLuint progname, shadername;
158 : WebGLProgram *program;
159 : WebGLShader *shader;
160 0 : if (!GetConcreteObjectAndGLName("attachShader: program", pobj, &program, &progname) ||
161 0 : !GetConcreteObjectAndGLName("attachShader: shader", shobj, &shader, &shadername))
162 0 : return NS_OK;
163 :
164 : // Per GLSL ES 2.0, we can only have one of each type of shader
165 : // attached. This renders the next test somewhat moot, but we'll
166 : // leave it for when we support more than one shader of each type.
167 0 : if (program->HasAttachedShaderOfType(shader->ShaderType()))
168 0 : return ErrorInvalidOperation("AttachShader: only one of each type of shader may be attached to a program");
169 :
170 0 : if (!program->AttachShader(shader))
171 0 : return ErrorInvalidOperation("AttachShader: shader is already attached");
172 :
173 0 : return NS_OK;
174 : }
175 :
176 :
177 : NS_IMETHODIMP
178 0 : WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, const nsAString& name)
179 : {
180 0 : if (!IsContextStable())
181 0 : return NS_OK;
182 :
183 : WebGLuint progname;
184 : WebGLProgram *prog;
185 0 : if (!GetConcreteObjectAndGLName("bindAttribLocation: program", pobj, &prog, &progname))
186 0 : return NS_OK;
187 :
188 0 : if (!ValidateGLSLVariableName(name, "bindAttribLocation"))
189 0 : return NS_OK;
190 :
191 0 : if (!ValidateAttribIndex(location, "bindAttribLocation"))
192 0 : return NS_OK;
193 :
194 0 : NS_LossyConvertUTF16toASCII cname(name);
195 0 : nsCString mappedName;
196 0 : prog->MapIdentifier(cname, &mappedName);
197 :
198 0 : MakeContextCurrent();
199 0 : gl->fBindAttribLocation(progname, location, mappedName.get());
200 0 : return NS_OK;
201 : }
202 :
203 : NS_IMETHODIMP
204 0 : WebGLContext::BindBuffer(WebGLenum target, nsIWebGLBuffer *bobj)
205 : {
206 : WebGLuint bufname;
207 : WebGLBuffer* buf;
208 : bool isNull; // allow null objects
209 : bool isDeleted; // allow deleted objects
210 0 : if (!GetConcreteObjectAndGLName("bindBuffer", bobj, &buf, &bufname, &isNull, &isDeleted))
211 0 : return NS_OK;
212 :
213 : // silently ignore a deleted buffer
214 0 : if (isDeleted)
215 0 : return NS_OK;
216 :
217 0 : if (target != LOCAL_GL_ARRAY_BUFFER &&
218 : target != LOCAL_GL_ELEMENT_ARRAY_BUFFER)
219 : {
220 0 : return ErrorInvalidEnumInfo("bindBuffer: target", target);
221 : }
222 :
223 0 : if (!isNull) {
224 0 : if ((buf->Target() != LOCAL_GL_NONE) && (target != buf->Target()))
225 0 : return ErrorInvalidOperation("BindBuffer: buffer already bound to a different target");
226 0 : buf->SetTarget(target);
227 0 : buf->SetHasEverBeenBound(true);
228 : }
229 :
230 : // we really want to do this AFTER all the validation is done, otherwise our bookkeeping could get confused.
231 : // see bug 656752
232 0 : if (target == LOCAL_GL_ARRAY_BUFFER) {
233 0 : mBoundArrayBuffer = buf;
234 0 : } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
235 0 : mBoundElementArrayBuffer = buf;
236 : }
237 :
238 0 : MakeContextCurrent();
239 :
240 0 : gl->fBindBuffer(target, bufname);
241 :
242 0 : return NS_OK;
243 : }
244 :
245 : NS_IMETHODIMP
246 0 : WebGLContext::BindFramebuffer(WebGLenum target, nsIWebGLFramebuffer *fbobj)
247 : {
248 : WebGLuint framebuffername;
249 : bool isNull; // allow null objects
250 : bool isDeleted; // allow deleted objects
251 : WebGLFramebuffer *wfb;
252 :
253 0 : if (target != LOCAL_GL_FRAMEBUFFER)
254 0 : return ErrorInvalidEnum("BindFramebuffer: target must be GL_FRAMEBUFFER");
255 :
256 0 : if (!GetConcreteObjectAndGLName("bindFramebuffer", fbobj, &wfb, &framebuffername, &isNull, &isDeleted))
257 0 : return NS_OK;
258 :
259 : // silently ignore a deleted frame buffer
260 0 : if (isDeleted)
261 0 : return NS_OK;
262 :
263 0 : MakeContextCurrent();
264 :
265 0 : if (isNull) {
266 0 : gl->fBindFramebuffer(target, gl->GetOffscreenFBO());
267 : } else {
268 0 : gl->fBindFramebuffer(target, framebuffername);
269 0 : wfb->SetHasEverBeenBound(true);
270 : }
271 :
272 0 : mBoundFramebuffer = wfb;
273 :
274 0 : return NS_OK;
275 : }
276 :
277 : NS_IMETHODIMP
278 0 : WebGLContext::BindRenderbuffer(WebGLenum target, nsIWebGLRenderbuffer *rbobj)
279 : {
280 : WebGLuint renderbuffername;
281 : bool isNull; // allow null objects
282 : bool isDeleted; // allow deleted objects
283 : WebGLRenderbuffer *wrb;
284 :
285 0 : if (target != LOCAL_GL_RENDERBUFFER)
286 0 : return ErrorInvalidEnumInfo("bindRenderbuffer: target", target);
287 :
288 0 : if (!GetConcreteObjectAndGLName("bindRenderBuffer", rbobj, &wrb, &renderbuffername, &isNull, &isDeleted))
289 0 : return NS_OK;
290 :
291 : // silently ignore a deleted buffer
292 0 : if (isDeleted)
293 0 : return NS_OK;
294 :
295 0 : if (!isNull)
296 0 : wrb->SetHasEverBeenBound(true);
297 :
298 0 : MakeContextCurrent();
299 :
300 0 : gl->fBindRenderbuffer(target, renderbuffername);
301 :
302 0 : mBoundRenderbuffer = wrb;
303 :
304 0 : return NS_OK;
305 : }
306 :
307 : NS_IMETHODIMP
308 0 : WebGLContext::BindTexture(WebGLenum target, nsIWebGLTexture *tobj)
309 : {
310 : WebGLuint texturename;
311 : WebGLTexture *tex;
312 : bool isNull; // allow null objects
313 : bool isDeleted; // allow deleted objects
314 0 : if (!GetConcreteObjectAndGLName("bindTexture", tobj, &tex, &texturename, &isNull, &isDeleted))
315 0 : return NS_OK;
316 :
317 : // silently ignore a deleted texture
318 0 : if (isDeleted)
319 0 : return NS_OK;
320 :
321 0 : if (target == LOCAL_GL_TEXTURE_2D) {
322 0 : mBound2DTextures[mActiveTexture] = tex;
323 0 : } else if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
324 0 : mBoundCubeMapTextures[mActiveTexture] = tex;
325 : } else {
326 0 : return ErrorInvalidEnumInfo("bindTexture: target", target);
327 : }
328 :
329 0 : MakeContextCurrent();
330 :
331 0 : if (tex)
332 0 : tex->Bind(target);
333 : else
334 0 : gl->fBindTexture(target, 0 /* == texturename */);
335 :
336 0 : return NS_OK;
337 : }
338 :
339 0 : GL_SAME_METHOD_4(BlendColor, BlendColor, WebGLfloat, WebGLfloat, WebGLfloat, WebGLfloat)
340 :
341 0 : NS_IMETHODIMP WebGLContext::BlendEquation(WebGLenum mode)
342 : {
343 0 : if (!IsContextStable())
344 0 : return NS_OK;
345 :
346 0 : if (!ValidateBlendEquationEnum(mode, "blendEquation: mode"))
347 0 : return NS_OK;
348 :
349 0 : MakeContextCurrent();
350 0 : gl->fBlendEquation(mode);
351 0 : return NS_OK;
352 : }
353 :
354 0 : NS_IMETHODIMP WebGLContext::BlendEquationSeparate(WebGLenum modeRGB, WebGLenum modeAlpha)
355 : {
356 0 : if (!IsContextStable())
357 0 : return NS_OK;
358 :
359 0 : if (!ValidateBlendEquationEnum(modeRGB, "blendEquationSeparate: modeRGB") ||
360 0 : !ValidateBlendEquationEnum(modeAlpha, "blendEquationSeparate: modeAlpha"))
361 0 : return NS_OK;
362 :
363 0 : MakeContextCurrent();
364 0 : gl->fBlendEquationSeparate(modeRGB, modeAlpha);
365 0 : return NS_OK;
366 : }
367 :
368 0 : NS_IMETHODIMP WebGLContext::BlendFunc(WebGLenum sfactor, WebGLenum dfactor)
369 : {
370 0 : if (!IsContextStable())
371 0 : return NS_OK;
372 :
373 0 : if (!ValidateBlendFuncSrcEnum(sfactor, "blendFunc: sfactor") ||
374 0 : !ValidateBlendFuncDstEnum(dfactor, "blendFunc: dfactor"))
375 0 : return NS_OK;
376 :
377 0 : if (!ValidateBlendFuncEnumsCompatibility(sfactor, dfactor, "blendFuncSeparate: srcRGB and dstRGB"))
378 0 : return NS_OK;
379 :
380 0 : MakeContextCurrent();
381 0 : gl->fBlendFunc(sfactor, dfactor);
382 0 : return NS_OK;
383 : }
384 :
385 : NS_IMETHODIMP
386 0 : WebGLContext::BlendFuncSeparate(WebGLenum srcRGB, WebGLenum dstRGB,
387 : WebGLenum srcAlpha, WebGLenum dstAlpha)
388 : {
389 0 : if (!IsContextStable())
390 0 : return NS_OK;
391 :
392 0 : if (!ValidateBlendFuncSrcEnum(srcRGB, "blendFuncSeparate: srcRGB") ||
393 0 : !ValidateBlendFuncSrcEnum(srcAlpha, "blendFuncSeparate: srcAlpha") ||
394 0 : !ValidateBlendFuncDstEnum(dstRGB, "blendFuncSeparate: dstRGB") ||
395 0 : !ValidateBlendFuncDstEnum(dstAlpha, "blendFuncSeparate: dstAlpha"))
396 0 : return NS_OK;
397 :
398 : // note that we only check compatibity for the RGB enums, no need to for the Alpha enums, see
399 : // "Section 6.8 forgetting to mention alpha factors?" thread on the public_webgl mailing list
400 0 : if (!ValidateBlendFuncEnumsCompatibility(srcRGB, dstRGB, "blendFuncSeparate: srcRGB and dstRGB"))
401 0 : return NS_OK;
402 :
403 0 : MakeContextCurrent();
404 0 : gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
405 0 : return NS_OK;
406 : }
407 :
408 0 : GLenum WebGLContext::CheckedBufferData(GLenum target,
409 : GLsizeiptr size,
410 : const GLvoid *data,
411 : GLenum usage)
412 : {
413 0 : WebGLBuffer *boundBuffer = NULL;
414 0 : if (target == LOCAL_GL_ARRAY_BUFFER) {
415 0 : boundBuffer = mBoundArrayBuffer;
416 0 : } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
417 0 : boundBuffer = mBoundElementArrayBuffer;
418 : }
419 0 : NS_ABORT_IF_FALSE(boundBuffer != nsnull, "no buffer bound for this target");
420 :
421 0 : bool sizeChanges = PRUint32(size) != boundBuffer->ByteLength();
422 0 : if (sizeChanges) {
423 0 : UpdateWebGLErrorAndClearGLError();
424 0 : gl->fBufferData(target, size, data, usage);
425 0 : GLenum error = LOCAL_GL_NO_ERROR;
426 0 : UpdateWebGLErrorAndClearGLError(&error);
427 0 : return error;
428 : } else {
429 0 : gl->fBufferData(target, size, data, usage);
430 0 : return LOCAL_GL_NO_ERROR;
431 : }
432 : }
433 :
434 : NS_IMETHODIMP
435 0 : WebGLContext::BufferData(PRInt32 dummy)
436 : {
437 0 : if (!IsContextStable())
438 0 : return NS_OK;
439 :
440 : // this should never be called
441 0 : LogMessageIfVerbose("BufferData");
442 0 : return NS_ERROR_FAILURE;
443 : }
444 :
445 : NS_IMETHODIMP
446 0 : WebGLContext::BufferData_null()
447 : {
448 0 : if (!IsContextStable())
449 0 : return NS_OK;
450 :
451 : // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
452 0 : return ErrorInvalidValue("bufferData: null object passed");
453 : }
454 :
455 :
456 : NS_IMETHODIMP
457 0 : WebGLContext::BufferData_size(WebGLenum target, WebGLsizei size, WebGLenum usage)
458 : {
459 0 : if (!IsContextStable())
460 0 : return NS_OK;
461 :
462 0 : WebGLBuffer *boundBuffer = NULL;
463 :
464 0 : if (target == LOCAL_GL_ARRAY_BUFFER) {
465 0 : boundBuffer = mBoundArrayBuffer;
466 0 : } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
467 0 : boundBuffer = mBoundElementArrayBuffer;
468 : } else {
469 0 : return ErrorInvalidEnumInfo("bufferData: target", target);
470 : }
471 :
472 0 : if (size < 0)
473 0 : return ErrorInvalidValue("bufferData: negative size");
474 :
475 0 : if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
476 0 : return NS_OK;
477 :
478 0 : if (!boundBuffer)
479 0 : return ErrorInvalidOperation("BufferData: no buffer bound!");
480 :
481 0 : MakeContextCurrent();
482 :
483 0 : GLenum error = CheckedBufferData(target, size, 0, usage);
484 0 : if (error) {
485 0 : LogMessageIfVerbose("bufferData generated error %s", ErrorName(error));
486 0 : return NS_OK;
487 : }
488 :
489 0 : boundBuffer->SetByteLength(size);
490 0 : boundBuffer->InvalidateCachedMaxElements();
491 0 : if (!boundBuffer->ZeroDataIfElementArray())
492 0 : return ErrorOutOfMemory("bufferData: out of memory");
493 :
494 0 : return NS_OK;
495 : }
496 :
497 : NS_IMETHODIMP
498 0 : WebGLContext::BufferData_buf(WebGLenum target, JSObject *wb, WebGLenum usage)
499 : {
500 0 : if (!IsContextStable())
501 0 : return NS_OK;
502 :
503 0 : WebGLBuffer *boundBuffer = NULL;
504 :
505 0 : if (target == LOCAL_GL_ARRAY_BUFFER) {
506 0 : boundBuffer = mBoundArrayBuffer;
507 0 : } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
508 0 : boundBuffer = mBoundElementArrayBuffer;
509 : } else {
510 0 : return ErrorInvalidEnumInfo("bufferData: target", target);
511 : }
512 :
513 0 : if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
514 0 : return NS_OK;
515 :
516 0 : if (!boundBuffer)
517 0 : return ErrorInvalidOperation("BufferData: no buffer bound!");
518 :
519 0 : MakeContextCurrent();
520 :
521 : GLenum error = CheckedBufferData(target,
522 0 : JS_GetArrayBufferByteLength(wb),
523 0 : JS_GetArrayBufferData(wb),
524 0 : usage);
525 0 : if (error) {
526 0 : LogMessageIfVerbose("bufferData generated error %s", ErrorName(error));
527 0 : return NS_OK;
528 : }
529 :
530 0 : boundBuffer->SetByteLength(JS_GetArrayBufferByteLength(wb));
531 0 : boundBuffer->InvalidateCachedMaxElements();
532 0 : if (!boundBuffer->CopyDataIfElementArray(JS_GetArrayBufferData(wb)))
533 0 : return ErrorOutOfMemory("bufferData: out of memory");
534 :
535 0 : return NS_OK;
536 : }
537 :
538 : NS_IMETHODIMP
539 0 : WebGLContext::BufferData_array(WebGLenum target, JSObject *wa, WebGLenum usage)
540 : {
541 0 : if (!IsContextStable())
542 0 : return NS_OK;
543 :
544 0 : WebGLBuffer *boundBuffer = NULL;
545 :
546 0 : if (target == LOCAL_GL_ARRAY_BUFFER) {
547 0 : boundBuffer = mBoundArrayBuffer;
548 0 : } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
549 0 : boundBuffer = mBoundElementArrayBuffer;
550 : } else {
551 0 : return ErrorInvalidEnumInfo("bufferData: target", target);
552 : }
553 :
554 0 : if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
555 0 : return NS_OK;
556 :
557 0 : if (!boundBuffer)
558 0 : return ErrorInvalidOperation("BufferData: no buffer bound!");
559 :
560 0 : MakeContextCurrent();
561 :
562 : GLenum error = CheckedBufferData(target,
563 0 : JS_GetTypedArrayByteLength(wa),
564 0 : JS_GetTypedArrayData(wa),
565 0 : usage);
566 0 : if (error) {
567 0 : LogMessageIfVerbose("bufferData generated error %s", ErrorName(error));
568 0 : return NS_OK;
569 : }
570 :
571 0 : boundBuffer->SetByteLength(JS_GetTypedArrayByteLength(wa));
572 0 : boundBuffer->InvalidateCachedMaxElements();
573 0 : if (!boundBuffer->CopyDataIfElementArray(JS_GetTypedArrayData(wa)))
574 0 : return ErrorOutOfMemory("bufferData: out of memory");
575 :
576 0 : return NS_OK;
577 : }
578 :
579 : NS_IMETHODIMP
580 0 : WebGLContext::BufferSubData(PRInt32)
581 : {
582 0 : if (!IsContextStable())
583 0 : return NS_OK;
584 :
585 0 : return NS_ERROR_FAILURE;
586 : }
587 :
588 : NS_IMETHODIMP
589 0 : WebGLContext::BufferSubData_null()
590 : {
591 0 : if (!IsContextStable())
592 0 : return NS_OK;
593 :
594 0 : return NS_OK; // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
595 : }
596 :
597 : NS_IMETHODIMP
598 0 : WebGLContext::BufferSubData_buf(GLenum target, WebGLsizei byteOffset, JSObject *wb)
599 : {
600 0 : if (!IsContextStable())
601 0 : return NS_OK;
602 :
603 0 : WebGLBuffer *boundBuffer = NULL;
604 :
605 0 : if (target == LOCAL_GL_ARRAY_BUFFER) {
606 0 : boundBuffer = mBoundArrayBuffer;
607 0 : } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
608 0 : boundBuffer = mBoundElementArrayBuffer;
609 : } else {
610 0 : return ErrorInvalidEnumInfo("bufferSubData: target", target);
611 : }
612 :
613 0 : if (byteOffset < 0)
614 0 : return ErrorInvalidValue("bufferSubData: negative offset");
615 :
616 0 : if (!boundBuffer)
617 0 : return ErrorInvalidOperation("BufferData: no buffer bound!");
618 :
619 0 : CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + JS_GetArrayBufferByteLength(wb);
620 0 : if (!checked_neededByteLength.valid())
621 0 : return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
622 :
623 0 : if (checked_neededByteLength.value() > boundBuffer->ByteLength())
624 : return ErrorInvalidOperation("BufferSubData: not enough data - operation requires %d bytes, but buffer only has %d bytes",
625 0 : byteOffset, JS_GetArrayBufferByteLength(wb), boundBuffer->ByteLength());
626 :
627 0 : MakeContextCurrent();
628 :
629 0 : boundBuffer->CopySubDataIfElementArray(byteOffset, JS_GetArrayBufferByteLength(wb), JS_GetArrayBufferData(wb));
630 0 : boundBuffer->InvalidateCachedMaxElements();
631 :
632 0 : gl->fBufferSubData(target, byteOffset, JS_GetArrayBufferByteLength(wb), JS_GetArrayBufferData(wb));
633 :
634 0 : return NS_OK;
635 : }
636 :
637 : NS_IMETHODIMP
638 0 : WebGLContext::BufferSubData_array(WebGLenum target, WebGLsizei byteOffset, JSObject *wa)
639 : {
640 0 : if (!IsContextStable())
641 0 : return NS_OK;
642 :
643 0 : WebGLBuffer *boundBuffer = NULL;
644 :
645 0 : if (target == LOCAL_GL_ARRAY_BUFFER) {
646 0 : boundBuffer = mBoundArrayBuffer;
647 0 : } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
648 0 : boundBuffer = mBoundElementArrayBuffer;
649 : } else {
650 0 : return ErrorInvalidEnumInfo("bufferSubData: target", target);
651 : }
652 :
653 0 : if (byteOffset < 0)
654 0 : return ErrorInvalidValue("bufferSubData: negative offset");
655 :
656 0 : if (!boundBuffer)
657 0 : return ErrorInvalidOperation("BufferData: no buffer bound!");
658 :
659 0 : CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + JS_GetTypedArrayByteLength(wa);
660 0 : if (!checked_neededByteLength.valid())
661 0 : return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
662 :
663 0 : if (checked_neededByteLength.value() > boundBuffer->ByteLength())
664 : return ErrorInvalidOperation("BufferSubData: not enough data -- operation requires %d bytes, but buffer only has %d bytes",
665 0 : byteOffset, JS_GetTypedArrayByteLength(wa), boundBuffer->ByteLength());
666 :
667 0 : MakeContextCurrent();
668 :
669 0 : boundBuffer->CopySubDataIfElementArray(byteOffset, JS_GetTypedArrayByteLength(wa), JS_GetTypedArrayData(wa));
670 0 : boundBuffer->InvalidateCachedMaxElements();
671 :
672 0 : gl->fBufferSubData(target, byteOffset, JS_GetTypedArrayByteLength(wa), JS_GetTypedArrayData(wa));
673 :
674 0 : return NS_OK;
675 : }
676 :
677 : NS_IMETHODIMP
678 0 : WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval)
679 : {
680 0 : if (!IsContextStable())
681 : {
682 0 : *retval = LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
683 0 : return NS_OK;
684 : }
685 :
686 0 : *retval = 0;
687 :
688 0 : MakeContextCurrent();
689 0 : if (target != LOCAL_GL_FRAMEBUFFER)
690 0 : return ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
691 :
692 0 : if (!mBoundFramebuffer)
693 0 : *retval = LOCAL_GL_FRAMEBUFFER_COMPLETE;
694 0 : else if(mBoundFramebuffer->HasDepthStencilConflict())
695 0 : *retval = LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
696 0 : else if(!mBoundFramebuffer->ColorAttachment().IsDefined())
697 0 : *retval = LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
698 0 : else if(mBoundFramebuffer->HasIncompleteAttachment())
699 0 : *retval = LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
700 0 : else if(mBoundFramebuffer->HasAttachmentsOfMismatchedDimensions())
701 0 : *retval = LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
702 : else
703 0 : *retval = gl->fCheckFramebufferStatus(target);
704 :
705 0 : return NS_OK;
706 : }
707 :
708 : NS_IMETHODIMP
709 0 : WebGLContext::Clear(PRUint32 mask)
710 : {
711 0 : if (!IsContextStable())
712 0 : return NS_OK;
713 :
714 0 : MakeContextCurrent();
715 :
716 0 : PRUint32 m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
717 0 : if (mask != m)
718 0 : return ErrorInvalidValue("clear: invalid mask bits");
719 :
720 0 : bool needClearCallHere = true;
721 :
722 0 : if (mBoundFramebuffer) {
723 0 : if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
724 0 : return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
725 : } else {
726 : // no FBO is bound, so we are clearing the backbuffer here
727 0 : EnsureBackbufferClearedAsNeeded();
728 0 : bool valuesAreDefault = mColorClearValue[0] == 0.0f &&
729 0 : mColorClearValue[1] == 0.0f &&
730 0 : mColorClearValue[2] == 0.0f &&
731 0 : mColorClearValue[3] == 0.0f &&
732 : mDepthClearValue == 1.0f &&
733 0 : mStencilClearValue == 0;
734 0 : if (valuesAreDefault &&
735 : mBackbufferClearingStatus == BackbufferClearingStatus::ClearedToDefaultValues)
736 : {
737 0 : needClearCallHere = false;
738 : }
739 : }
740 :
741 0 : if (needClearCallHere) {
742 0 : gl->fClear(mask);
743 0 : mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
744 0 : Invalidate();
745 : }
746 :
747 0 : return NS_OK;
748 : }
749 :
750 : NS_IMETHODIMP
751 0 : WebGLContext::ClearColor(WebGLfloat r, WebGLfloat g, WebGLfloat b, WebGLfloat a)
752 : {
753 0 : if (!IsContextStable())
754 0 : return NS_OK;
755 :
756 0 : MakeContextCurrent();
757 0 : mColorClearValue[0] = r;
758 0 : mColorClearValue[1] = g;
759 0 : mColorClearValue[2] = b;
760 0 : mColorClearValue[3] = a;
761 0 : gl->fClearColor(r, g, b, a);
762 0 : return NS_OK;
763 : }
764 :
765 : NS_IMETHODIMP
766 0 : WebGLContext::ClearDepth(WebGLfloat v)
767 : {
768 0 : if (!IsContextStable())
769 0 : return NS_OK;
770 :
771 0 : MakeContextCurrent();
772 0 : mDepthClearValue = v;
773 0 : gl->fClearDepth(v);
774 0 : return NS_OK;
775 : }
776 :
777 : NS_IMETHODIMP
778 0 : WebGLContext::ClearStencil(WebGLint v)
779 : {
780 0 : if (!IsContextStable())
781 0 : return NS_OK;
782 :
783 0 : MakeContextCurrent();
784 0 : mStencilClearValue = v;
785 0 : gl->fClearStencil(v);
786 0 : return NS_OK;
787 : }
788 :
789 : NS_IMETHODIMP
790 0 : WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a)
791 : {
792 0 : if (!IsContextStable())
793 0 : return NS_OK;
794 :
795 0 : MakeContextCurrent();
796 0 : mColorWriteMask[0] = r;
797 0 : mColorWriteMask[1] = g;
798 0 : mColorWriteMask[2] = b;
799 0 : mColorWriteMask[3] = a;
800 0 : gl->fColorMask(r, g, b, a);
801 0 : return NS_OK;
802 : }
803 :
804 : nsresult
805 0 : WebGLContext::CopyTexSubImage2D_base(WebGLenum target,
806 : WebGLint level,
807 : WebGLenum internalformat,
808 : WebGLint xoffset,
809 : WebGLint yoffset,
810 : WebGLint x,
811 : WebGLint y,
812 : WebGLsizei width,
813 : WebGLsizei height,
814 : bool sub)
815 : {
816 0 : const WebGLRectangleObject *framebufferRect = FramebufferRectangleObject();
817 0 : WebGLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
818 0 : WebGLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
819 :
820 0 : const char *info = sub ? "copyTexSubImage2D" : "copyTexImage2D";
821 :
822 0 : MakeContextCurrent();
823 :
824 0 : if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
825 0 : if (sub)
826 0 : gl->fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
827 : else
828 0 : gl->fCopyTexImage2D(target, level, internalformat, x, y, width, height, 0);
829 : } else {
830 :
831 : // the rect doesn't fit in the framebuffer
832 :
833 : /*** first, we initialize the texture as black ***/
834 :
835 : // first, compute the size of the buffer we should allocate to initialize the texture as black
836 :
837 0 : PRUint32 texelSize = 0;
838 0 : if (!ValidateTexFormatAndType(internalformat, LOCAL_GL_UNSIGNED_BYTE, -1, &texelSize, info))
839 0 : return NS_OK;
840 :
841 : CheckedUint32 checked_neededByteLength =
842 0 : GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
843 :
844 0 : if (!checked_neededByteLength.valid())
845 0 : return ErrorInvalidOperation("%s: integer overflow computing the needed buffer size", info);
846 :
847 0 : PRUint32 bytesNeeded = checked_neededByteLength.value();
848 :
849 : // now that the size is known, create the buffer
850 :
851 : // We need some zero pages, because GL doesn't guarantee the
852 : // contents of a texture allocated with NULL data.
853 : // Hopefully calloc will just mmap zero pages here.
854 0 : void *tempZeroData = calloc(1, bytesNeeded);
855 0 : if (!tempZeroData)
856 0 : return ErrorOutOfMemory("%s: could not allocate %d bytes (for zero fill)", info, bytesNeeded);
857 :
858 : // now initialize the texture as black
859 :
860 0 : if (sub)
861 : gl->fTexSubImage2D(target, level, 0, 0, width, height,
862 0 : internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
863 : else
864 : gl->fTexImage2D(target, level, internalformat, width, height,
865 0 : 0, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
866 0 : free(tempZeroData);
867 :
868 : // if we are completely outside of the framebuffer, we can exit now with our black texture
869 0 : if ( x >= framebufferWidth
870 : || x+width <= 0
871 : || y >= framebufferHeight
872 : || y+height <= 0)
873 : {
874 : // we are completely outside of range, can exit now with buffer filled with zeros
875 0 : return DummyFramebufferOperation(info);
876 : }
877 :
878 0 : GLint actual_x = clamped(x, 0, framebufferWidth);
879 0 : GLint actual_x_plus_width = clamped(x + width, 0, framebufferWidth);
880 0 : GLsizei actual_width = actual_x_plus_width - actual_x;
881 0 : GLint actual_xoffset = xoffset + actual_x - x;
882 :
883 0 : GLint actual_y = clamped(y, 0, framebufferHeight);
884 0 : GLint actual_y_plus_height = clamped(y + height, 0, framebufferHeight);
885 0 : GLsizei actual_height = actual_y_plus_height - actual_y;
886 0 : GLint actual_yoffset = yoffset + actual_y - y;
887 :
888 0 : gl->fCopyTexSubImage2D(target, level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height);
889 : }
890 :
891 0 : return NS_OK;
892 : }
893 :
894 : NS_IMETHODIMP
895 0 : WebGLContext::CopyTexImage2D(WebGLenum target,
896 : WebGLint level,
897 : WebGLenum internalformat,
898 : WebGLint x,
899 : WebGLint y,
900 : WebGLsizei width,
901 : WebGLsizei height,
902 : WebGLint border)
903 : {
904 0 : if (!IsContextStable())
905 0 : return NS_OK;
906 :
907 0 : switch (target) {
908 : case LOCAL_GL_TEXTURE_2D:
909 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
910 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
911 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
912 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
913 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
914 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
915 : break;
916 : default:
917 0 : return ErrorInvalidEnumInfo("copyTexImage2D: target", target);
918 : }
919 :
920 :
921 0 : switch (internalformat) {
922 : case LOCAL_GL_RGB:
923 : case LOCAL_GL_LUMINANCE:
924 : case LOCAL_GL_RGBA:
925 : case LOCAL_GL_ALPHA:
926 : case LOCAL_GL_LUMINANCE_ALPHA:
927 : break;
928 : default:
929 0 : return ErrorInvalidEnumInfo("CopyTexImage2D: internal format", internalformat);
930 : }
931 :
932 0 : if (border != 0)
933 0 : return ErrorInvalidValue("copyTexImage2D: border must be 0");
934 :
935 0 : if (width < 0 || height < 0)
936 0 : return ErrorInvalidValue("copyTexImage2D: width and height may not be negative");
937 :
938 0 : if (level < 0)
939 0 : return ErrorInvalidValue("copyTexImage2D: level may not be negative");
940 :
941 0 : WebGLsizei maxTextureSize = MaxTextureSizeForTarget(target);
942 0 : if (!(maxTextureSize >> level))
943 0 : return ErrorInvalidValue("copyTexImage2D: 2^level exceeds maximum texture size");
944 :
945 0 : if (level >= 1) {
946 0 : if (!(is_pot_assuming_nonnegative(width) &&
947 0 : is_pot_assuming_nonnegative(height)))
948 0 : return ErrorInvalidValue("copyTexImage2D: with level > 0, width and height must be powers of two");
949 : }
950 :
951 : bool texFormatRequiresAlpha = internalformat == LOCAL_GL_RGBA ||
952 : internalformat == LOCAL_GL_ALPHA ||
953 0 : internalformat == LOCAL_GL_LUMINANCE_ALPHA;
954 0 : bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha()
955 0 : : bool(gl->ActualFormat().alpha > 0);
956 0 : if (texFormatRequiresAlpha && !fboFormatHasAlpha)
957 : return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel "
958 0 : "but the framebuffer doesn't have one");
959 :
960 0 : if (mBoundFramebuffer)
961 0 : if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
962 0 : return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
963 :
964 0 : WebGLTexture *tex = activeBoundTextureForTarget(target);
965 0 : if (!tex)
966 0 : return ErrorInvalidOperation("copyTexImage2D: no texture bound to this target");
967 :
968 : // copyTexImage2D only generates textures with type = UNSIGNED_BYTE
969 0 : GLenum type = LOCAL_GL_UNSIGNED_BYTE;
970 :
971 : // check if the memory size of this texture may change with this call
972 0 : bool sizeMayChange = true;
973 0 : size_t face = WebGLTexture::FaceForTarget(target);
974 0 : if (tex->HasImageInfoAt(level, face)) {
975 0 : const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(level, face);
976 :
977 0 : sizeMayChange = width != imageInfo.Width() ||
978 0 : height != imageInfo.Height() ||
979 0 : internalformat != imageInfo.Format() ||
980 0 : type != imageInfo.Type();
981 : }
982 :
983 0 : if (sizeMayChange) {
984 0 : UpdateWebGLErrorAndClearGLError();
985 0 : CopyTexSubImage2D_base(target, level, internalformat, 0, 0, x, y, width, height, false);
986 0 : GLenum error = LOCAL_GL_NO_ERROR;
987 0 : UpdateWebGLErrorAndClearGLError(&error);
988 0 : if (error) {
989 0 : LogMessageIfVerbose("copyTexImage2D generated error %s", ErrorName(error));
990 0 : return NS_OK;
991 : }
992 : } else {
993 0 : CopyTexSubImage2D_base(target, level, internalformat, 0, 0, x, y, width, height, false);
994 : }
995 :
996 0 : tex->SetImageInfo(target, level, width, height, internalformat, type);
997 0 : return NS_OK;
998 : }
999 :
1000 : NS_IMETHODIMP
1001 0 : WebGLContext::CopyTexSubImage2D(WebGLenum target,
1002 : WebGLint level,
1003 : WebGLint xoffset,
1004 : WebGLint yoffset,
1005 : WebGLint x,
1006 : WebGLint y,
1007 : WebGLsizei width,
1008 : WebGLsizei height)
1009 : {
1010 0 : if (!IsContextStable())
1011 0 : return NS_OK;
1012 :
1013 0 : switch (target) {
1014 : case LOCAL_GL_TEXTURE_2D:
1015 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1016 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1017 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1018 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1019 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1020 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1021 : break;
1022 : default:
1023 0 : return ErrorInvalidEnumInfo("CopyTexSubImage2D: target", target);
1024 : }
1025 :
1026 0 : if (level < 0)
1027 0 : return ErrorInvalidValue("copyTexSubImage2D: level may not be negative");
1028 :
1029 0 : WebGLsizei maxTextureSize = MaxTextureSizeForTarget(target);
1030 0 : if (!(maxTextureSize >> level))
1031 0 : return ErrorInvalidValue("copyTexSubImage2D: 2^level exceeds maximum texture size");
1032 :
1033 0 : if (width < 0 || height < 0)
1034 0 : return ErrorInvalidValue("copyTexSubImage2D: width and height may not be negative");
1035 :
1036 0 : if (xoffset < 0 || yoffset < 0)
1037 0 : return ErrorInvalidValue("copyTexSubImage2D: xoffset and yoffset may not be negative");
1038 :
1039 0 : WebGLTexture *tex = activeBoundTextureForTarget(target);
1040 0 : if (!tex)
1041 0 : return ErrorInvalidOperation("copyTexSubImage2D: no texture bound to this target");
1042 :
1043 0 : WebGLint face = WebGLTexture::FaceForTarget(target);
1044 0 : if (!tex->HasImageInfoAt(level, face))
1045 0 : return ErrorInvalidOperation("copyTexSubImage2D: no texture image previously defined for this level and face");
1046 :
1047 0 : const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(level, face);
1048 0 : WebGLsizei texWidth = imageInfo.Width();
1049 0 : WebGLsizei texHeight = imageInfo.Height();
1050 :
1051 0 : if (xoffset + width > texWidth || xoffset + width < 0)
1052 0 : return ErrorInvalidValue("copyTexSubImage2D: xoffset+width is too large");
1053 :
1054 0 : if (yoffset + height > texHeight || yoffset + height < 0)
1055 0 : return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
1056 :
1057 0 : WebGLenum format = imageInfo.Format();
1058 : bool texFormatRequiresAlpha = format == LOCAL_GL_RGBA ||
1059 : format == LOCAL_GL_ALPHA ||
1060 0 : format == LOCAL_GL_LUMINANCE_ALPHA;
1061 0 : bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha()
1062 0 : : bool(gl->ActualFormat().alpha > 0);
1063 :
1064 0 : if (texFormatRequiresAlpha && !fboFormatHasAlpha)
1065 : return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
1066 0 : "but the framebuffer doesn't have one");
1067 :
1068 0 : if (mBoundFramebuffer)
1069 0 : if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
1070 0 : return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
1071 :
1072 0 : return CopyTexSubImage2D_base(target, level, format, xoffset, yoffset, x, y, width, height, true);
1073 : }
1074 :
1075 :
1076 : NS_IMETHODIMP
1077 0 : WebGLContext::CreateProgram(nsIWebGLProgram **retval)
1078 : {
1079 0 : if (!IsContextStable())
1080 0 : return NS_OK;
1081 :
1082 0 : *retval = nsnull;
1083 :
1084 0 : WebGLProgram *prog = new WebGLProgram(this);
1085 0 : NS_ADDREF(*retval = prog);
1086 :
1087 0 : return NS_OK;
1088 : }
1089 :
1090 : NS_IMETHODIMP
1091 0 : WebGLContext::CreateShader(WebGLenum type, nsIWebGLShader **retval)
1092 : {
1093 0 : if (!IsContextStable())
1094 0 : return NS_OK;
1095 :
1096 0 : *retval = nsnull;
1097 :
1098 0 : if (type != LOCAL_GL_VERTEX_SHADER &&
1099 : type != LOCAL_GL_FRAGMENT_SHADER)
1100 : {
1101 0 : return ErrorInvalidEnumInfo("createShader: type", type);
1102 : }
1103 :
1104 0 : WebGLShader *shader = new WebGLShader(this, type);
1105 0 : NS_ADDREF(*retval = shader);
1106 :
1107 0 : return NS_OK;
1108 : }
1109 :
1110 : NS_IMETHODIMP
1111 0 : WebGLContext::CullFace(WebGLenum face)
1112 : {
1113 0 : if (!IsContextStable())
1114 0 : return NS_OK;
1115 :
1116 0 : if (!ValidateFaceEnum(face, "cullFace"))
1117 0 : return NS_OK;
1118 :
1119 0 : MakeContextCurrent();
1120 0 : gl->fCullFace(face);
1121 0 : return NS_OK;
1122 : }
1123 :
1124 : NS_IMETHODIMP
1125 0 : WebGLContext::DeleteBuffer(nsIWebGLBuffer *bobj)
1126 : {
1127 0 : if (!IsContextStable())
1128 0 : return NS_OK;
1129 :
1130 : WebGLuint bufname;
1131 : WebGLBuffer *buf;
1132 : bool isNull, isDeleted;
1133 0 : if (!GetConcreteObjectAndGLName("deleteBuffer", bobj, &buf, &bufname, &isNull, &isDeleted))
1134 0 : return NS_OK;
1135 :
1136 0 : if (isNull || isDeleted)
1137 0 : return NS_OK;
1138 :
1139 0 : if (mBoundArrayBuffer == buf)
1140 0 : BindBuffer(LOCAL_GL_ARRAY_BUFFER, nsnull);
1141 0 : if (mBoundElementArrayBuffer == buf)
1142 0 : BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nsnull);
1143 :
1144 0 : for (int i = 0; i < mGLMaxVertexAttribs; i++) {
1145 0 : if (mAttribBuffers[i].buf == buf)
1146 0 : mAttribBuffers[i].buf = nsnull;
1147 : }
1148 :
1149 0 : buf->RequestDelete();
1150 :
1151 0 : return NS_OK;
1152 : }
1153 :
1154 : NS_IMETHODIMP
1155 0 : WebGLContext::DeleteFramebuffer(nsIWebGLFramebuffer *fbobj)
1156 : {
1157 0 : if (!IsContextStable())
1158 0 : return NS_OK;
1159 :
1160 : WebGLFramebuffer *fbuf;
1161 : WebGLuint fbufname;
1162 : bool isNull, isDeleted;
1163 0 : if (!GetConcreteObjectAndGLName("deleteFramebuffer", fbobj, &fbuf, &fbufname, &isNull, &isDeleted))
1164 0 : return NS_OK;
1165 :
1166 0 : if (isNull || isDeleted)
1167 0 : return NS_OK;
1168 :
1169 0 : fbuf->RequestDelete();
1170 :
1171 0 : if (mBoundFramebuffer == fbuf)
1172 0 : BindFramebuffer(LOCAL_GL_FRAMEBUFFER, nsnull);
1173 :
1174 0 : return NS_OK;
1175 : }
1176 :
1177 : NS_IMETHODIMP
1178 0 : WebGLContext::DeleteRenderbuffer(nsIWebGLRenderbuffer *rbobj)
1179 : {
1180 0 : if (!IsContextStable())
1181 0 : return NS_OK;
1182 :
1183 : WebGLRenderbuffer *rbuf;
1184 : WebGLuint rbufname;
1185 : bool isNull, isDeleted;
1186 0 : if (!GetConcreteObjectAndGLName("deleteRenderbuffer", rbobj, &rbuf, &rbufname, &isNull, &isDeleted))
1187 0 : return NS_OK;
1188 :
1189 0 : if (isNull || isDeleted)
1190 0 : return NS_OK;
1191 :
1192 0 : if (mBoundFramebuffer)
1193 0 : mBoundFramebuffer->DetachRenderbuffer(rbuf);
1194 :
1195 0 : if (mBoundRenderbuffer == rbuf)
1196 0 : BindRenderbuffer(LOCAL_GL_RENDERBUFFER, nsnull);
1197 :
1198 0 : rbuf->RequestDelete();
1199 :
1200 0 : return NS_OK;
1201 : }
1202 :
1203 : NS_IMETHODIMP
1204 0 : WebGLContext::DeleteTexture(nsIWebGLTexture *tobj)
1205 : {
1206 0 : if (!IsContextStable())
1207 0 : return NS_OK;
1208 :
1209 : WebGLTexture *tex;
1210 : WebGLuint texname;
1211 : bool isNull, isDeleted;
1212 0 : if (!GetConcreteObjectAndGLName("deleteTexture", tobj, &tex, &texname, &isNull, &isDeleted))
1213 0 : return NS_OK;
1214 :
1215 0 : if (isNull || isDeleted)
1216 0 : return NS_OK;
1217 :
1218 0 : if (mBoundFramebuffer)
1219 0 : mBoundFramebuffer->DetachTexture(tex);
1220 :
1221 0 : for (int i = 0; i < mGLMaxTextureUnits; i++) {
1222 0 : if ((tex->Target() == LOCAL_GL_TEXTURE_2D && mBound2DTextures[i] == tex) ||
1223 0 : (tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP && mBoundCubeMapTextures[i] == tex))
1224 : {
1225 0 : ActiveTexture(LOCAL_GL_TEXTURE0 + i);
1226 0 : BindTexture(tex->Target(), nsnull);
1227 : }
1228 : }
1229 0 : ActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
1230 :
1231 0 : tex->RequestDelete();
1232 :
1233 0 : return NS_OK;
1234 : }
1235 :
1236 : NS_IMETHODIMP
1237 0 : WebGLContext::DeleteProgram(nsIWebGLProgram *pobj)
1238 : {
1239 0 : if (!IsContextStable())
1240 0 : return NS_OK;
1241 :
1242 : WebGLuint progname;
1243 : WebGLProgram *prog;
1244 : bool isNull, isDeleted;
1245 0 : if (!GetConcreteObjectAndGLName("deleteProgram", pobj, &prog, &progname, &isNull, &isDeleted))
1246 0 : return NS_OK;
1247 :
1248 0 : if (isNull || isDeleted)
1249 0 : return NS_OK;
1250 :
1251 0 : prog->RequestDelete();
1252 :
1253 0 : return NS_OK;
1254 : }
1255 :
1256 : NS_IMETHODIMP
1257 0 : WebGLContext::DeleteShader(nsIWebGLShader *sobj)
1258 : {
1259 0 : if (!IsContextStable())
1260 0 : return NS_OK;
1261 :
1262 : WebGLuint shadername;
1263 : WebGLShader *shader;
1264 : bool isNull, isDeleted;
1265 0 : if (!GetConcreteObjectAndGLName("deleteShader", sobj, &shader, &shadername, &isNull, &isDeleted))
1266 0 : return NS_OK;
1267 :
1268 0 : if (isNull || isDeleted)
1269 0 : return NS_OK;
1270 :
1271 0 : shader->RequestDelete();
1272 :
1273 0 : return NS_OK;
1274 : }
1275 :
1276 : NS_IMETHODIMP
1277 0 : WebGLContext::DetachShader(nsIWebGLProgram *pobj, nsIWebGLShader *shobj)
1278 : {
1279 0 : if (!IsContextStable())
1280 0 : return NS_OK;
1281 :
1282 : WebGLuint progname, shadername;
1283 : WebGLProgram *program;
1284 : WebGLShader *shader;
1285 : bool shaderDeleted;
1286 0 : if (!GetConcreteObjectAndGLName("detachShader: program", pobj, &program, &progname) ||
1287 0 : !GetConcreteObjectAndGLName("detachShader: shader", shobj, &shader, &shadername, nsnull, &shaderDeleted))
1288 0 : return NS_OK;
1289 :
1290 : // shaderDeleted is ignored -- it's valid to attempt to detach a
1291 : // deleted shader, since it's still a shader
1292 0 : if (!program->DetachShader(shader))
1293 0 : return ErrorInvalidOperation("DetachShader: shader is not attached");
1294 :
1295 0 : return NS_OK;
1296 : }
1297 :
1298 : NS_IMETHODIMP
1299 0 : WebGLContext::DepthFunc(WebGLenum func)
1300 : {
1301 0 : if (!IsContextStable())
1302 0 : return NS_OK;
1303 :
1304 0 : if (!ValidateComparisonEnum(func, "depthFunc"))
1305 0 : return NS_OK;
1306 :
1307 0 : MakeContextCurrent();
1308 0 : gl->fDepthFunc(func);
1309 0 : return NS_OK;
1310 : }
1311 :
1312 : NS_IMETHODIMP
1313 0 : WebGLContext::DepthMask(WebGLboolean b)
1314 : {
1315 0 : if (!IsContextStable())
1316 0 : return NS_OK;
1317 :
1318 0 : MakeContextCurrent();
1319 0 : mDepthWriteMask = b;
1320 0 : gl->fDepthMask(b);
1321 0 : return NS_OK;
1322 : }
1323 :
1324 : NS_IMETHODIMP
1325 0 : WebGLContext::DepthRange(WebGLfloat zNear, WebGLfloat zFar)
1326 : {
1327 0 : if (!IsContextStable())
1328 0 : return NS_OK;
1329 :
1330 0 : if (zNear > zFar)
1331 0 : return ErrorInvalidOperation("depthRange: the near value is greater than the far value!");
1332 :
1333 0 : MakeContextCurrent();
1334 0 : gl->fDepthRange(zNear, zFar);
1335 0 : return NS_OK;
1336 : }
1337 :
1338 : NS_IMETHODIMP
1339 0 : WebGLContext::DisableVertexAttribArray(WebGLuint index)
1340 : {
1341 0 : if (!IsContextStable())
1342 0 : return NS_OK;
1343 :
1344 0 : if (!ValidateAttribIndex(index, "disableVertexAttribArray"))
1345 0 : return NS_OK;
1346 :
1347 0 : MakeContextCurrent();
1348 :
1349 0 : if (index || gl->IsGLES2())
1350 0 : gl->fDisableVertexAttribArray(index);
1351 :
1352 0 : mAttribBuffers[index].enabled = false;
1353 :
1354 0 : return NS_OK;
1355 : }
1356 :
1357 : int
1358 0 : WebGLContext::WhatDoesVertexAttrib0Need()
1359 : {
1360 : // here we may assume that mCurrentProgram != null
1361 :
1362 : // work around Mac OSX crash, see bug 631420
1363 : #ifdef XP_MACOSX
1364 : if (mAttribBuffers[0].enabled &&
1365 : !mCurrentProgram->IsAttribInUse(0))
1366 : return VertexAttrib0Status::EmulatedUninitializedArray;
1367 : #endif
1368 :
1369 0 : return (gl->IsGLES2() || mAttribBuffers[0].enabled) ? VertexAttrib0Status::Default
1370 0 : : mCurrentProgram->IsAttribInUse(0) ? VertexAttrib0Status::EmulatedInitializedArray
1371 0 : : VertexAttrib0Status::EmulatedUninitializedArray;
1372 : }
1373 :
1374 : bool
1375 0 : WebGLContext::DoFakeVertexAttrib0(WebGLuint vertexCount)
1376 : {
1377 0 : int whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
1378 :
1379 0 : if (whatDoesAttrib0Need == VertexAttrib0Status::Default)
1380 0 : return true;
1381 :
1382 0 : CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(WebGLfloat);
1383 :
1384 0 : if (!checked_dataSize.valid()) {
1385 : ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
1386 0 : "with %d vertices. Try reducing the number of vertices.", vertexCount);
1387 0 : return false;
1388 : }
1389 :
1390 0 : WebGLuint dataSize = checked_dataSize.value();
1391 :
1392 0 : if (!mFakeVertexAttrib0BufferObject) {
1393 0 : gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject);
1394 : }
1395 :
1396 : // if the VBO status is already exactly what we need, or if the only difference is that it's initialized and
1397 : // we don't need it to be, then consider it OK
1398 : bool vertexAttrib0BufferStatusOK =
1399 : mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need ||
1400 : (mFakeVertexAttrib0BufferStatus == VertexAttrib0Status::EmulatedInitializedArray &&
1401 0 : whatDoesAttrib0Need == VertexAttrib0Status::EmulatedUninitializedArray);
1402 :
1403 0 : if (!vertexAttrib0BufferStatusOK ||
1404 : mFakeVertexAttrib0BufferObjectSize < dataSize ||
1405 0 : mFakeVertexAttrib0BufferObjectVector[0] != mVertexAttrib0Vector[0] ||
1406 0 : mFakeVertexAttrib0BufferObjectVector[1] != mVertexAttrib0Vector[1] ||
1407 0 : mFakeVertexAttrib0BufferObjectVector[2] != mVertexAttrib0Vector[2] ||
1408 0 : mFakeVertexAttrib0BufferObjectVector[3] != mVertexAttrib0Vector[3])
1409 : {
1410 0 : mFakeVertexAttrib0BufferStatus = whatDoesAttrib0Need;
1411 0 : mFakeVertexAttrib0BufferObjectSize = dataSize;
1412 0 : mFakeVertexAttrib0BufferObjectVector[0] = mVertexAttrib0Vector[0];
1413 0 : mFakeVertexAttrib0BufferObjectVector[1] = mVertexAttrib0Vector[1];
1414 0 : mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
1415 0 : mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];
1416 :
1417 0 : gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
1418 :
1419 0 : GLenum error = LOCAL_GL_NO_ERROR;
1420 0 : UpdateWebGLErrorAndClearGLError();
1421 :
1422 0 : if (mFakeVertexAttrib0BufferStatus == VertexAttrib0Status::EmulatedInitializedArray) {
1423 0 : nsAutoArrayPtr<WebGLfloat> array(new WebGLfloat[4 * vertexCount]);
1424 0 : for(size_t i = 0; i < vertexCount; ++i) {
1425 0 : array[4 * i + 0] = mVertexAttrib0Vector[0];
1426 0 : array[4 * i + 1] = mVertexAttrib0Vector[1];
1427 0 : array[4 * i + 2] = mVertexAttrib0Vector[2];
1428 0 : array[4 * i + 3] = mVertexAttrib0Vector[3];
1429 : }
1430 0 : gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array, LOCAL_GL_DYNAMIC_DRAW);
1431 : } else {
1432 0 : gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nsnull, LOCAL_GL_DYNAMIC_DRAW);
1433 : }
1434 0 : UpdateWebGLErrorAndClearGLError(&error);
1435 :
1436 0 : gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
1437 :
1438 : // note that we do this error checking and early return AFTER having restored the buffer binding above
1439 0 : if (error) {
1440 : ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation "
1441 0 : "with %d vertices. Try reducing the number of vertices.", vertexCount);
1442 0 : return false;
1443 : }
1444 : }
1445 :
1446 0 : gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
1447 0 : gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0);
1448 :
1449 0 : return true;
1450 : }
1451 :
1452 : void
1453 0 : WebGLContext::UndoFakeVertexAttrib0()
1454 : {
1455 0 : int whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
1456 :
1457 0 : if (whatDoesAttrib0Need == VertexAttrib0Status::Default)
1458 0 : return;
1459 :
1460 0 : gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mAttribBuffers[0].buf ? mAttribBuffers[0].buf->GLName() : 0);
1461 : gl->fVertexAttribPointer(0,
1462 0 : mAttribBuffers[0].size,
1463 0 : mAttribBuffers[0].type,
1464 0 : mAttribBuffers[0].normalized,
1465 0 : mAttribBuffers[0].stride,
1466 0 : reinterpret_cast<const GLvoid *>(mAttribBuffers[0].byteOffset));
1467 :
1468 0 : gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
1469 : }
1470 :
1471 : bool
1472 0 : WebGLContext::NeedFakeBlack()
1473 : {
1474 : // handle this case first, it's the generic case
1475 0 : if (mFakeBlackStatus == DoNotNeedFakeBlack)
1476 0 : return false;
1477 :
1478 0 : if (mFakeBlackStatus == DontKnowIfNeedFakeBlack) {
1479 0 : for (PRInt32 i = 0; i < mGLMaxTextureUnits; ++i) {
1480 0 : if ((mBound2DTextures[i] && mBound2DTextures[i]->NeedFakeBlack()) ||
1481 0 : (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->NeedFakeBlack()))
1482 : {
1483 0 : mFakeBlackStatus = DoNeedFakeBlack;
1484 0 : break;
1485 : }
1486 : }
1487 :
1488 : // we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
1489 : // that means that we do NOT need it.
1490 0 : if (mFakeBlackStatus == DontKnowIfNeedFakeBlack)
1491 0 : mFakeBlackStatus = DoNotNeedFakeBlack;
1492 : }
1493 :
1494 0 : return mFakeBlackStatus == DoNeedFakeBlack;
1495 : }
1496 :
1497 : void
1498 0 : WebGLContext::BindFakeBlackTextures()
1499 : {
1500 : // this is the generic case: try to return early
1501 0 : if (!NeedFakeBlack())
1502 0 : return;
1503 :
1504 0 : if (!mBlackTexturesAreInitialized) {
1505 0 : GLuint bound2DTex = 0;
1506 0 : GLuint boundCubeTex = 0;
1507 0 : gl->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &bound2DTex);
1508 0 : gl->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, (GLint*) &boundCubeTex);
1509 :
1510 0 : const PRUint8 black[] = {0, 0, 0, 255};
1511 :
1512 0 : gl->fGenTextures(1, &mBlackTexture2D);
1513 0 : gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBlackTexture2D);
1514 : gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 1, 1,
1515 0 : 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, &black);
1516 :
1517 0 : gl->fGenTextures(1, &mBlackTextureCubeMap);
1518 0 : gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBlackTextureCubeMap);
1519 0 : for (WebGLuint i = 0; i < 6; ++i) {
1520 : gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, LOCAL_GL_RGBA, 1, 1,
1521 0 : 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, &black);
1522 : }
1523 :
1524 : // Reset bound textures
1525 0 : gl->fBindTexture(LOCAL_GL_TEXTURE_2D, bound2DTex);
1526 0 : gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, boundCubeTex);
1527 :
1528 0 : mBlackTexturesAreInitialized = true;
1529 : }
1530 :
1531 0 : for (PRInt32 i = 0; i < mGLMaxTextureUnits; ++i) {
1532 0 : if (mBound2DTextures[i] && mBound2DTextures[i]->NeedFakeBlack()) {
1533 0 : gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
1534 0 : gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBlackTexture2D);
1535 : }
1536 0 : if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->NeedFakeBlack()) {
1537 0 : gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
1538 0 : gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBlackTextureCubeMap);
1539 : }
1540 : }
1541 : }
1542 :
1543 : void
1544 0 : WebGLContext::UnbindFakeBlackTextures()
1545 : {
1546 : // this is the generic case: try to return early
1547 0 : if (!NeedFakeBlack())
1548 0 : return;
1549 :
1550 0 : for (PRInt32 i = 0; i < mGLMaxTextureUnits; ++i) {
1551 0 : if (mBound2DTextures[i] && mBound2DTextures[i]->NeedFakeBlack()) {
1552 0 : gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
1553 0 : gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->GLName());
1554 : }
1555 0 : if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->NeedFakeBlack()) {
1556 0 : gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
1557 0 : gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->GLName());
1558 : }
1559 : }
1560 :
1561 0 : gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
1562 : }
1563 :
1564 : NS_IMETHODIMP
1565 0 : WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
1566 : {
1567 0 : if (!IsContextStable())
1568 0 : return NS_OK;
1569 :
1570 0 : if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
1571 0 : return NS_OK;
1572 :
1573 0 : if (first < 0 || count < 0)
1574 0 : return ErrorInvalidValue("DrawArrays: negative first or count");
1575 :
1576 0 : if (!ValidateStencilParamsForDrawCall())
1577 0 : return NS_OK;
1578 :
1579 : // If count is 0, there's nothing to do.
1580 0 : if (count == 0)
1581 0 : return NS_OK;
1582 :
1583 : // If there is no current program, this is silently ignored.
1584 : // Any checks below this depend on a program being available.
1585 0 : if (!mCurrentProgram)
1586 0 : return NS_OK;
1587 :
1588 0 : PRInt32 maxAllowedCount = 0;
1589 0 : if (!ValidateBuffers(&maxAllowedCount, "drawArrays"))
1590 0 : return NS_OK;
1591 :
1592 0 : CheckedInt32 checked_firstPlusCount = CheckedInt32(first) + count;
1593 :
1594 0 : if (!checked_firstPlusCount.valid())
1595 0 : return ErrorInvalidOperation("drawArrays: overflow in first+count");
1596 :
1597 0 : if (checked_firstPlusCount.value() > maxAllowedCount)
1598 0 : return ErrorInvalidOperation("drawArrays: bound vertex attribute buffers do not have sufficient size for given first and count");
1599 :
1600 0 : MakeContextCurrent();
1601 :
1602 0 : if (mBoundFramebuffer) {
1603 0 : if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
1604 0 : return ErrorInvalidFramebufferOperation("drawArrays: incomplete framebuffer");
1605 : } else {
1606 0 : EnsureBackbufferClearedAsNeeded();
1607 : }
1608 :
1609 0 : BindFakeBlackTextures();
1610 0 : if (!DoFakeVertexAttrib0(checked_firstPlusCount.value()))
1611 0 : return NS_OK;
1612 :
1613 0 : SetupRobustnessTimer();
1614 0 : gl->fDrawArrays(mode, first, count);
1615 :
1616 0 : UndoFakeVertexAttrib0();
1617 0 : UnbindFakeBlackTextures();
1618 :
1619 0 : mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
1620 0 : Invalidate();
1621 :
1622 0 : return NS_OK;
1623 : }
1624 :
1625 : NS_IMETHODIMP
1626 0 : WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, WebGLint byteOffset)
1627 : {
1628 0 : if (!IsContextStable())
1629 0 : return NS_OK;
1630 :
1631 0 : if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
1632 0 : return NS_OK;
1633 :
1634 0 : if (count < 0 || byteOffset < 0)
1635 0 : return ErrorInvalidValue("DrawElements: negative count or offset");
1636 :
1637 0 : if (!ValidateStencilParamsForDrawCall())
1638 0 : return NS_OK;
1639 :
1640 : // If count is 0, there's nothing to do.
1641 0 : if (count == 0)
1642 0 : return NS_OK;
1643 :
1644 0 : CheckedUint32 checked_byteCount;
1645 :
1646 0 : if (type == LOCAL_GL_UNSIGNED_SHORT) {
1647 0 : checked_byteCount = 2 * CheckedUint32(count);
1648 0 : if (byteOffset % 2 != 0)
1649 0 : return ErrorInvalidOperation("DrawElements: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)");
1650 0 : } else if (type == LOCAL_GL_UNSIGNED_BYTE) {
1651 0 : checked_byteCount = count;
1652 : } else {
1653 0 : return ErrorInvalidEnum("DrawElements: type must be UNSIGNED_SHORT or UNSIGNED_BYTE");
1654 : }
1655 :
1656 0 : if (!checked_byteCount.valid())
1657 0 : return ErrorInvalidValue("DrawElements: overflow in byteCount");
1658 :
1659 : // If there is no current program, this is silently ignored.
1660 : // Any checks below this depend on a program being available.
1661 0 : if (!mCurrentProgram)
1662 0 : return NS_OK;
1663 :
1664 0 : if (!mBoundElementArrayBuffer)
1665 0 : return ErrorInvalidOperation("DrawElements: must have element array buffer binding");
1666 :
1667 0 : if (!mBoundElementArrayBuffer->Data())
1668 0 : return ErrorInvalidOperation("drawElements: bound element array buffer doesn't have any data");
1669 :
1670 0 : CheckedUint32 checked_neededByteCount = checked_byteCount + byteOffset;
1671 :
1672 0 : if (!checked_neededByteCount.valid())
1673 0 : return ErrorInvalidOperation("DrawElements: overflow in byteOffset+byteCount");
1674 :
1675 0 : if (checked_neededByteCount.value() > mBoundElementArrayBuffer->ByteLength())
1676 0 : return ErrorInvalidOperation("DrawElements: bound element array buffer is too small for given count and offset");
1677 :
1678 0 : PRInt32 maxAllowedCount = 0;
1679 0 : if (!ValidateBuffers(&maxAllowedCount, "drawElements"))
1680 0 : return NS_OK;
1681 :
1682 : PRInt32 maxIndex
1683 : = type == LOCAL_GL_UNSIGNED_SHORT
1684 0 : ? mBoundElementArrayBuffer->FindMaxUshortElement()
1685 0 : : mBoundElementArrayBuffer->FindMaxUbyteElement();
1686 :
1687 0 : CheckedInt32 checked_maxIndexPlusOne = CheckedInt32(maxIndex) + 1;
1688 :
1689 0 : if (!checked_maxIndexPlusOne.valid() ||
1690 0 : checked_maxIndexPlusOne.value() > maxAllowedCount)
1691 : {
1692 : // the index array contains invalid indices for the current drawing state, but they
1693 : // might not be used by the present drawElements call, depending on first and count.
1694 :
1695 : PRInt32 maxIndexInSubArray
1696 : = type == LOCAL_GL_UNSIGNED_SHORT
1697 0 : ? mBoundElementArrayBuffer->FindMaxElementInSubArray<GLushort>(count, byteOffset)
1698 0 : : mBoundElementArrayBuffer->FindMaxElementInSubArray<GLubyte>(count, byteOffset);
1699 :
1700 0 : CheckedInt32 checked_maxIndexInSubArrayPlusOne = CheckedInt32(maxIndexInSubArray) + 1;
1701 :
1702 0 : if (!checked_maxIndexInSubArrayPlusOne.valid() ||
1703 0 : checked_maxIndexInSubArrayPlusOne.value() > maxAllowedCount)
1704 : {
1705 : return ErrorInvalidOperation(
1706 : "DrawElements: bound vertex attribute buffers do not have sufficient "
1707 0 : "size for given indices from the bound element array");
1708 : }
1709 : }
1710 :
1711 0 : MakeContextCurrent();
1712 :
1713 0 : if (mBoundFramebuffer) {
1714 0 : if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
1715 0 : return ErrorInvalidFramebufferOperation("drawElements: incomplete framebuffer");
1716 : } else {
1717 0 : EnsureBackbufferClearedAsNeeded();
1718 : }
1719 :
1720 0 : BindFakeBlackTextures();
1721 0 : if (!DoFakeVertexAttrib0(checked_maxIndexPlusOne.value()))
1722 0 : return NS_OK;
1723 :
1724 0 : SetupRobustnessTimer();
1725 0 : gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
1726 :
1727 0 : UndoFakeVertexAttrib0();
1728 0 : UnbindFakeBlackTextures();
1729 :
1730 0 : mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
1731 0 : Invalidate();
1732 :
1733 0 : return NS_OK;
1734 : }
1735 :
1736 0 : NS_IMETHODIMP WebGLContext::Enable(WebGLenum cap)
1737 : {
1738 0 : if (!IsContextStable())
1739 0 : return NS_OK;
1740 :
1741 0 : if (!ValidateCapabilityEnum(cap, "enable"))
1742 0 : return NS_OK;
1743 :
1744 0 : switch(cap) {
1745 : case LOCAL_GL_SCISSOR_TEST:
1746 0 : mScissorTestEnabled = 1;
1747 0 : break;
1748 : case LOCAL_GL_DITHER:
1749 0 : mDitherEnabled = 1;
1750 0 : break;
1751 : }
1752 :
1753 0 : MakeContextCurrent();
1754 0 : gl->fEnable(cap);
1755 0 : return NS_OK;
1756 : }
1757 :
1758 0 : NS_IMETHODIMP WebGLContext::Disable(WebGLenum cap)
1759 : {
1760 0 : if (!IsContextStable())
1761 0 : return NS_OK;
1762 :
1763 0 : if (!ValidateCapabilityEnum(cap, "disable"))
1764 0 : return NS_OK;
1765 :
1766 0 : switch(cap) {
1767 : case LOCAL_GL_SCISSOR_TEST:
1768 0 : mScissorTestEnabled = 0;
1769 0 : break;
1770 : case LOCAL_GL_DITHER:
1771 0 : mDitherEnabled = 0;
1772 0 : break;
1773 : }
1774 :
1775 0 : MakeContextCurrent();
1776 0 : gl->fDisable(cap);
1777 0 : return NS_OK;
1778 : }
1779 :
1780 : NS_IMETHODIMP
1781 0 : WebGLContext::EnableVertexAttribArray(WebGLuint index)
1782 : {
1783 0 : if (!IsContextStable())
1784 0 : return NS_OK;
1785 :
1786 0 : if (!ValidateAttribIndex(index, "enableVertexAttribArray"))
1787 0 : return NS_OK;
1788 :
1789 0 : MakeContextCurrent();
1790 :
1791 0 : gl->fEnableVertexAttribArray(index);
1792 0 : mAttribBuffers[index].enabled = true;
1793 :
1794 0 : return NS_OK;
1795 : }
1796 :
1797 : NS_IMETHODIMP
1798 0 : WebGLContext::FramebufferRenderbuffer(WebGLenum target, WebGLenum attachment, WebGLenum rbtarget, nsIWebGLRenderbuffer *rbobj)
1799 : {
1800 0 : if (!IsContextStable())
1801 0 : return NS_OK;
1802 :
1803 0 : if (!mBoundFramebuffer)
1804 0 : return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
1805 :
1806 0 : return mBoundFramebuffer->FramebufferRenderbuffer(target, attachment, rbtarget, rbobj);
1807 : }
1808 :
1809 : NS_IMETHODIMP
1810 0 : WebGLContext::FramebufferTexture2D(WebGLenum target,
1811 : WebGLenum attachment,
1812 : WebGLenum textarget,
1813 : nsIWebGLTexture *tobj,
1814 : WebGLint level)
1815 : {
1816 0 : if (!IsContextStable())
1817 0 : return NS_OK;
1818 :
1819 0 : if (mBoundFramebuffer)
1820 0 : return mBoundFramebuffer->FramebufferTexture2D(target, attachment, textarget, tobj, level);
1821 : else
1822 0 : return ErrorInvalidOperation("framebufferTexture2D: cannot modify framebuffer 0");
1823 : }
1824 :
1825 0 : GL_SAME_METHOD_0(Flush, Flush)
1826 :
1827 0 : GL_SAME_METHOD_0(Finish, Finish)
1828 :
1829 : NS_IMETHODIMP
1830 0 : WebGLContext::FrontFace(WebGLenum mode)
1831 : {
1832 0 : if (!IsContextStable())
1833 0 : return NS_OK;
1834 :
1835 0 : switch (mode) {
1836 : case LOCAL_GL_CW:
1837 : case LOCAL_GL_CCW:
1838 : break;
1839 : default:
1840 0 : return ErrorInvalidEnumInfo("frontFace: mode", mode);
1841 : }
1842 :
1843 0 : MakeContextCurrent();
1844 0 : gl->fFrontFace(mode);
1845 0 : return NS_OK;
1846 : }
1847 :
1848 : // returns an object: { size: ..., type: ..., name: ... }
1849 : NS_IMETHODIMP
1850 0 : WebGLContext::GetActiveAttrib(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLActiveInfo **retval)
1851 : {
1852 0 : if (!IsContextStable())
1853 0 : return NS_OK;
1854 :
1855 0 : *retval = nsnull;
1856 :
1857 : WebGLuint progname;
1858 : WebGLProgram *prog;
1859 0 : if (!GetConcreteObjectAndGLName("getActiveAttrib: program", pobj, &prog, &progname))
1860 0 : return NS_OK;
1861 :
1862 0 : MakeContextCurrent();
1863 :
1864 0 : GLint len = 0;
1865 0 : gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len);
1866 0 : if (len == 0)
1867 0 : return NS_OK;
1868 :
1869 0 : nsAutoArrayPtr<char> name(new char[len]);
1870 0 : GLint attrsize = 0;
1871 0 : GLuint attrtype = 0;
1872 :
1873 0 : gl->fGetActiveAttrib(progname, index, len, &len, &attrsize, &attrtype, name);
1874 0 : if (attrsize == 0 || attrtype == 0) {
1875 0 : *retval = nsnull;
1876 0 : return NS_OK;
1877 : }
1878 :
1879 0 : nsCString reverseMappedName;
1880 0 : prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
1881 :
1882 0 : WebGLActiveInfo *retActiveInfo = new WebGLActiveInfo(attrsize, attrtype, reverseMappedName);
1883 0 : NS_ADDREF(*retval = retActiveInfo);
1884 :
1885 0 : return NS_OK;
1886 : }
1887 :
1888 : NS_IMETHODIMP
1889 0 : WebGLContext::GenerateMipmap(WebGLenum target)
1890 : {
1891 0 : if (!IsContextStable())
1892 0 : return NS_OK;
1893 :
1894 0 : if (!ValidateTextureTargetEnum(target, "generateMipmap"))
1895 0 : return NS_OK;
1896 :
1897 0 : WebGLTexture *tex = activeBoundTextureForTarget(target);
1898 :
1899 0 : if (!tex)
1900 0 : return ErrorInvalidOperation("generateMipmap: no texture is bound to this target");
1901 :
1902 0 : if (!tex->IsFirstImagePowerOfTwo()) {
1903 0 : return ErrorInvalidOperation("generateMipmap: the width or height of this texture is not a power of two");
1904 : }
1905 :
1906 0 : if (!tex->AreAllLevel0ImageInfosEqual()) {
1907 0 : return ErrorInvalidOperation("generateMipmap: the six faces of this cube map have different dimensions, format, or type.");
1908 : }
1909 :
1910 0 : tex->SetGeneratedMipmap();
1911 :
1912 0 : MakeContextCurrent();
1913 0 : gl->fGenerateMipmap(target);
1914 0 : return NS_OK;
1915 : }
1916 :
1917 : NS_IMETHODIMP
1918 0 : WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLActiveInfo **retval)
1919 : {
1920 0 : if (!IsContextStable())
1921 0 : return NS_OK;
1922 :
1923 0 : *retval = nsnull;
1924 :
1925 : WebGLuint progname;
1926 : WebGLProgram *prog;
1927 0 : if (!GetConcreteObjectAndGLName("getActiveUniform: program", pobj, &prog, &progname))
1928 0 : return NS_OK;
1929 :
1930 0 : MakeContextCurrent();
1931 :
1932 0 : GLint len = 0;
1933 0 : gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &len);
1934 0 : if (len == 0)
1935 0 : *retval = nsnull;
1936 :
1937 0 : nsAutoArrayPtr<char> name(new char[len]);
1938 :
1939 0 : GLint usize = 0;
1940 0 : GLuint utype = 0;
1941 :
1942 0 : gl->fGetActiveUniform(progname, index, len, &len, &usize, &utype, name);
1943 0 : if (len == 0 || usize == 0 || utype == 0) {
1944 0 : *retval = nsnull;
1945 0 : return NS_OK;
1946 : }
1947 :
1948 0 : nsCString reverseMappedName;
1949 0 : prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
1950 :
1951 : // OpenGL ES 2.0 specifies that if foo is a uniform array, GetActiveUniform returns its name as "foo[0]".
1952 : // See section 2.10 page 35 in the OpenGL ES 2.0.24 specification:
1953 : //
1954 : // > If the active uniform is an array, the uniform name returned in name will always
1955 : // > be the name of the uniform array appended with "[0]".
1956 : //
1957 : // There is no such requirement in the OpenGL (non-ES) spec and indeed we have OpenGL implementations returning
1958 : // "foo" instead of "foo[0]". So, when implementing WebGL on top of desktop OpenGL, we must check if the
1959 : // returned name ends in [0], and if it doesn't, append that.
1960 : //
1961 : // In principle we don't need to do that on OpenGL ES, but this is such a tricky difference between the ES and non-ES
1962 : // specs that it seems probable that some ES implementers will overlook it. Since the work-around is quite cheap,
1963 : // we do it unconditionally.
1964 0 : if (usize > 1 && reverseMappedName.CharAt(reverseMappedName.Length()-1) != ']')
1965 0 : reverseMappedName.AppendLiteral("[0]");
1966 :
1967 0 : WebGLActiveInfo *retActiveInfo = new WebGLActiveInfo(usize, utype, reverseMappedName);
1968 0 : NS_ADDREF(*retval = retActiveInfo);
1969 0 : return NS_OK;
1970 : }
1971 :
1972 : NS_IMETHODIMP
1973 0 : WebGLContext::GetAttachedShaders(nsIWebGLProgram *pobj, nsIVariant **retval)
1974 : {
1975 0 : if (!IsContextStable())
1976 0 : return NS_OK;
1977 :
1978 0 : *retval = nsnull;
1979 :
1980 : WebGLProgram *prog;
1981 : bool isNull;
1982 0 : if (!GetConcreteObject("getAttachedShaders", pobj, &prog, &isNull))
1983 0 : return NS_OK;
1984 :
1985 0 : nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
1986 0 : NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
1987 :
1988 0 : MakeContextCurrent();
1989 :
1990 0 : if (isNull) {
1991 0 : wrval->SetAsEmpty();
1992 : // note no return, we still want to return the variant
1993 0 : ErrorInvalidValue("getAttachedShaders: invalid program");
1994 0 : } else if (prog->AttachedShaders().Length() == 0) {
1995 0 : wrval->SetAsEmptyArray();
1996 : } else {
1997 0 : wrval->SetAsArray(nsIDataType::VTYPE_INTERFACE,
1998 : &NS_GET_IID(nsIWebGLShader),
1999 0 : prog->AttachedShaders().Length(),
2000 : const_cast<void*>( // @#$% SetAsArray doesn't accept a const void*
2001 : static_cast<const void*>(
2002 0 : prog->AttachedShaders().Elements()
2003 : )
2004 : )
2005 0 : );
2006 : }
2007 :
2008 0 : *retval = wrval.forget().get();
2009 :
2010 0 : return NS_OK;
2011 : }
2012 :
2013 : NS_IMETHODIMP
2014 0 : WebGLContext::GetAttribLocation(nsIWebGLProgram *pobj,
2015 : const nsAString& name,
2016 : PRInt32 *retval)
2017 : {
2018 0 : *retval = -1;
2019 :
2020 0 : if (!IsContextStable())
2021 0 : return NS_OK;
2022 :
2023 : WebGLuint progname;
2024 : WebGLProgram *prog;
2025 0 : if (!GetConcreteObjectAndGLName("getAttribLocation: program", pobj, &prog, &progname))
2026 0 : return NS_OK;
2027 :
2028 0 : if (!ValidateGLSLVariableName(name, "getAttribLocation"))
2029 0 : return NS_OK;
2030 :
2031 0 : NS_LossyConvertUTF16toASCII cname(name);
2032 0 : nsCString mappedName;
2033 0 : prog->MapIdentifier(cname, &mappedName);
2034 :
2035 0 : MakeContextCurrent();
2036 0 : *retval = gl->fGetAttribLocation(progname, mappedName.get());
2037 0 : return NS_OK;
2038 : }
2039 :
2040 : NS_IMETHODIMP
2041 0 : WebGLContext::GetParameter(PRUint32 pname, nsIVariant **retval)
2042 : {
2043 0 : if (!IsContextStable())
2044 0 : return NS_OK;
2045 :
2046 0 : *retval = nsnull;
2047 :
2048 0 : nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
2049 0 : NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
2050 :
2051 0 : MakeContextCurrent();
2052 :
2053 0 : if (MinCapabilityMode()) {
2054 0 : bool override = true;
2055 0 : switch(pname) {
2056 : //
2057 : // Single-value params
2058 : //
2059 :
2060 : // int
2061 : case LOCAL_GL_MAX_VERTEX_ATTRIBS:
2062 0 : wrval->SetAsInt32(MINVALUE_GL_MAX_VERTEX_ATTRIBS);
2063 0 : break;
2064 :
2065 : case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
2066 0 : wrval->SetAsInt32(MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS);
2067 0 : break;
2068 :
2069 : case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
2070 0 : wrval->SetAsInt32(MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS);
2071 0 : break;
2072 :
2073 : case LOCAL_GL_MAX_VARYING_VECTORS:
2074 0 : wrval->SetAsInt32(MINVALUE_GL_MAX_VARYING_VECTORS);
2075 0 : break;
2076 :
2077 : case LOCAL_GL_MAX_TEXTURE_SIZE:
2078 0 : wrval->SetAsInt32(MINVALUE_GL_MAX_TEXTURE_SIZE);
2079 0 : break;
2080 :
2081 : case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
2082 0 : wrval->SetAsInt32(MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE);
2083 0 : break;
2084 :
2085 : case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
2086 0 : wrval->SetAsInt32(MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS);
2087 0 : break;
2088 :
2089 : case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2090 0 : wrval->SetAsInt32(MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
2091 0 : break;
2092 :
2093 : case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
2094 0 : wrval->SetAsInt32(MINVALUE_GL_MAX_RENDERBUFFER_SIZE);
2095 0 : break;
2096 :
2097 : default:
2098 0 : override = false;
2099 : }
2100 :
2101 0 : if (override) {
2102 0 : *retval = wrval.forget().get();
2103 0 : return NS_OK;
2104 : }
2105 : }
2106 :
2107 0 : switch (pname) {
2108 : //
2109 : // String params
2110 : //
2111 :
2112 : case LOCAL_GL_VENDOR:
2113 0 : wrval->SetAsDOMString(NS_LITERAL_STRING("Mozilla"));
2114 0 : break;
2115 : case LOCAL_GL_RENDERER:
2116 0 : wrval->SetAsDOMString(NS_LITERAL_STRING("Mozilla"));
2117 0 : break;
2118 : case LOCAL_GL_VERSION:
2119 0 : wrval->SetAsDOMString(NS_LITERAL_STRING("WebGL 1.0"));
2120 0 : break;
2121 : case LOCAL_GL_SHADING_LANGUAGE_VERSION:
2122 0 : wrval->SetAsDOMString(NS_LITERAL_STRING("WebGL GLSL ES 1.0"));
2123 0 : break;
2124 :
2125 : //
2126 : // Single-value params
2127 : //
2128 :
2129 : // int
2130 : case LOCAL_GL_CULL_FACE_MODE:
2131 : case LOCAL_GL_FRONT_FACE:
2132 : case LOCAL_GL_ACTIVE_TEXTURE:
2133 : case LOCAL_GL_STENCIL_CLEAR_VALUE:
2134 : case LOCAL_GL_STENCIL_FUNC:
2135 : case LOCAL_GL_STENCIL_REF:
2136 : case LOCAL_GL_STENCIL_FAIL:
2137 : case LOCAL_GL_STENCIL_PASS_DEPTH_FAIL:
2138 : case LOCAL_GL_STENCIL_PASS_DEPTH_PASS:
2139 : case LOCAL_GL_STENCIL_BACK_FUNC:
2140 : case LOCAL_GL_STENCIL_BACK_REF:
2141 : case LOCAL_GL_STENCIL_BACK_FAIL:
2142 : case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL:
2143 : case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS:
2144 : case LOCAL_GL_DEPTH_FUNC:
2145 : case LOCAL_GL_BLEND_SRC_RGB:
2146 : case LOCAL_GL_BLEND_SRC_ALPHA:
2147 : case LOCAL_GL_BLEND_DST_RGB:
2148 : case LOCAL_GL_BLEND_DST_ALPHA:
2149 : case LOCAL_GL_BLEND_EQUATION_RGB:
2150 : case LOCAL_GL_BLEND_EQUATION_ALPHA:
2151 : case LOCAL_GL_UNPACK_ALIGNMENT:
2152 : case LOCAL_GL_PACK_ALIGNMENT:
2153 : case LOCAL_GL_GENERATE_MIPMAP_HINT:
2154 : case LOCAL_GL_SUBPIXEL_BITS:
2155 : case LOCAL_GL_MAX_TEXTURE_SIZE:
2156 : case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
2157 : case LOCAL_GL_SAMPLE_BUFFERS:
2158 : case LOCAL_GL_SAMPLES:
2159 : case LOCAL_GL_MAX_VERTEX_ATTRIBS:
2160 : case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2161 : case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2162 : case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
2163 : case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
2164 : case LOCAL_GL_RED_BITS:
2165 : case LOCAL_GL_GREEN_BITS:
2166 : case LOCAL_GL_BLUE_BITS:
2167 : case LOCAL_GL_ALPHA_BITS:
2168 : case LOCAL_GL_DEPTH_BITS:
2169 : case LOCAL_GL_STENCIL_BITS:
2170 : {
2171 0 : GLint i = 0;
2172 0 : gl->fGetIntegerv(pname, &i);
2173 0 : wrval->SetAsInt32(i);
2174 : }
2175 0 : break;
2176 : case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
2177 0 : if (mEnabledExtensions[WebGL_OES_standard_derivatives]) {
2178 0 : GLint i = 0;
2179 0 : gl->fGetIntegerv(pname, &i);
2180 0 : wrval->SetAsInt32(i);
2181 : }
2182 : else
2183 0 : return ErrorInvalidEnum("getParameter: parameter", pname);
2184 0 : break;
2185 :
2186 : case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
2187 0 : wrval->SetAsInt32(mGLMaxVertexUniformVectors);
2188 0 : break;
2189 :
2190 : case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
2191 0 : wrval->SetAsInt32(mGLMaxFragmentUniformVectors);
2192 0 : break;
2193 :
2194 : case LOCAL_GL_MAX_VARYING_VECTORS:
2195 0 : wrval->SetAsInt32(mGLMaxVaryingVectors);
2196 0 : break;
2197 :
2198 : case LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
2199 0 : wrval->SetAsInt32(0);
2200 0 : break;
2201 : case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS:
2202 0 : wrval->SetAsEmptyArray();
2203 0 : break;
2204 :
2205 : // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as
2206 : // javascript integer values. We just return them as doubles and javascript doesn't care.
2207 : case LOCAL_GL_STENCIL_BACK_VALUE_MASK:
2208 : case LOCAL_GL_STENCIL_BACK_WRITEMASK:
2209 : case LOCAL_GL_STENCIL_VALUE_MASK:
2210 : case LOCAL_GL_STENCIL_WRITEMASK:
2211 : {
2212 0 : GLint i = 0; // the GL api (glGetIntegerv) only does signed ints
2213 0 : gl->fGetIntegerv(pname, &i);
2214 0 : GLuint i_unsigned(i); // this is where -1 becomes 2^32-1
2215 0 : double i_double(i_unsigned); // pass as FP value to allow large values such as 2^32-1.
2216 0 : wrval->SetAsDouble(i_double);
2217 : }
2218 0 : break;
2219 :
2220 : // float
2221 : case LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
2222 0 : if (mEnabledExtensions[WebGL_EXT_texture_filter_anisotropic]) {
2223 0 : GLfloat f = 0.f;
2224 0 : gl->fGetFloatv(pname, &f);
2225 0 : wrval->SetAsFloat(f);
2226 : } else {
2227 0 : return ErrorInvalidEnum("getParameter: parameter", pname);
2228 : }
2229 0 : break;
2230 : case LOCAL_GL_DEPTH_CLEAR_VALUE:
2231 : case LOCAL_GL_LINE_WIDTH:
2232 : case LOCAL_GL_POLYGON_OFFSET_FACTOR:
2233 : case LOCAL_GL_POLYGON_OFFSET_UNITS:
2234 : case LOCAL_GL_SAMPLE_COVERAGE_VALUE:
2235 : {
2236 0 : GLfloat f = 0.f;
2237 0 : gl->fGetFloatv(pname, &f);
2238 0 : wrval->SetAsFloat(f);
2239 : }
2240 0 : break;
2241 :
2242 : // bool
2243 : case LOCAL_GL_BLEND:
2244 : case LOCAL_GL_DEPTH_TEST:
2245 : case LOCAL_GL_STENCIL_TEST:
2246 : case LOCAL_GL_CULL_FACE:
2247 : case LOCAL_GL_DITHER:
2248 : case LOCAL_GL_POLYGON_OFFSET_FILL:
2249 : case LOCAL_GL_SCISSOR_TEST:
2250 : case LOCAL_GL_SAMPLE_COVERAGE_INVERT:
2251 : case LOCAL_GL_DEPTH_WRITEMASK:
2252 : {
2253 0 : realGLboolean b = 0;
2254 0 : gl->fGetBooleanv(pname, &b);
2255 0 : wrval->SetAsBool(bool(b));
2256 : }
2257 0 : break;
2258 :
2259 : // bool, WebGL-specific
2260 : case UNPACK_FLIP_Y_WEBGL:
2261 0 : wrval->SetAsBool(mPixelStoreFlipY);
2262 0 : break;
2263 : case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2264 0 : wrval->SetAsBool(mPixelStorePremultiplyAlpha);
2265 0 : break;
2266 :
2267 : // uint, WebGL-specific
2268 : case UNPACK_COLORSPACE_CONVERSION_WEBGL:
2269 0 : wrval->SetAsUint32(mPixelStoreColorspaceConversion);
2270 0 : break;
2271 :
2272 : //
2273 : // Complex values
2274 : //
2275 : case LOCAL_GL_DEPTH_RANGE: // 2 floats
2276 : case LOCAL_GL_ALIASED_POINT_SIZE_RANGE: // 2 floats
2277 : case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: // 2 floats
2278 : {
2279 0 : GLfloat fv[2] = { 0 };
2280 0 : gl->fGetFloatv(pname, fv);
2281 0 : wrval->SetAsArray(nsIDataType::VTYPE_FLOAT, nsnull,
2282 0 : 2, static_cast<void*>(fv));
2283 : }
2284 0 : break;
2285 :
2286 : case LOCAL_GL_COLOR_CLEAR_VALUE: // 4 floats
2287 : case LOCAL_GL_BLEND_COLOR: // 4 floats
2288 : {
2289 0 : GLfloat fv[4] = { 0 };
2290 0 : gl->fGetFloatv(pname, fv);
2291 0 : wrval->SetAsArray(nsIDataType::VTYPE_FLOAT, nsnull,
2292 0 : 4, static_cast<void*>(fv));
2293 : }
2294 0 : break;
2295 :
2296 : case LOCAL_GL_MAX_VIEWPORT_DIMS: // 2 ints
2297 : {
2298 0 : GLint iv[2] = { 0 };
2299 0 : gl->fGetIntegerv(pname, iv);
2300 0 : wrval->SetAsArray(nsIDataType::VTYPE_INT32, nsnull,
2301 0 : 2, static_cast<void*>(iv));
2302 : }
2303 0 : break;
2304 :
2305 : case LOCAL_GL_SCISSOR_BOX: // 4 ints
2306 : case LOCAL_GL_VIEWPORT: // 4 ints
2307 : {
2308 0 : GLint iv[4] = { 0 };
2309 0 : gl->fGetIntegerv(pname, iv);
2310 0 : wrval->SetAsArray(nsIDataType::VTYPE_INT32, nsnull,
2311 0 : 4, static_cast<void*>(iv));
2312 : }
2313 0 : break;
2314 :
2315 : case LOCAL_GL_COLOR_WRITEMASK: // 4 bools
2316 : {
2317 0 : realGLboolean gl_bv[4] = { 0 };
2318 0 : gl->fGetBooleanv(pname, gl_bv);
2319 0 : bool pr_bv[4] = { (bool)gl_bv[0], (bool)gl_bv[1], (bool)gl_bv[2], (bool)gl_bv[3] };
2320 0 : wrval->SetAsArray(nsIDataType::VTYPE_BOOL, nsnull,
2321 0 : 4, static_cast<void*>(pr_bv));
2322 : }
2323 0 : break;
2324 :
2325 : case LOCAL_GL_ARRAY_BUFFER_BINDING:
2326 0 : wrval->SetAsISupports(mBoundArrayBuffer);
2327 0 : break;
2328 :
2329 : case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING:
2330 0 : wrval->SetAsISupports(mBoundElementArrayBuffer);
2331 0 : break;
2332 :
2333 : case LOCAL_GL_RENDERBUFFER_BINDING:
2334 0 : wrval->SetAsISupports(mBoundRenderbuffer);
2335 0 : break;
2336 :
2337 : case LOCAL_GL_FRAMEBUFFER_BINDING:
2338 0 : wrval->SetAsISupports(mBoundFramebuffer);
2339 0 : break;
2340 :
2341 : case LOCAL_GL_CURRENT_PROGRAM:
2342 0 : wrval->SetAsISupports(mCurrentProgram);
2343 0 : break;
2344 :
2345 : case LOCAL_GL_TEXTURE_BINDING_2D:
2346 0 : wrval->SetAsISupports(mBound2DTextures[mActiveTexture]);
2347 0 : break;
2348 :
2349 : case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP:
2350 0 : wrval->SetAsISupports(mBoundCubeMapTextures[mActiveTexture]);
2351 0 : break;
2352 :
2353 : default:
2354 0 : return ErrorInvalidEnumInfo("getParameter: parameter", pname);
2355 : }
2356 :
2357 0 : *retval = wrval.forget().get();
2358 :
2359 0 : return NS_OK;
2360 : }
2361 :
2362 : NS_IMETHODIMP
2363 0 : WebGLContext::GetBufferParameter(WebGLenum target, WebGLenum pname, nsIVariant **retval)
2364 : {
2365 0 : if (!IsContextStable())
2366 0 : return NS_OK;
2367 :
2368 0 : *retval = nsnull;
2369 :
2370 0 : nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
2371 0 : NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
2372 :
2373 0 : if (target != LOCAL_GL_ARRAY_BUFFER && target != LOCAL_GL_ELEMENT_ARRAY_BUFFER)
2374 0 : return ErrorInvalidEnumInfo("getBufferParameter: target", target);
2375 :
2376 0 : MakeContextCurrent();
2377 :
2378 0 : switch (pname) {
2379 : case LOCAL_GL_BUFFER_SIZE:
2380 : case LOCAL_GL_BUFFER_USAGE:
2381 : case LOCAL_GL_BUFFER_ACCESS:
2382 : case LOCAL_GL_BUFFER_MAPPED:
2383 : {
2384 0 : GLint i = 0;
2385 0 : gl->fGetBufferParameteriv(target, pname, &i);
2386 0 : wrval->SetAsInt32(i);
2387 : }
2388 : break;
2389 :
2390 : default:
2391 0 : return ErrorInvalidEnumInfo("getBufferParameter: parameter", pname);
2392 : }
2393 :
2394 0 : *retval = wrval.forget().get();
2395 :
2396 0 : return NS_OK;
2397 : }
2398 :
2399 : NS_IMETHODIMP
2400 0 : WebGLContext::GetFramebufferAttachmentParameter(WebGLenum target, WebGLenum attachment, WebGLenum pname, nsIVariant **retval)
2401 : {
2402 0 : if (!IsContextStable())
2403 0 : return NS_OK;
2404 :
2405 0 : *retval = nsnull;
2406 :
2407 0 : nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
2408 0 : NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
2409 :
2410 0 : if (target != LOCAL_GL_FRAMEBUFFER)
2411 0 : return ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: target", target);
2412 :
2413 0 : switch (attachment) {
2414 : case LOCAL_GL_COLOR_ATTACHMENT0:
2415 : case LOCAL_GL_DEPTH_ATTACHMENT:
2416 : case LOCAL_GL_STENCIL_ATTACHMENT:
2417 : case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
2418 : break;
2419 : default:
2420 0 : return ErrorInvalidEnumInfo("GetFramebufferAttachmentParameter: attachment", attachment);
2421 : }
2422 :
2423 0 : if (!mBoundFramebuffer)
2424 0 : return ErrorInvalidOperation("GetFramebufferAttachmentParameter: cannot query framebuffer 0");
2425 :
2426 0 : MakeContextCurrent();
2427 :
2428 0 : const WebGLFramebufferAttachment& fba = mBoundFramebuffer->GetAttachment(attachment);
2429 :
2430 0 : if (fba.Renderbuffer()) {
2431 0 : switch (pname) {
2432 : case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2433 0 : wrval->SetAsInt32(LOCAL_GL_RENDERBUFFER);
2434 0 : break;
2435 :
2436 : case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2437 0 : wrval->SetAsISupports(const_cast<WebGLRenderbuffer*>(fba.Renderbuffer()));
2438 0 : break;
2439 :
2440 : default:
2441 0 : return ErrorInvalidEnumInfo("GetFramebufferAttachmentParameter: pname", pname);
2442 : }
2443 0 : } else if (fba.Texture()) {
2444 0 : switch (pname) {
2445 : case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2446 0 : wrval->SetAsInt32(LOCAL_GL_TEXTURE);
2447 0 : break;
2448 :
2449 : case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2450 0 : wrval->SetAsISupports(const_cast<WebGLTexture*>(fba.Texture()));
2451 0 : break;
2452 :
2453 : case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2454 0 : wrval->SetAsInt32(fba.TextureLevel());
2455 0 : break;
2456 :
2457 : case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2458 0 : wrval->SetAsInt32(fba.TextureCubeMapFace());
2459 0 : break;
2460 :
2461 : default:
2462 0 : return ErrorInvalidEnumInfo("GetFramebufferAttachmentParameter: pname", pname);
2463 : }
2464 : } else {
2465 0 : switch (pname) {
2466 : case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2467 0 : wrval->SetAsInt32(LOCAL_GL_NONE);
2468 0 : break;
2469 :
2470 : default:
2471 0 : return ErrorInvalidEnumInfo("GetFramebufferAttachmentParameter: pname", pname);
2472 : }
2473 : }
2474 :
2475 0 : *retval = wrval.forget().get();
2476 :
2477 0 : return NS_OK;
2478 : }
2479 :
2480 : NS_IMETHODIMP
2481 0 : WebGLContext::GetRenderbufferParameter(WebGLenum target, WebGLenum pname, nsIVariant **retval)
2482 : {
2483 0 : if (!IsContextStable())
2484 0 : return NS_OK;
2485 :
2486 0 : *retval = nsnull;
2487 :
2488 0 : nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
2489 0 : NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
2490 :
2491 0 : if (target != LOCAL_GL_RENDERBUFFER)
2492 0 : return ErrorInvalidEnumInfo("GetRenderbufferParameter: target", target);
2493 :
2494 0 : MakeContextCurrent();
2495 :
2496 0 : switch (pname) {
2497 : case LOCAL_GL_RENDERBUFFER_WIDTH:
2498 : case LOCAL_GL_RENDERBUFFER_HEIGHT:
2499 : case LOCAL_GL_RENDERBUFFER_RED_SIZE:
2500 : case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
2501 : case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
2502 : case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
2503 : case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
2504 : case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
2505 : {
2506 0 : GLint i = 0;
2507 0 : gl->fGetRenderbufferParameteriv(target, pname, &i);
2508 0 : wrval->SetAsInt32(i);
2509 : }
2510 0 : break;
2511 : case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
2512 : {
2513 0 : GLint i = 0;
2514 0 : gl->fGetRenderbufferParameteriv(target, pname, &i);
2515 0 : if (i == LOCAL_GL_DEPTH24_STENCIL8)
2516 : {
2517 0 : i = LOCAL_GL_DEPTH_STENCIL;
2518 : }
2519 0 : wrval->SetAsInt32(i);
2520 : }
2521 0 : break;
2522 : default:
2523 0 : return ErrorInvalidEnumInfo("GetRenderbufferParameter: parameter", pname);
2524 : }
2525 :
2526 0 : *retval = wrval.forget().get();
2527 :
2528 0 : return NS_OK;
2529 : }
2530 :
2531 : NS_IMETHODIMP
2532 0 : WebGLContext::CreateBuffer(nsIWebGLBuffer **retval)
2533 : {
2534 0 : if (!IsContextStable())
2535 0 : return NS_OK;
2536 :
2537 0 : *retval = nsnull;
2538 :
2539 0 : WebGLBuffer *globj = new WebGLBuffer(this);
2540 0 : NS_ADDREF(*retval = globj);
2541 :
2542 0 : return NS_OK;
2543 : }
2544 :
2545 : NS_IMETHODIMP
2546 0 : WebGLContext::CreateTexture(nsIWebGLTexture **retval)
2547 : {
2548 0 : if (!IsContextStable())
2549 0 : return NS_OK;
2550 :
2551 0 : *retval = nsnull;
2552 :
2553 0 : MakeContextCurrent();
2554 :
2555 0 : WebGLTexture *globj = new WebGLTexture(this);
2556 0 : NS_ADDREF(*retval = globj);
2557 :
2558 0 : return NS_OK;
2559 : }
2560 :
2561 : NS_IMETHODIMP
2562 0 : WebGLContext::GetError(WebGLenum *_retval)
2563 : {
2564 0 : if (mContextStatus == ContextStable) {
2565 0 : MakeContextCurrent();
2566 0 : UpdateWebGLErrorAndClearGLError();
2567 0 : } else if (!mContextLostErrorSet) {
2568 0 : mWebGLError = LOCAL_GL_CONTEXT_LOST;
2569 0 : mContextLostErrorSet = true;
2570 : }
2571 :
2572 0 : *_retval = mWebGLError;
2573 0 : mWebGLError = LOCAL_GL_NO_ERROR;
2574 :
2575 0 : return NS_OK;
2576 : }
2577 :
2578 : NS_IMETHODIMP
2579 0 : WebGLContext::GetProgramParameter(nsIWebGLProgram *pobj, PRUint32 pname, nsIVariant **retval)
2580 : {
2581 0 : if (!IsContextStable())
2582 0 : return NS_OK;
2583 :
2584 0 : *retval = nsnull;
2585 :
2586 : WebGLuint progname;
2587 : bool isDeleted;
2588 : WebGLProgram *prog;
2589 0 : if (!GetConcreteObjectAndGLName("getProgramParameter: program", pobj, &prog, &progname, nsnull, &isDeleted))
2590 0 : return NS_OK;
2591 :
2592 0 : nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
2593 0 : NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
2594 :
2595 0 : MakeContextCurrent();
2596 :
2597 0 : switch (pname) {
2598 : case LOCAL_GL_CURRENT_PROGRAM:
2599 : case LOCAL_GL_ATTACHED_SHADERS:
2600 : case LOCAL_GL_INFO_LOG_LENGTH:
2601 : case LOCAL_GL_ACTIVE_UNIFORMS:
2602 : case LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH:
2603 : case LOCAL_GL_ACTIVE_ATTRIBUTES:
2604 : case LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
2605 : {
2606 0 : GLint i = 0;
2607 0 : gl->fGetProgramiv(progname, pname, &i);
2608 0 : wrval->SetAsInt32(i);
2609 : }
2610 0 : break;
2611 : case LOCAL_GL_DELETE_STATUS:
2612 0 : wrval->SetAsBool(prog->IsDeleteRequested());
2613 0 : break;
2614 : case LOCAL_GL_LINK_STATUS:
2615 : {
2616 0 : GLint i = 0;
2617 0 : gl->fGetProgramiv(progname, pname, &i);
2618 0 : wrval->SetAsBool(bool(i));
2619 : }
2620 0 : break;
2621 : case LOCAL_GL_VALIDATE_STATUS:
2622 : {
2623 0 : GLint i = 0;
2624 : #ifdef XP_MACOSX
2625 : // See comment in ValidateProgram below.
2626 : i = 1;
2627 : #else
2628 0 : gl->fGetProgramiv(progname, pname, &i);
2629 : #endif
2630 0 : wrval->SetAsBool(bool(i));
2631 : }
2632 0 : break;
2633 :
2634 : default:
2635 0 : return ErrorInvalidEnumInfo("GetProgramParameter: parameter", pname);
2636 : }
2637 :
2638 0 : *retval = wrval.forget().get();
2639 :
2640 0 : return NS_OK;
2641 : }
2642 :
2643 : NS_IMETHODIMP
2644 0 : WebGLContext::GetProgramInfoLog(nsIWebGLProgram *pobj, nsAString& retval)
2645 : {
2646 0 : if (!IsContextStable())
2647 : {
2648 0 : retval.SetIsVoid(true);
2649 0 : return NS_OK;
2650 : }
2651 :
2652 : WebGLuint progname;
2653 0 : if (!GetGLName<WebGLProgram>("getProgramInfoLog: program", pobj, &progname))
2654 0 : return NS_OK;
2655 :
2656 0 : MakeContextCurrent();
2657 :
2658 0 : GLint k = -1;
2659 0 : gl->fGetProgramiv(progname, LOCAL_GL_INFO_LOG_LENGTH, &k);
2660 0 : if (k == -1)
2661 0 : return NS_ERROR_FAILURE; // XXX GL error? shouldn't happen!
2662 :
2663 0 : if (k == 0) {
2664 0 : retval.Truncate();
2665 0 : return NS_OK;
2666 : }
2667 :
2668 0 : nsCAutoString log;
2669 0 : log.SetCapacity(k);
2670 :
2671 0 : gl->fGetProgramInfoLog(progname, k, &k, (char*) log.BeginWriting());
2672 :
2673 0 : log.SetLength(k);
2674 :
2675 0 : CopyASCIItoUTF16(log, retval);
2676 :
2677 0 : return NS_OK;
2678 : }
2679 :
2680 : // here we have to support all pnames with both int and float params.
2681 : // See this discussion:
2682 : // https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
2683 0 : nsresult WebGLContext::TexParameter_base(WebGLenum target, WebGLenum pname,
2684 : WebGLint *intParamPtr, WebGLfloat *floatParamPtr)
2685 : {
2686 0 : NS_ENSURE_TRUE(intParamPtr || floatParamPtr, NS_ERROR_FAILURE);
2687 :
2688 0 : WebGLint intParam = intParamPtr ? *intParamPtr : WebGLint(*floatParamPtr);
2689 0 : WebGLfloat floatParam = floatParamPtr ? *floatParamPtr : WebGLfloat(*intParamPtr);
2690 :
2691 0 : if (!ValidateTextureTargetEnum(target, "texParameter: target"))
2692 0 : return NS_OK;
2693 :
2694 0 : WebGLTexture *tex = activeBoundTextureForTarget(target);
2695 0 : if (!tex)
2696 0 : return ErrorInvalidOperation("texParameter: no texture is bound to this target");
2697 :
2698 0 : bool pnameAndParamAreIncompatible = false;
2699 0 : bool paramValueInvalid = false;
2700 :
2701 0 : switch (pname) {
2702 : case LOCAL_GL_TEXTURE_MIN_FILTER:
2703 0 : switch (intParam) {
2704 : case LOCAL_GL_NEAREST:
2705 : case LOCAL_GL_LINEAR:
2706 : case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
2707 : case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
2708 : case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
2709 : case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
2710 0 : tex->SetMinFilter(intParam);
2711 0 : break;
2712 : default:
2713 0 : pnameAndParamAreIncompatible = true;
2714 : }
2715 0 : break;
2716 : case LOCAL_GL_TEXTURE_MAG_FILTER:
2717 0 : switch (intParam) {
2718 : case LOCAL_GL_NEAREST:
2719 : case LOCAL_GL_LINEAR:
2720 0 : tex->SetMagFilter(intParam);
2721 0 : break;
2722 : default:
2723 0 : pnameAndParamAreIncompatible = true;
2724 : }
2725 0 : break;
2726 : case LOCAL_GL_TEXTURE_WRAP_S:
2727 0 : switch (intParam) {
2728 : case LOCAL_GL_CLAMP_TO_EDGE:
2729 : case LOCAL_GL_MIRRORED_REPEAT:
2730 : case LOCAL_GL_REPEAT:
2731 0 : tex->SetWrapS(intParam);
2732 0 : break;
2733 : default:
2734 0 : pnameAndParamAreIncompatible = true;
2735 : }
2736 0 : break;
2737 : case LOCAL_GL_TEXTURE_WRAP_T:
2738 0 : switch (intParam) {
2739 : case LOCAL_GL_CLAMP_TO_EDGE:
2740 : case LOCAL_GL_MIRRORED_REPEAT:
2741 : case LOCAL_GL_REPEAT:
2742 0 : tex->SetWrapT(intParam);
2743 0 : break;
2744 : default:
2745 0 : pnameAndParamAreIncompatible = true;
2746 : }
2747 0 : break;
2748 : case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
2749 0 : if (mEnabledExtensions[WebGL_EXT_texture_filter_anisotropic]) {
2750 0 : if (floatParamPtr && floatParam < 1.f)
2751 0 : paramValueInvalid = true;
2752 0 : else if (intParamPtr && intParam < 1)
2753 0 : paramValueInvalid = true;
2754 : }
2755 : else
2756 0 : pnameAndParamAreIncompatible = true;
2757 0 : break;
2758 : default:
2759 0 : return ErrorInvalidEnumInfo("texParameter: pname", pname);
2760 : }
2761 :
2762 0 : if (pnameAndParamAreIncompatible) {
2763 0 : if (intParamPtr)
2764 : return ErrorInvalidEnum("texParameteri: pname %x and param %x (decimal %d) are mutually incompatible",
2765 0 : pname, intParam, intParam);
2766 : else
2767 : return ErrorInvalidEnum("texParameterf: pname %x and param %g are mutually incompatible",
2768 0 : pname, floatParam);
2769 0 : } else if (paramValueInvalid) {
2770 0 : if (intParamPtr)
2771 : return ErrorInvalidValue("texParameteri: pname %x and param %x (decimal %d) is invalid",
2772 0 : pname, intParam, intParam);
2773 : else
2774 : return ErrorInvalidValue("texParameterf: pname %x and param %g is invalid",
2775 0 : pname, floatParam);
2776 : }
2777 :
2778 0 : MakeContextCurrent();
2779 0 : if (intParamPtr)
2780 0 : gl->fTexParameteri(target, pname, intParam);
2781 : else
2782 0 : gl->fTexParameterf(target, pname, floatParam);
2783 :
2784 0 : return NS_OK;
2785 : }
2786 :
2787 : NS_IMETHODIMP
2788 0 : WebGLContext::TexParameterf(WebGLenum target, WebGLenum pname, WebGLfloat param)
2789 : {
2790 0 : if (!IsContextStable())
2791 0 : return NS_OK;
2792 :
2793 0 : return TexParameter_base(target, pname, nsnull, ¶m);
2794 : }
2795 :
2796 : NS_IMETHODIMP
2797 0 : WebGLContext::TexParameteri(WebGLenum target, WebGLenum pname, WebGLint param)
2798 : {
2799 0 : if (!IsContextStable())
2800 0 : return NS_OK;
2801 :
2802 0 : return TexParameter_base(target, pname, ¶m, nsnull);
2803 : }
2804 :
2805 : NS_IMETHODIMP
2806 0 : WebGLContext::GetTexParameter(WebGLenum target, WebGLenum pname, nsIVariant **retval)
2807 : {
2808 0 : if (!IsContextStable())
2809 0 : return NS_OK;
2810 :
2811 0 : *retval = nsnull;
2812 :
2813 0 : MakeContextCurrent();
2814 :
2815 0 : if (!ValidateTextureTargetEnum(target, "getTexParameter: target"))
2816 0 : return NS_OK;
2817 :
2818 0 : if (!activeBoundTextureForTarget(target))
2819 0 : return ErrorInvalidOperation("getTexParameter: no texture bound");
2820 :
2821 0 : nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
2822 0 : NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
2823 :
2824 0 : switch (pname) {
2825 : case LOCAL_GL_TEXTURE_MIN_FILTER:
2826 : case LOCAL_GL_TEXTURE_MAG_FILTER:
2827 : case LOCAL_GL_TEXTURE_WRAP_S:
2828 : case LOCAL_GL_TEXTURE_WRAP_T:
2829 : {
2830 0 : GLint i = 0;
2831 0 : gl->fGetTexParameteriv(target, pname, &i);
2832 0 : wrval->SetAsInt32(i);
2833 : }
2834 0 : break;
2835 : case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
2836 0 : if (mEnabledExtensions[WebGL_EXT_texture_filter_anisotropic]) {
2837 0 : GLfloat f = 0.f;
2838 0 : gl->fGetTexParameterfv(target, pname, &f);
2839 0 : wrval->SetAsFloat(f);
2840 : }
2841 : else
2842 0 : return ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
2843 0 : break;
2844 :
2845 : default:
2846 0 : return ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
2847 : }
2848 :
2849 0 : *retval = wrval.forget().get();
2850 :
2851 0 : return NS_OK;
2852 : }
2853 :
2854 : /* any getUniform(in WebGLProgram program, in WebGLUniformLocation location) raises(DOMException); */
2855 : NS_IMETHODIMP
2856 0 : WebGLContext::GetUniform(nsIWebGLProgram *pobj, nsIWebGLUniformLocation *ploc, nsIVariant **retval)
2857 : {
2858 0 : if (!IsContextStable())
2859 0 : return NS_OK;
2860 :
2861 0 : *retval = nsnull;
2862 :
2863 : WebGLuint progname;
2864 : WebGLProgram *prog;
2865 0 : if (!GetConcreteObjectAndGLName("getUniform: program", pobj, &prog, &progname))
2866 0 : return NS_OK;
2867 :
2868 : WebGLUniformLocation *location;
2869 0 : if (!GetConcreteObject("getUniform: location", ploc, &location))
2870 0 : return NS_OK;
2871 :
2872 0 : if (location->Program() != prog)
2873 0 : return ErrorInvalidValue("GetUniform: this uniform location corresponds to another program");
2874 :
2875 0 : if (location->ProgramGeneration() != prog->Generation())
2876 0 : return ErrorInvalidOperation("GetUniform: this uniform location is obsolete since the program has been relinked");
2877 :
2878 0 : nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
2879 0 : NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
2880 :
2881 0 : MakeContextCurrent();
2882 :
2883 0 : GLint uniforms = 0;
2884 0 : GLint uniformNameMaxLength = 0;
2885 0 : gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORMS, &uniforms);
2886 0 : gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformNameMaxLength);
2887 :
2888 : // we now need the type info to switch between fGetUniformfv and fGetUniformiv
2889 : // the only way to get that is to iterate through all active uniforms by index until
2890 : // one matches the given uniform location.
2891 0 : GLenum uniformType = 0;
2892 0 : nsAutoArrayPtr<GLchar> uniformName(new GLchar[uniformNameMaxLength]);
2893 : // this buffer has 16 more bytes to be able to store [index] at the end.
2894 0 : nsAutoArrayPtr<GLchar> uniformNameBracketIndex(new GLchar[uniformNameMaxLength + 16]);
2895 :
2896 : GLint index;
2897 0 : for (index = 0; index < uniforms; ++index) {
2898 : GLsizei length;
2899 : GLint size;
2900 : gl->fGetActiveUniform(progname, index, uniformNameMaxLength, &length,
2901 0 : &size, &uniformType, uniformName);
2902 0 : if (gl->fGetUniformLocation(progname, uniformName) == location->Location())
2903 0 : break;
2904 :
2905 : // now we handle the case of array uniforms. In that case, fGetActiveUniform returned as 'size'
2906 : // the biggest index used plus one, so we need to loop over that. The 0 index has already been handled above,
2907 : // so we can start at one. For each index, we construct the string uniformName + "[" + index + "]".
2908 0 : if (size > 1) {
2909 0 : bool found_it = false;
2910 0 : if (uniformName[length - 1] == ']') { // if uniformName ends in [0]
2911 : // remove the [0] at the end
2912 0 : length -= 3;
2913 0 : uniformName[length] = 0;
2914 : }
2915 0 : for (GLint arrayIndex = 1; arrayIndex < size; arrayIndex++) {
2916 0 : sprintf(uniformNameBracketIndex.get(), "%s[%d]", uniformName.get(), arrayIndex);
2917 0 : if (gl->fGetUniformLocation(progname, uniformNameBracketIndex) == location->Location()) {
2918 0 : found_it = true;
2919 0 : break;
2920 : }
2921 : }
2922 0 : if (found_it) break;
2923 : }
2924 : }
2925 :
2926 0 : if (index == uniforms)
2927 0 : return NS_ERROR_FAILURE; // XXX GL error? shouldn't happen.
2928 :
2929 : GLenum baseType;
2930 : GLint unitSize;
2931 0 : if (!BaseTypeAndSizeFromUniformType(uniformType, &baseType, &unitSize))
2932 0 : return NS_ERROR_FAILURE;
2933 :
2934 : // this should never happen
2935 0 : if (unitSize > 16)
2936 0 : return NS_ERROR_FAILURE;
2937 :
2938 0 : if (baseType == LOCAL_GL_FLOAT) {
2939 0 : GLfloat fv[16] = { GLfloat(0) };
2940 0 : gl->fGetUniformfv(progname, location->Location(), fv);
2941 0 : if (unitSize == 1) {
2942 0 : wrval->SetAsFloat(fv[0]);
2943 : } else {
2944 0 : wrval->SetAsArray(nsIDataType::VTYPE_FLOAT, nsnull,
2945 0 : unitSize, static_cast<void*>(fv));
2946 : }
2947 0 : } else if (baseType == LOCAL_GL_INT) {
2948 0 : GLint iv[16] = { 0 };
2949 0 : gl->fGetUniformiv(progname, location->Location(), iv);
2950 0 : if (unitSize == 1) {
2951 0 : wrval->SetAsInt32(iv[0]);
2952 : } else {
2953 0 : wrval->SetAsArray(nsIDataType::VTYPE_INT32, nsnull,
2954 0 : unitSize, static_cast<void*>(iv));
2955 : }
2956 0 : } else if (baseType == LOCAL_GL_BOOL) {
2957 0 : GLint iv[16] = { 0 };
2958 0 : gl->fGetUniformiv(progname, location->Location(), iv);
2959 0 : if (unitSize == 1) {
2960 0 : wrval->SetAsBool(iv[0] ? true : false);
2961 : } else {
2962 0 : bool uv[16] = { 0 };
2963 0 : for (int k = 0; k < unitSize; k++)
2964 0 : uv[k] = iv[k] ? true : false;
2965 0 : wrval->SetAsArray(nsIDataType::VTYPE_BOOL, nsnull,
2966 0 : unitSize, static_cast<void*>(uv));
2967 : }
2968 : } else {
2969 0 : wrval->SetAsVoid();
2970 : }
2971 :
2972 0 : *retval = wrval.forget().get();
2973 :
2974 0 : return NS_OK;
2975 : }
2976 :
2977 : NS_IMETHODIMP
2978 0 : WebGLContext::GetUniformLocation(nsIWebGLProgram *pobj, const nsAString& name, nsIWebGLUniformLocation **retval)
2979 : {
2980 0 : if (!IsContextStable())
2981 0 : return NS_OK;
2982 :
2983 0 : *retval = nsnull;
2984 :
2985 : WebGLuint progname;
2986 : WebGLProgram *prog;
2987 0 : if (!GetConcreteObjectAndGLName("getUniformLocation: program", pobj, &prog, &progname))
2988 0 : return NS_OK;
2989 :
2990 0 : if (!ValidateGLSLVariableName(name, "getUniformLocation"))
2991 0 : return NS_OK;
2992 :
2993 0 : NS_LossyConvertUTF16toASCII cname(name);
2994 0 : nsCString mappedName;
2995 0 : prog->MapIdentifier(cname, &mappedName);
2996 :
2997 0 : MakeContextCurrent();
2998 0 : GLint intlocation = gl->fGetUniformLocation(progname, mappedName.get());
2999 :
3000 0 : WebGLUniformLocation *loc = nsnull;
3001 0 : if (intlocation >= 0)
3002 0 : NS_ADDREF(loc = new WebGLUniformLocation(this, prog, intlocation));
3003 0 : *retval = loc;
3004 0 : return NS_OK;
3005 : }
3006 :
3007 : NS_IMETHODIMP
3008 0 : WebGLContext::GetVertexAttrib(WebGLuint index, WebGLenum pname, nsIVariant **retval)
3009 : {
3010 0 : if (!IsContextStable())
3011 0 : return NS_OK;
3012 :
3013 0 : *retval = nsnull;
3014 :
3015 0 : if (!ValidateAttribIndex(index, "getVertexAttrib"))
3016 0 : return NS_OK;
3017 :
3018 0 : nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
3019 0 : NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
3020 :
3021 0 : MakeContextCurrent();
3022 :
3023 0 : switch (pname) {
3024 : case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
3025 0 : wrval->SetAsISupports(mAttribBuffers[index].buf);
3026 0 : break;
3027 :
3028 : case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE:
3029 0 : wrval->SetAsInt32(mAttribBuffers[index].stride);
3030 0 : break;
3031 :
3032 : case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
3033 : case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
3034 : {
3035 0 : GLint i = 0;
3036 0 : gl->fGetVertexAttribiv(index, pname, &i);
3037 0 : wrval->SetAsInt32(i);
3038 : }
3039 0 : break;
3040 :
3041 : case LOCAL_GL_CURRENT_VERTEX_ATTRIB:
3042 : {
3043 0 : WebGLfloat vec[4] = {0, 0, 0, 1};
3044 0 : if (index) {
3045 0 : gl->fGetVertexAttribfv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, &vec[0]);
3046 : } else {
3047 0 : vec[0] = mVertexAttrib0Vector[0];
3048 0 : vec[1] = mVertexAttrib0Vector[1];
3049 0 : vec[2] = mVertexAttrib0Vector[2];
3050 0 : vec[3] = mVertexAttrib0Vector[3];
3051 : }
3052 0 : wrval->SetAsArray(nsIDataType::VTYPE_FLOAT, nsnull,
3053 0 : 4, vec);
3054 : }
3055 0 : break;
3056 :
3057 : case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED:
3058 : case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
3059 : {
3060 0 : GLint i = 0;
3061 0 : gl->fGetVertexAttribiv(index, pname, &i);
3062 0 : wrval->SetAsBool(bool(i));
3063 : }
3064 0 : break;
3065 :
3066 : case LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER:
3067 0 : wrval->SetAsUint32(mAttribBuffers[index].byteOffset);
3068 0 : break;
3069 :
3070 : default:
3071 0 : return ErrorInvalidEnumInfo("getVertexAttrib: parameter", pname);
3072 : }
3073 :
3074 0 : *retval = wrval.forget().get();
3075 :
3076 0 : return NS_OK;
3077 : }
3078 :
3079 : /* GLuint getVertexAttribOffset (in GLuint index, in GLenum pname); */
3080 : NS_IMETHODIMP
3081 0 : WebGLContext::GetVertexAttribOffset(WebGLuint index, WebGLenum pname, WebGLuint *retval)
3082 : {
3083 0 : *retval = 0;
3084 0 : if (!IsContextStable())
3085 0 : return NS_OK;
3086 :
3087 0 : if (!ValidateAttribIndex(index, "getVertexAttribOffset"))
3088 0 : return NS_OK;
3089 :
3090 0 : if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER)
3091 0 : return ErrorInvalidEnum("getVertexAttribOffset: bad parameter");
3092 :
3093 0 : *retval = mAttribBuffers[index].byteOffset;
3094 0 : return NS_OK;
3095 : }
3096 :
3097 : NS_IMETHODIMP
3098 0 : WebGLContext::Hint(WebGLenum target, WebGLenum mode)
3099 : {
3100 0 : if (!IsContextStable())
3101 0 : return NS_OK;
3102 :
3103 0 : bool isValid = false;
3104 :
3105 0 : switch (target) {
3106 : case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
3107 0 : if (mEnabledExtensions[WebGL_OES_standard_derivatives])
3108 0 : isValid = true;
3109 0 : break;
3110 : }
3111 :
3112 0 : if (isValid) {
3113 0 : gl->fHint(target, mode);
3114 0 : return NS_OK;
3115 : }
3116 :
3117 0 : return ErrorInvalidEnum("hint: invalid hint");
3118 : }
3119 :
3120 : NS_IMETHODIMP
3121 0 : WebGLContext::IsBuffer(nsIWebGLBuffer *bobj, WebGLboolean *retval)
3122 : {
3123 0 : if (!IsContextStable())
3124 : {
3125 0 : *retval = false;
3126 0 : return NS_OK;
3127 : }
3128 :
3129 : bool isDeleted;
3130 : WebGLuint buffername;
3131 : WebGLBuffer *buffer;
3132 0 : *retval = GetConcreteObjectAndGLName("isBuffer", bobj, &buffer, &buffername, nsnull, &isDeleted) &&
3133 0 : !isDeleted &&
3134 0 : buffer->HasEverBeenBound();
3135 0 : return NS_OK;
3136 : }
3137 :
3138 : NS_IMETHODIMP
3139 0 : WebGLContext::IsFramebuffer(nsIWebGLFramebuffer *fbobj, WebGLboolean *retval)
3140 : {
3141 0 : if (!IsContextStable())
3142 : {
3143 0 : *retval = false;
3144 0 : return NS_OK;
3145 : }
3146 :
3147 : bool isDeleted;
3148 : WebGLuint fbname;
3149 : WebGLFramebuffer *fb;
3150 0 : *retval = GetConcreteObjectAndGLName("isFramebuffer", fbobj, &fb, &fbname, nsnull, &isDeleted) &&
3151 0 : !isDeleted &&
3152 0 : fb->HasEverBeenBound();
3153 0 : return NS_OK;
3154 : }
3155 :
3156 : NS_IMETHODIMP
3157 0 : WebGLContext::IsProgram(nsIWebGLProgram *pobj, WebGLboolean *retval)
3158 : {
3159 0 : if (!IsContextStable())
3160 : {
3161 0 : *retval = false;
3162 0 : return NS_OK;
3163 : }
3164 :
3165 : bool isDeleted;
3166 0 : WebGLProgram *prog = nsnull;
3167 0 : *retval = GetConcreteObject("isProgram", pobj, &prog, nsnull, &isDeleted, false) &&
3168 0 : !isDeleted;
3169 0 : return NS_OK;
3170 : }
3171 :
3172 : NS_IMETHODIMP
3173 0 : WebGLContext::IsRenderbuffer(nsIWebGLRenderbuffer *rbobj, WebGLboolean *retval)
3174 : {
3175 0 : if (!IsContextStable())
3176 : {
3177 0 : *retval = false;
3178 0 : return NS_OK;
3179 : }
3180 :
3181 : bool isDeleted;
3182 : WebGLuint rbname;
3183 : WebGLRenderbuffer *rb;
3184 0 : *retval = GetConcreteObjectAndGLName("isRenderBuffer", rbobj, &rb, &rbname, nsnull, &isDeleted) &&
3185 0 : !isDeleted &&
3186 0 : rb->HasEverBeenBound();
3187 0 : return NS_OK;
3188 : }
3189 :
3190 : NS_IMETHODIMP
3191 0 : WebGLContext::IsShader(nsIWebGLShader *sobj, WebGLboolean *retval)
3192 : {
3193 0 : if (!IsContextStable())
3194 : {
3195 0 : *retval = false;
3196 0 : return NS_OK;
3197 : }
3198 :
3199 : bool isDeleted;
3200 0 : WebGLShader *shader = nsnull;
3201 0 : *retval = GetConcreteObject("isShader", sobj, &shader, nsnull, &isDeleted, false) &&
3202 0 : !isDeleted;
3203 0 : return NS_OK;
3204 : }
3205 :
3206 : NS_IMETHODIMP
3207 0 : WebGLContext::IsTexture(nsIWebGLTexture *tobj, WebGLboolean *retval)
3208 : {
3209 0 : if (!IsContextStable())
3210 : {
3211 0 : *retval = false;
3212 0 : return NS_OK;
3213 : }
3214 :
3215 : bool isDeleted;
3216 : WebGLuint texname;
3217 : WebGLTexture *tex;
3218 0 : *retval = GetConcreteObjectAndGLName("isTexture", tobj, &tex, &texname, nsnull, &isDeleted) &&
3219 0 : !isDeleted &&
3220 0 : tex->HasEverBeenBound();
3221 0 : return NS_OK;
3222 : }
3223 :
3224 : NS_IMETHODIMP
3225 0 : WebGLContext::IsEnabled(WebGLenum cap, WebGLboolean *retval)
3226 : {
3227 0 : if (!IsContextStable())
3228 : {
3229 0 : *retval = false;
3230 0 : return NS_OK;
3231 : }
3232 :
3233 0 : *retval = 0;
3234 :
3235 0 : if (!ValidateCapabilityEnum(cap, "isEnabled"))
3236 0 : return NS_OK;
3237 :
3238 0 : MakeContextCurrent();
3239 0 : *retval = gl->fIsEnabled(cap);
3240 0 : return NS_OK;
3241 : }
3242 :
3243 0 : GL_SAME_METHOD_1(LineWidth, LineWidth, WebGLfloat)
3244 :
3245 : NS_IMETHODIMP
3246 0 : WebGLContext::LinkProgram(nsIWebGLProgram *pobj)
3247 : {
3248 0 : if (!IsContextStable())
3249 0 : return NS_OK;
3250 :
3251 : GLuint progname;
3252 : WebGLProgram *program;
3253 0 : if (!GetConcreteObjectAndGLName("linkProgram", pobj, &program, &progname))
3254 0 : return NS_OK;
3255 :
3256 0 : if (!program->NextGeneration())
3257 0 : return NS_ERROR_FAILURE;
3258 :
3259 0 : if (!program->HasBothShaderTypesAttached()) {
3260 0 : program->SetLinkStatus(false);
3261 0 : return NS_OK;
3262 : }
3263 :
3264 0 : MakeContextCurrent();
3265 0 : gl->fLinkProgram(progname);
3266 :
3267 : GLint ok;
3268 0 : gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok);
3269 0 : if (ok) {
3270 0 : bool updateInfoSucceeded = program->UpdateInfo();
3271 0 : program->SetLinkStatus(updateInfoSucceeded);
3272 : } else {
3273 0 : program->SetLinkStatus(false);
3274 : }
3275 0 : return NS_OK;
3276 : }
3277 :
3278 : NS_IMETHODIMP
3279 0 : WebGLContext::PixelStorei(WebGLenum pname, WebGLint param)
3280 : {
3281 0 : if (!IsContextStable())
3282 0 : return NS_OK;
3283 :
3284 0 : switch (pname) {
3285 : case UNPACK_FLIP_Y_WEBGL:
3286 0 : mPixelStoreFlipY = (param != 0);
3287 0 : break;
3288 : case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
3289 0 : mPixelStorePremultiplyAlpha = (param != 0);
3290 0 : break;
3291 : case UNPACK_COLORSPACE_CONVERSION_WEBGL:
3292 0 : if (param == LOCAL_GL_NONE || param == BROWSER_DEFAULT_WEBGL)
3293 0 : mPixelStoreColorspaceConversion = param;
3294 : else
3295 0 : return ErrorInvalidEnumInfo("pixelStorei: colorspace conversion parameter", param);
3296 0 : break;
3297 : case LOCAL_GL_PACK_ALIGNMENT:
3298 : case LOCAL_GL_UNPACK_ALIGNMENT:
3299 0 : if (param != 1 &&
3300 : param != 2 &&
3301 : param != 4 &&
3302 : param != 8)
3303 0 : return ErrorInvalidValue("PixelStorei: invalid pack/unpack alignment value");
3304 0 : if (pname == LOCAL_GL_PACK_ALIGNMENT)
3305 0 : mPixelStorePackAlignment = param;
3306 0 : else if (pname == LOCAL_GL_UNPACK_ALIGNMENT)
3307 0 : mPixelStoreUnpackAlignment = param;
3308 0 : MakeContextCurrent();
3309 0 : gl->fPixelStorei(pname, param);
3310 0 : break;
3311 : default:
3312 0 : return ErrorInvalidEnumInfo("PixelStorei: parameter", pname);
3313 : }
3314 :
3315 0 : return NS_OK;
3316 : }
3317 :
3318 :
3319 0 : GL_SAME_METHOD_2(PolygonOffset, PolygonOffset, WebGLfloat, WebGLfloat)
3320 :
3321 : NS_IMETHODIMP
3322 0 : WebGLContext::ReadPixels(PRInt32)
3323 : {
3324 0 : if (!IsContextStable())
3325 0 : return NS_OK;
3326 :
3327 0 : return NS_ERROR_FAILURE;
3328 : }
3329 :
3330 : nsresult
3331 0 : WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height,
3332 : WebGLenum format, WebGLenum type, JSObject* pixels)
3333 : {
3334 0 : if (HTMLCanvasElement()->IsWriteOnly() && !nsContentUtils::IsCallerTrustedForRead()) {
3335 0 : LogMessageIfVerbose("ReadPixels: Not allowed");
3336 0 : return NS_ERROR_DOM_SECURITY_ERR;
3337 : }
3338 :
3339 0 : if (width < 0 || height < 0)
3340 0 : return ErrorInvalidValue("ReadPixels: negative size passed");
3341 :
3342 0 : if (!pixels)
3343 0 : return ErrorInvalidValue("ReadPixels: null array passed");
3344 :
3345 0 : const WebGLRectangleObject *framebufferRect = FramebufferRectangleObject();
3346 0 : WebGLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
3347 0 : WebGLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
3348 :
3349 0 : void* data = JS_GetTypedArrayData(pixels);
3350 0 : PRUint32 dataByteLen = JS_GetTypedArrayByteLength(pixels);
3351 0 : int dataType = JS_GetTypedArrayType(pixels);
3352 :
3353 0 : PRUint32 channels = 0;
3354 :
3355 : // Check the format param
3356 0 : switch (format) {
3357 : case LOCAL_GL_ALPHA:
3358 0 : channels = 1;
3359 0 : break;
3360 : case LOCAL_GL_RGB:
3361 0 : channels = 3;
3362 0 : break;
3363 : case LOCAL_GL_RGBA:
3364 0 : channels = 4;
3365 0 : break;
3366 : default:
3367 0 : return ErrorInvalidEnum("readPixels: Bad format");
3368 : }
3369 :
3370 0 : PRUint32 bytesPerPixel = 0;
3371 0 : int requiredDataType = 0;
3372 :
3373 : // Check the type param
3374 0 : switch (type) {
3375 : case LOCAL_GL_UNSIGNED_BYTE:
3376 0 : bytesPerPixel = 1 * channels;
3377 0 : requiredDataType = js::TypedArray::TYPE_UINT8;
3378 0 : break;
3379 : case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
3380 : case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
3381 : case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
3382 0 : bytesPerPixel = 2;
3383 0 : requiredDataType = js::TypedArray::TYPE_UINT16;
3384 0 : break;
3385 : default:
3386 0 : return ErrorInvalidEnum("readPixels: Bad type");
3387 : }
3388 :
3389 : // Check the pixels param type
3390 0 : if (dataType != requiredDataType)
3391 0 : return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
3392 :
3393 : // Check the pixels param size
3394 : CheckedUint32 checked_neededByteLength =
3395 0 : GetImageSize(height, width, bytesPerPixel, mPixelStorePackAlignment);
3396 :
3397 0 : CheckedUint32 checked_plainRowSize = CheckedUint32(width) * bytesPerPixel;
3398 :
3399 : CheckedUint32 checked_alignedRowSize =
3400 0 : RoundedToNextMultipleOf(checked_plainRowSize, mPixelStorePackAlignment);
3401 :
3402 0 : if (!checked_neededByteLength.valid())
3403 0 : return ErrorInvalidOperation("ReadPixels: integer overflow computing the needed buffer size");
3404 :
3405 0 : if (checked_neededByteLength.value() > dataByteLen)
3406 0 : return ErrorInvalidOperation("ReadPixels: buffer too small");
3407 :
3408 : // Check the format and type params to assure they are an acceptable pair (as per spec)
3409 0 : switch (format) {
3410 : case LOCAL_GL_RGBA: {
3411 0 : switch (type) {
3412 : case LOCAL_GL_UNSIGNED_BYTE:
3413 : break;
3414 : default:
3415 0 : return ErrorInvalidOperation("readPixels: Invalid format/type pair");
3416 : }
3417 : break;
3418 : }
3419 : default:
3420 0 : return ErrorInvalidOperation("readPixels: Invalid format/type pair");
3421 : }
3422 :
3423 0 : MakeContextCurrent();
3424 :
3425 0 : if (mBoundFramebuffer) {
3426 : // prevent readback of arbitrary video memory through uninitialized renderbuffers!
3427 0 : if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
3428 0 : return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
3429 : } else {
3430 0 : EnsureBackbufferClearedAsNeeded();
3431 : }
3432 : // Now that the errors are out of the way, on to actually reading
3433 :
3434 : // If we won't be reading any pixels anyways, just skip the actual reading
3435 0 : if (width == 0 || height == 0)
3436 0 : return DummyFramebufferOperation("readPixels");
3437 :
3438 0 : if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
3439 : // the easy case: we're not reading out-of-range pixels
3440 0 : gl->fReadPixels(x, y, width, height, format, type, data);
3441 : } else {
3442 : // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
3443 : // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
3444 : // to do that for us, because passing out of range parameters to a buggy OpenGL implementation
3445 : // could conceivably allow to read memory we shouldn't be allowed to read. So we manually initialize
3446 : // the buffer to zero and compute the parameters to pass to OpenGL. We have to use an intermediate buffer
3447 : // to accomodate the potentially different strides (widths).
3448 :
3449 : // zero the whole destination buffer. Too bad for the part that's going to be overwritten, we're not
3450 : // 100% efficient here, but in practice this is a quite rare case anyway.
3451 0 : memset(data, 0, dataByteLen);
3452 :
3453 0 : if ( x >= framebufferWidth
3454 : || x+width <= 0
3455 : || y >= framebufferHeight
3456 : || y+height <= 0)
3457 : {
3458 : // we are completely outside of range, can exit now with buffer filled with zeros
3459 0 : return DummyFramebufferOperation("readPixels");
3460 : }
3461 :
3462 : // compute the parameters of the subrect we're actually going to call glReadPixels on
3463 0 : GLint subrect_x = NS_MAX(x, 0);
3464 0 : GLint subrect_end_x = NS_MIN(x+width, framebufferWidth);
3465 0 : GLsizei subrect_width = subrect_end_x - subrect_x;
3466 :
3467 0 : GLint subrect_y = NS_MAX(y, 0);
3468 0 : GLint subrect_end_y = NS_MIN(y+height, framebufferHeight);
3469 0 : GLsizei subrect_height = subrect_end_y - subrect_y;
3470 :
3471 0 : if (subrect_width < 0 || subrect_height < 0 ||
3472 : subrect_width > width || subrect_height > height)
3473 0 : return ErrorInvalidOperation("ReadPixels: integer overflow computing clipped rect size");
3474 :
3475 : // now we know that subrect_width is in the [0..width] interval, and same for heights.
3476 :
3477 : // now, same computation as above to find the size of the intermediate buffer to allocate for the subrect
3478 : // no need to check again for integer overflow here, since we already know the sizes aren't greater than before
3479 0 : PRUint32 subrect_plainRowSize = subrect_width * bytesPerPixel;
3480 : // There are checks above to ensure that this doesn't overflow.
3481 : PRUint32 subrect_alignedRowSize =
3482 0 : RoundedToNextMultipleOf(subrect_plainRowSize, mPixelStorePackAlignment).value();
3483 0 : PRUint32 subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize;
3484 :
3485 : // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
3486 0 : GLubyte *subrect_data = new GLubyte[subrect_byteLength];
3487 0 : gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height, format, type, subrect_data);
3488 :
3489 : // notice that this for loop terminates because we already checked that subrect_height is at most height
3490 0 : for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
3491 0 : GLint subrect_x_in_dest_buffer = subrect_x - x;
3492 0 : GLint subrect_y_in_dest_buffer = subrect_y - y;
3493 : memcpy(static_cast<GLubyte*>(data)
3494 0 : + checked_alignedRowSize.value() * (subrect_y_in_dest_buffer + y_inside_subrect)
3495 0 : + bytesPerPixel * subrect_x_in_dest_buffer, // destination
3496 : subrect_data + subrect_alignedRowSize * y_inside_subrect, // source
3497 0 : subrect_plainRowSize); // size
3498 : }
3499 0 : delete [] subrect_data;
3500 : }
3501 :
3502 : // if we're reading alpha, we may need to do fixup. Note that we don't allow
3503 : // GL_ALPHA to readpixels currently, but we had the code written for it already.
3504 0 : if (format == LOCAL_GL_ALPHA ||
3505 : format == LOCAL_GL_RGBA)
3506 : {
3507 : bool needAlphaFixup;
3508 0 : if (mBoundFramebuffer) {
3509 0 : needAlphaFixup = !mBoundFramebuffer->ColorAttachment().HasAlpha();
3510 : } else {
3511 0 : needAlphaFixup = gl->ActualFormat().alpha == 0;
3512 : }
3513 :
3514 0 : if (needAlphaFixup) {
3515 0 : if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) {
3516 : // this is easy; it's an 0xff memset per row
3517 0 : PRUint8 *row = (PRUint8*)data;
3518 0 : for (GLint j = 0; j < height; ++j) {
3519 0 : memset(row, 0xff, checked_plainRowSize.value());
3520 0 : row += checked_alignedRowSize.value();
3521 0 : }
3522 0 : } else if (format == LOCAL_GL_RGBA && type == LOCAL_GL_UNSIGNED_BYTE) {
3523 : // this is harder, we need to just set the alpha byte here
3524 0 : PRUint8 *row = (PRUint8*)data;
3525 0 : for (GLint j = 0; j < height; ++j) {
3526 0 : PRUint8 *rowp = row;
3527 : #ifdef IS_LITTLE_ENDIAN
3528 : // offset to get the alpha byte; we're always going to
3529 : // move by 4 bytes
3530 0 : rowp += 3;
3531 : #endif
3532 0 : PRUint8 *endrowp = rowp + 4 * width;
3533 0 : while (rowp != endrowp) {
3534 0 : *rowp = 0xff;
3535 0 : rowp += 4;
3536 : }
3537 :
3538 0 : row += checked_alignedRowSize.value();
3539 0 : }
3540 : } else {
3541 0 : NS_WARNING("Unhandled case, how'd we get here?");
3542 0 : return NS_ERROR_FAILURE;
3543 : }
3544 : }
3545 : }
3546 :
3547 0 : return NS_OK;
3548 : }
3549 :
3550 : NS_IMETHODIMP
3551 0 : WebGLContext::ReadPixels_array(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height,
3552 : WebGLenum format, WebGLenum type, JSObject *pixels)
3553 : {
3554 0 : if (!IsContextStable())
3555 0 : return NS_OK;
3556 :
3557 0 : return ReadPixels_base(x, y, width, height, format, type, pixels);
3558 : }
3559 :
3560 : NS_IMETHODIMP
3561 0 : WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, WebGLsizei width, WebGLsizei height)
3562 : {
3563 0 : if (!IsContextStable())
3564 0 : return NS_OK;
3565 :
3566 0 : if (!mBoundRenderbuffer || !mBoundRenderbuffer->GLName())
3567 0 : return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
3568 :
3569 0 : if (target != LOCAL_GL_RENDERBUFFER)
3570 0 : return ErrorInvalidEnumInfo("renderbufferStorage: target", target);
3571 :
3572 0 : if (width < 0 || height < 0)
3573 0 : return ErrorInvalidValue("renderbufferStorage: width and height must be >= 0");
3574 :
3575 0 : if (!mBoundRenderbuffer || !mBoundRenderbuffer->GLName())
3576 0 : return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
3577 :
3578 : // certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
3579 0 : WebGLenum internalformatForGL = internalformat;
3580 :
3581 0 : switch (internalformat) {
3582 : case LOCAL_GL_RGBA4:
3583 : case LOCAL_GL_RGB5_A1:
3584 : // 16-bit RGBA formats are not supported on desktop GL
3585 0 : if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGBA8;
3586 0 : break;
3587 : case LOCAL_GL_RGB565:
3588 : // the RGB565 format is not supported on desktop GL
3589 0 : if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGB8;
3590 0 : break;
3591 : case LOCAL_GL_DEPTH_COMPONENT16:
3592 0 : if (!gl->IsGLES2() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
3593 0 : internalformatForGL = LOCAL_GL_DEPTH_COMPONENT24;
3594 0 : else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil))
3595 0 : internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
3596 0 : break;
3597 : case LOCAL_GL_STENCIL_INDEX8:
3598 0 : break;
3599 : case LOCAL_GL_DEPTH_STENCIL:
3600 : // this one is available in newer OpenGL (at least since 3.1); will probably become available
3601 : // in OpenGL ES 3 (at least it will have some DEPTH_STENCIL) and is the same value that
3602 : // is otherwise provided by EXT_packed_depth_stencil and OES_packed_depth_stencil extensions
3603 : // which means it's supported on most GL and GL ES systems already.
3604 : //
3605 : // So we just use it hoping that it's available (perhaps as an extension) and if it's not available,
3606 : // we just let the GL generate an error and don't do anything about it ourselves.
3607 0 : internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
3608 0 : break;
3609 : default:
3610 0 : return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
3611 : }
3612 :
3613 0 : MakeContextCurrent();
3614 :
3615 0 : bool sizeChanges = width != mBoundRenderbuffer->Width() ||
3616 0 : height != mBoundRenderbuffer->Height() ||
3617 0 : internalformat != mBoundRenderbuffer->InternalFormat();
3618 0 : if (sizeChanges) {
3619 0 : UpdateWebGLErrorAndClearGLError();
3620 0 : gl->fRenderbufferStorage(target, internalformatForGL, width, height);
3621 0 : GLenum error = LOCAL_GL_NO_ERROR;
3622 0 : UpdateWebGLErrorAndClearGLError(&error);
3623 0 : if (error) {
3624 0 : LogMessageIfVerbose("renderbufferStorage generated error %s", ErrorName(error));
3625 0 : return NS_OK;
3626 : }
3627 : } else {
3628 0 : gl->fRenderbufferStorage(target, internalformatForGL, width, height);
3629 : }
3630 :
3631 0 : mBoundRenderbuffer->SetInternalFormat(internalformat);
3632 0 : mBoundRenderbuffer->SetInternalFormatForGL(internalformatForGL);
3633 0 : mBoundRenderbuffer->setDimensions(width, height);
3634 0 : mBoundRenderbuffer->SetInitialized(false);
3635 :
3636 0 : return NS_OK;
3637 : }
3638 :
3639 0 : GL_SAME_METHOD_2(SampleCoverage, SampleCoverage, WebGLfloat, WebGLboolean)
3640 :
3641 : NS_IMETHODIMP
3642 0 : WebGLContext::Scissor(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height)
3643 : {
3644 0 : if (!IsContextStable())
3645 0 : return NS_OK;
3646 :
3647 0 : if (width < 0 || height < 0)
3648 0 : return ErrorInvalidValue("Scissor: negative size");
3649 :
3650 0 : MakeContextCurrent();
3651 0 : gl->fScissor(x, y, width, height);
3652 0 : return NS_OK;
3653 : }
3654 :
3655 : NS_IMETHODIMP
3656 0 : WebGLContext::StencilFunc(WebGLenum func, WebGLint ref, WebGLuint mask)
3657 : {
3658 0 : if (!IsContextStable())
3659 0 : return NS_OK;
3660 :
3661 0 : if (!ValidateComparisonEnum(func, "stencilFunc: func"))
3662 0 : return NS_OK;
3663 :
3664 0 : mStencilRefFront = ref;
3665 0 : mStencilRefBack = ref;
3666 0 : mStencilValueMaskFront = mask;
3667 0 : mStencilValueMaskBack = mask;
3668 :
3669 0 : MakeContextCurrent();
3670 0 : gl->fStencilFunc(func, ref, mask);
3671 0 : return NS_OK;
3672 : }
3673 :
3674 : NS_IMETHODIMP
3675 0 : WebGLContext::StencilFuncSeparate(WebGLenum face, WebGLenum func, WebGLint ref, WebGLuint mask)
3676 : {
3677 0 : if (!IsContextStable())
3678 0 : return NS_OK;
3679 :
3680 0 : if (!ValidateFaceEnum(face, "stencilFuncSeparate: face") ||
3681 0 : !ValidateComparisonEnum(func, "stencilFuncSeparate: func"))
3682 0 : return NS_OK;
3683 :
3684 0 : switch (face) {
3685 : case LOCAL_GL_FRONT_AND_BACK:
3686 0 : mStencilRefFront = ref;
3687 0 : mStencilRefBack = ref;
3688 0 : mStencilValueMaskFront = mask;
3689 0 : mStencilValueMaskBack = mask;
3690 0 : break;
3691 : case LOCAL_GL_FRONT:
3692 0 : mStencilRefFront = ref;
3693 0 : mStencilValueMaskFront = mask;
3694 0 : break;
3695 : case LOCAL_GL_BACK:
3696 0 : mStencilRefBack = ref;
3697 0 : mStencilValueMaskBack = mask;
3698 0 : break;
3699 : }
3700 :
3701 0 : MakeContextCurrent();
3702 0 : gl->fStencilFuncSeparate(face, func, ref, mask);
3703 0 : return NS_OK;
3704 : }
3705 :
3706 : NS_IMETHODIMP
3707 0 : WebGLContext::StencilMask(WebGLuint mask)
3708 : {
3709 0 : if (!IsContextStable())
3710 0 : return NS_OK;
3711 :
3712 0 : mStencilWriteMaskFront = mask;
3713 0 : mStencilWriteMaskBack = mask;
3714 :
3715 0 : MakeContextCurrent();
3716 0 : gl->fStencilMask(mask);
3717 0 : return NS_OK;
3718 : }
3719 :
3720 : NS_IMETHODIMP
3721 0 : WebGLContext::StencilMaskSeparate(WebGLenum face, WebGLuint mask)
3722 : {
3723 0 : if (!IsContextStable())
3724 0 : return NS_OK;
3725 :
3726 0 : if (!ValidateFaceEnum(face, "stencilMaskSeparate: face"))
3727 0 : return NS_OK;
3728 :
3729 0 : switch (face) {
3730 : case LOCAL_GL_FRONT_AND_BACK:
3731 0 : mStencilWriteMaskFront = mask;
3732 0 : mStencilWriteMaskBack = mask;
3733 0 : break;
3734 : case LOCAL_GL_FRONT:
3735 0 : mStencilWriteMaskFront = mask;
3736 0 : break;
3737 : case LOCAL_GL_BACK:
3738 0 : mStencilWriteMaskBack = mask;
3739 0 : break;
3740 : }
3741 :
3742 0 : MakeContextCurrent();
3743 0 : gl->fStencilMaskSeparate(face, mask);
3744 0 : return NS_OK;
3745 : }
3746 :
3747 : NS_IMETHODIMP
3748 0 : WebGLContext::StencilOp(WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass)
3749 : {
3750 0 : if (!IsContextStable())
3751 0 : return NS_OK;
3752 :
3753 0 : if (!ValidateStencilOpEnum(sfail, "stencilOp: sfail") ||
3754 0 : !ValidateStencilOpEnum(dpfail, "stencilOp: dpfail") ||
3755 0 : !ValidateStencilOpEnum(dppass, "stencilOp: dppass"))
3756 0 : return NS_OK;
3757 :
3758 0 : MakeContextCurrent();
3759 0 : gl->fStencilOp(sfail, dpfail, dppass);
3760 0 : return NS_OK;
3761 : }
3762 :
3763 : NS_IMETHODIMP
3764 0 : WebGLContext::StencilOpSeparate(WebGLenum face, WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass)
3765 : {
3766 0 : if (!IsContextStable())
3767 0 : return NS_OK;
3768 :
3769 0 : if (!ValidateFaceEnum(face, "stencilOpSeparate: face") ||
3770 0 : !ValidateStencilOpEnum(sfail, "stencilOpSeparate: sfail") ||
3771 0 : !ValidateStencilOpEnum(dpfail, "stencilOpSeparate: dpfail") ||
3772 0 : !ValidateStencilOpEnum(dppass, "stencilOpSeparate: dppass"))
3773 0 : return NS_OK;
3774 :
3775 0 : MakeContextCurrent();
3776 0 : gl->fStencilOpSeparate(face, sfail, dpfail, dppass);
3777 0 : return NS_OK;
3778 : }
3779 :
3780 : struct WebGLImageConverter
3781 : {
3782 : bool flip;
3783 : size_t width, height, srcStride, dstStride, srcTexelSize, dstTexelSize;
3784 : const PRUint8 *src;
3785 : PRUint8 *dst;
3786 :
3787 0 : WebGLImageConverter()
3788 : {
3789 0 : memset(this, 0, sizeof(WebGLImageConverter));
3790 0 : }
3791 :
3792 : template<typename SrcType, typename DstType, typename UnpackType,
3793 : void unpackingFunc(const SrcType*, UnpackType*),
3794 : void packingFunc(const UnpackType*, DstType*)>
3795 0 : void run()
3796 : {
3797 : // Note -- even though the functions take UnpackType, the
3798 : // pointers below are all in terms of PRUint8; otherwise
3799 : // pointer math starts getting tricky.
3800 0 : for (size_t src_row = 0; src_row < height; ++src_row) {
3801 0 : size_t dst_row = flip ? (height - 1 - src_row) : src_row;
3802 0 : PRUint8 *dst_row_ptr = dst + dst_row * dstStride;
3803 0 : const PRUint8 *src_row_ptr = src + src_row * srcStride;
3804 0 : const PRUint8 *src_row_end = src_row_ptr + width * srcTexelSize; // != src_row_ptr + byteStride
3805 0 : while (src_row_ptr != src_row_end) {
3806 : UnpackType tmp[4];
3807 0 : unpackingFunc(reinterpret_cast<const SrcType*>(src_row_ptr), tmp);
3808 0 : packingFunc(tmp, reinterpret_cast<DstType*>(dst_row_ptr));
3809 0 : src_row_ptr += srcTexelSize;
3810 0 : dst_row_ptr += dstTexelSize;
3811 : }
3812 : }
3813 0 : }
3814 : };
3815 :
3816 : void
3817 0 : WebGLContext::ConvertImage(size_t width, size_t height, size_t srcStride, size_t dstStride,
3818 : const PRUint8*src, PRUint8 *dst,
3819 : int srcFormat, bool srcPremultiplied,
3820 : int dstFormat, bool dstPremultiplied,
3821 : size_t dstTexelSize)
3822 : {
3823 0 : if (width <= 0 || height <= 0)
3824 0 : return;
3825 :
3826 0 : if (srcFormat == dstFormat &&
3827 : srcPremultiplied == dstPremultiplied)
3828 : {
3829 : // fast exit path: we just have to memcpy all the rows.
3830 : //
3831 : // The case where absolutely nothing needs to be done is supposed to have
3832 : // been handled earlier (in TexImage2D_base, etc).
3833 : //
3834 : // So the case we're handling here is when even though no format conversion is needed,
3835 : // we still might have to flip vertically and/or to adjust to a different stride.
3836 :
3837 0 : NS_ASSERTION(mPixelStoreFlipY || srcStride != dstStride, "Performance trap -- should handle this case earlier, to avoid memcpy");
3838 :
3839 0 : size_t row_size = width * dstTexelSize; // doesn't matter, src and dst formats agree
3840 0 : const PRUint8* src_row = src;
3841 0 : const PRUint8* src_end = src + height * srcStride;
3842 :
3843 0 : PRUint8* dst_row = mPixelStoreFlipY ? dst + (height-1) * dstStride : dst;
3844 0 : ptrdiff_t dstStrideSigned(dstStride);
3845 0 : ptrdiff_t dst_delta = mPixelStoreFlipY ? -dstStrideSigned : dstStrideSigned;
3846 :
3847 0 : while(src_row != src_end) {
3848 0 : memcpy(dst_row, src_row, row_size);
3849 0 : src_row += srcStride;
3850 0 : dst_row += dst_delta;
3851 : }
3852 0 : return;
3853 : }
3854 :
3855 0 : WebGLImageConverter converter;
3856 0 : converter.flip = mPixelStoreFlipY;
3857 0 : converter.width = width;
3858 0 : converter.height = height;
3859 0 : converter.srcStride = srcStride;
3860 0 : converter.dstStride = dstStride;
3861 0 : converter.dstTexelSize = dstTexelSize;
3862 0 : converter.src = src;
3863 0 : converter.dst = dst;
3864 :
3865 : int premultiplicationOp = (!srcPremultiplied && dstPremultiplied) ? WebGLTexelPremultiplicationOp::Premultiply
3866 0 : : (srcPremultiplied && !dstPremultiplied) ? WebGLTexelPremultiplicationOp::Unmultiply
3867 0 : : WebGLTexelPremultiplicationOp::None;
3868 :
3869 : #define HANDLE_DSTFORMAT(format, SrcType, DstType, unpackFunc, packFunc) \
3870 : case WebGLTexelFormat::format: \
3871 : switch (premultiplicationOp) { \
3872 : case WebGLTexelPremultiplicationOp::Premultiply: \
3873 : converter.run<SrcType, DstType, PRUint8, \
3874 : WebGLTexelConversions::unpackFunc, \
3875 : WebGLTexelConversions::packFunc##Premultiply>(); \
3876 : break; \
3877 : case WebGLTexelPremultiplicationOp::Unmultiply: \
3878 : converter.run<SrcType, DstType, PRUint8, \
3879 : WebGLTexelConversions::unpackFunc, \
3880 : WebGLTexelConversions::packFunc##Unmultiply>(); \
3881 : break; \
3882 : default: \
3883 : converter.run<SrcType, DstType, PRUint8, \
3884 : WebGLTexelConversions::unpackFunc, \
3885 : WebGLTexelConversions::packFunc>(); \
3886 : break; \
3887 : } \
3888 : break;
3889 :
3890 : #define HANDLE_SRCFORMAT(format, size, SrcType, unpackFunc) \
3891 : case WebGLTexelFormat::format: \
3892 : converter.srcTexelSize = size; \
3893 : switch (dstFormat) { \
3894 : HANDLE_DSTFORMAT(RGBA8, SrcType, PRUint8, unpackFunc, packRGBA8ToRGBA8) \
3895 : HANDLE_DSTFORMAT(RGB8, SrcType, PRUint8, unpackFunc, packRGBA8ToRGB8) \
3896 : HANDLE_DSTFORMAT(R8, SrcType, PRUint8, unpackFunc, packRGBA8ToR8) \
3897 : HANDLE_DSTFORMAT(RA8, SrcType, PRUint8, unpackFunc, packRGBA8ToRA8) \
3898 : HANDLE_DSTFORMAT(RGBA5551, SrcType, PRUint16, unpackFunc, packRGBA8ToUnsignedShort5551) \
3899 : HANDLE_DSTFORMAT(RGBA4444, SrcType, PRUint16, unpackFunc, packRGBA8ToUnsignedShort4444) \
3900 : HANDLE_DSTFORMAT(RGB565, SrcType, PRUint16, unpackFunc, packRGBA8ToUnsignedShort565) \
3901 : /* A8 needs to be special-cased as it doesn't have color channels to premultiply */ \
3902 : case WebGLTexelFormat::A8: \
3903 : converter.run<SrcType, PRUint8, PRUint8, \
3904 : WebGLTexelConversions::unpackFunc, \
3905 : WebGLTexelConversions::packRGBA8ToA8>(); \
3906 : break; \
3907 : default: \
3908 : NS_ASSERTION(false, "Coding error?! Should never reach this point."); \
3909 : return; \
3910 : } \
3911 : break;
3912 :
3913 : #define HANDLE_FLOAT_DSTFORMAT(format, unpackFunc, packFunc) \
3914 : case WebGLTexelFormat::format: \
3915 : switch (premultiplicationOp) { \
3916 : case WebGLTexelPremultiplicationOp::Premultiply: \
3917 : converter.run<float, float, float, \
3918 : WebGLTexelConversions::unpackFunc, \
3919 : WebGLTexelConversions::packFunc##Premultiply>(); \
3920 : break; \
3921 : case WebGLTexelPremultiplicationOp::Unmultiply: \
3922 : NS_ASSERTION(false, "Floating point can't be un-premultiplied -- we have no premultiplied source data!"); \
3923 : break; \
3924 : default: \
3925 : converter.run<float, float, float, \
3926 : WebGLTexelConversions::unpackFunc, \
3927 : WebGLTexelConversions::packFunc>(); \
3928 : break; \
3929 : } \
3930 : break;
3931 :
3932 : #define HANDLE_FLOAT_SRCFORMAT(format, size, unpackFunc) \
3933 : case WebGLTexelFormat::format: \
3934 : converter.srcTexelSize = size; \
3935 : switch (dstFormat) { \
3936 : HANDLE_FLOAT_DSTFORMAT(RGB32F, unpackFunc, packRGBA32FToRGB32F) \
3937 : HANDLE_FLOAT_DSTFORMAT(A32F, unpackFunc, packRGBA32FToA32F) \
3938 : HANDLE_FLOAT_DSTFORMAT(R32F, unpackFunc, packRGBA32FToR32F) \
3939 : HANDLE_FLOAT_DSTFORMAT(RA32F, unpackFunc, packRGBA32FToRA32F) \
3940 : default: \
3941 : NS_ASSERTION(false, "Coding error?! Should never reach this point."); \
3942 : return; \
3943 : } \
3944 : break;
3945 :
3946 0 : switch (srcFormat) {
3947 0 : HANDLE_SRCFORMAT(RGBA8, 4, PRUint8, unpackRGBA8ToRGBA8)
3948 0 : HANDLE_SRCFORMAT(RGBX8, 4, PRUint8, unpackRGB8ToRGBA8)
3949 0 : HANDLE_SRCFORMAT(RGB8, 3, PRUint8, unpackRGB8ToRGBA8)
3950 0 : HANDLE_SRCFORMAT(BGRA8, 4, PRUint8, unpackBGRA8ToRGBA8)
3951 0 : HANDLE_SRCFORMAT(BGRX8, 4, PRUint8, unpackBGR8ToRGBA8)
3952 0 : HANDLE_SRCFORMAT(BGR8, 3, PRUint8, unpackBGR8ToRGBA8)
3953 0 : HANDLE_SRCFORMAT(R8, 1, PRUint8, unpackR8ToRGBA8)
3954 0 : HANDLE_SRCFORMAT(A8, 1, PRUint8, unpackA8ToRGBA8)
3955 0 : HANDLE_SRCFORMAT(RA8, 2, PRUint8, unpackRA8ToRGBA8)
3956 0 : HANDLE_SRCFORMAT(RGBA5551, 2, PRUint16, unpackRGBA5551ToRGBA8)
3957 0 : HANDLE_SRCFORMAT(RGBA4444, 2, PRUint16, unpackRGBA4444ToRGBA8)
3958 0 : HANDLE_SRCFORMAT(RGB565, 2, PRUint16, unpackRGB565ToRGBA8)
3959 0 : HANDLE_FLOAT_SRCFORMAT(RGB32F, 12, unpackRGB32FToRGBA32F)
3960 0 : HANDLE_FLOAT_SRCFORMAT(RA32F, 8, unpackRA32FToRGBA32F)
3961 0 : HANDLE_FLOAT_SRCFORMAT(R32F, 4, unpackR32FToRGBA32F)
3962 0 : HANDLE_FLOAT_SRCFORMAT(A32F, 4, unpackA32FToRGBA32F)
3963 : default:
3964 0 : NS_ASSERTION(false, "Coding error?! Should never reach this point.");
3965 0 : return;
3966 : }
3967 : }
3968 :
3969 : nsresult
3970 0 : WebGLContext::DOMElementToImageSurface(Element* imageOrCanvas,
3971 : gfxImageSurface **imageOut, int *format)
3972 : {
3973 0 : if (!imageOrCanvas) {
3974 0 : return NS_ERROR_FAILURE;
3975 : }
3976 :
3977 : PRUint32 flags =
3978 : nsLayoutUtils::SFE_WANT_NEW_SURFACE |
3979 0 : nsLayoutUtils::SFE_WANT_IMAGE_SURFACE;
3980 :
3981 0 : if (mPixelStoreColorspaceConversion == LOCAL_GL_NONE)
3982 0 : flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
3983 0 : if (!mPixelStorePremultiplyAlpha)
3984 0 : flags |= nsLayoutUtils::SFE_NO_PREMULTIPLY_ALPHA;
3985 :
3986 : nsLayoutUtils::SurfaceFromElementResult res =
3987 0 : nsLayoutUtils::SurfaceFromElement(imageOrCanvas, flags);
3988 0 : if (!res.mSurface)
3989 0 : return NS_ERROR_FAILURE;
3990 0 : if (res.mSurface->GetType() != gfxASurface::SurfaceTypeImage) {
3991 : // SurfaceFromElement lied!
3992 0 : return NS_ERROR_FAILURE;
3993 : }
3994 :
3995 : // We disallow loading cross-domain images and videos that have not been validated
3996 : // with CORS as WebGL textures. The reason for doing that is that timing
3997 : // attacks on WebGL shaders are able to retrieve approximations of the
3998 : // pixel values in WebGL textures; see bug 655987.
3999 : //
4000 : // To prevent a loophole where a Canvas2D would be used as a proxy to load
4001 : // cross-domain textures, we also disallow loading textures from write-only
4002 : // Canvas2D's.
4003 :
4004 : // part 1: check that the DOM element is same-origin, or has otherwise been
4005 : // validated for cross-domain use.
4006 0 : if (!res.mCORSUsed) {
4007 : bool subsumes;
4008 0 : nsresult rv = HTMLCanvasElement()->NodePrincipal()->Subsumes(res.mPrincipal, &subsumes);
4009 0 : if (NS_FAILED(rv) || !subsumes) {
4010 : LogMessageIfVerbose("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
4011 0 : "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
4012 0 : return NS_ERROR_DOM_SECURITY_ERR;
4013 : }
4014 : }
4015 :
4016 : // part 2: if the DOM element is a canvas, check that it's not write-only.
4017 : // That would indicate a tainted canvas, i.e. a canvas that could contain
4018 : // cross-domain image data.
4019 0 : if (nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(imageOrCanvas)) {
4020 0 : if (canvas->IsWriteOnly()) {
4021 : LogMessageIfVerbose("The canvas used as source for texImage2D here is tainted (write-only). It is forbidden "
4022 : "to load a WebGL texture from a tainted canvas. A Canvas becomes tainted for example "
4023 : "when a cross-domain image is drawn on it. "
4024 0 : "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
4025 0 : return NS_ERROR_DOM_SECURITY_ERR;
4026 : }
4027 : }
4028 :
4029 : // End of security checks, now we should be safe regarding cross-domain images
4030 : // Notice that there is never a need to mark the WebGL canvas as write-only, since we reject write-only/cross-domain
4031 : // texture sources in the first place.
4032 :
4033 0 : gfxImageSurface* surf = static_cast<gfxImageSurface*>(res.mSurface.get());
4034 :
4035 0 : res.mSurface.forget();
4036 0 : *imageOut = surf;
4037 :
4038 0 : switch (surf->Format()) {
4039 : case gfxASurface::ImageFormatARGB32:
4040 0 : *format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA
4041 0 : break;
4042 : case gfxASurface::ImageFormatRGB24:
4043 0 : *format = WebGLTexelFormat::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8.
4044 0 : break;
4045 : case gfxASurface::ImageFormatA8:
4046 0 : *format = WebGLTexelFormat::A8;
4047 0 : break;
4048 : case gfxASurface::ImageFormatRGB16_565:
4049 0 : *format = WebGLTexelFormat::RGB565;
4050 0 : break;
4051 : default:
4052 0 : NS_ASSERTION(false, "Unsupported image format. Unimplemented.");
4053 0 : return NS_ERROR_NOT_IMPLEMENTED;
4054 : }
4055 :
4056 0 : return NS_OK;
4057 : }
4058 :
4059 : #define OBTAIN_UNIFORM_LOCATION(info) \
4060 : WebGLUniformLocation *location_object; \
4061 : bool isNull; \
4062 : if (!GetConcreteObject(info, ploc, &location_object, &isNull)) \
4063 : return NS_OK; \
4064 : if (isNull) \
4065 : return NS_OK; \
4066 : /* the need to check specifically for !mCurrentProgram here is explained in bug 657556 */ \
4067 : if (!mCurrentProgram) \
4068 : return ErrorInvalidOperation("%s: no program is currently bound", info); \
4069 : if (mCurrentProgram != location_object->Program()) \
4070 : return ErrorInvalidOperation("%s: this uniform location doesn't correspond to the current program", info); \
4071 : if (mCurrentProgram->Generation() != location_object->ProgramGeneration()) \
4072 : return ErrorInvalidOperation("%s: This uniform location is obsolete since the program has been relinked", info); \
4073 : GLint location = location_object->Location();
4074 :
4075 : #define SIMPLE_ARRAY_METHOD_UNIFORM(name, cnt, arrayType, ptrType) \
4076 : NS_IMETHODIMP \
4077 : WebGLContext::name(PRInt32) { \
4078 : return NS_ERROR_NOT_IMPLEMENTED; \
4079 : } \
4080 : NS_IMETHODIMP \
4081 : WebGLContext::name##_array(nsIWebGLUniformLocation *ploc, JSObject *wa) \
4082 : { \
4083 : if (!IsContextStable()) \
4084 : return NS_OK; \
4085 : OBTAIN_UNIFORM_LOCATION(#name ": location") \
4086 : if (!wa || JS_GetTypedArrayType(wa) != js::TypedArray::arrayType) \
4087 : return ErrorInvalidOperation(#name ": array must be " #arrayType); \
4088 : if (JS_GetTypedArrayLength(wa) == 0 || JS_GetTypedArrayLength(wa) % cnt != 0)\
4089 : return ErrorInvalidValue(#name ": array must be > 0 elements and have a length multiple of %d", cnt); \
4090 : MakeContextCurrent(); \
4091 : gl->f##name(location, JS_GetTypedArrayLength(wa) / cnt, (ptrType *)JS_GetTypedArrayData(wa)); \
4092 : return NS_OK; \
4093 : }
4094 :
4095 : #define SIMPLE_MATRIX_METHOD_UNIFORM(name, dim, arrayType, ptrType) \
4096 : NS_IMETHODIMP \
4097 : WebGLContext::name(PRInt32) { \
4098 : return NS_ERROR_NOT_IMPLEMENTED; \
4099 : } \
4100 : NS_IMETHODIMP \
4101 : WebGLContext::name##_array(nsIWebGLUniformLocation *ploc, WebGLboolean transpose, JSObject *wa) \
4102 : { \
4103 : if (!IsContextStable()) \
4104 : return NS_OK; \
4105 : OBTAIN_UNIFORM_LOCATION(#name ": location") \
4106 : if (!wa || JS_GetTypedArrayType(wa) != js::TypedArray::arrayType) \
4107 : return ErrorInvalidValue(#name ": array must be " #arrayType); \
4108 : if (JS_GetTypedArrayLength(wa) == 0 || JS_GetTypedArrayLength(wa) % (dim*dim) != 0) \
4109 : return ErrorInvalidValue(#name ": array length must be >0 and multiple of %d", dim*dim); \
4110 : if (transpose) \
4111 : return ErrorInvalidValue(#name ": transpose must be FALSE as per the OpenGL ES 2.0 spec"); \
4112 : MakeContextCurrent(); \
4113 : gl->f##name(location, JS_GetTypedArrayLength(wa) / (dim*dim), transpose, (ptrType *)JS_GetTypedArrayData(wa)); \
4114 : return NS_OK; \
4115 : }
4116 :
4117 : #define SIMPLE_METHOD_UNIFORM_1(glname, name, t1) \
4118 : NS_IMETHODIMP WebGLContext::name(nsIWebGLUniformLocation *ploc, t1 a1) { \
4119 : if (!IsContextStable()) \
4120 : return NS_OK; \
4121 : OBTAIN_UNIFORM_LOCATION(#name ": location") \
4122 : MakeContextCurrent(); gl->f##glname(location, a1); return NS_OK; \
4123 : }
4124 :
4125 : #define SIMPLE_METHOD_UNIFORM_2(glname, name, t1, t2) \
4126 : NS_IMETHODIMP WebGLContext::name(nsIWebGLUniformLocation *ploc, t1 a1, t2 a2) { \
4127 : if (!IsContextStable()) \
4128 : return NS_OK; \
4129 : OBTAIN_UNIFORM_LOCATION(#name ": location") \
4130 : MakeContextCurrent(); gl->f##glname(location, a1, a2); return NS_OK; \
4131 : }
4132 :
4133 : #define SIMPLE_METHOD_UNIFORM_3(glname, name, t1, t2, t3) \
4134 : NS_IMETHODIMP WebGLContext::name(nsIWebGLUniformLocation *ploc, t1 a1, t2 a2, t3 a3) { \
4135 : if (!IsContextStable()) \
4136 : return NS_OK; \
4137 : OBTAIN_UNIFORM_LOCATION(#name ": location") \
4138 : MakeContextCurrent(); gl->f##glname(location, a1, a2, a3); return NS_OK; \
4139 : }
4140 :
4141 : #define SIMPLE_METHOD_UNIFORM_4(glname, name, t1, t2, t3, t4) \
4142 : NS_IMETHODIMP WebGLContext::name(nsIWebGLUniformLocation *ploc, t1 a1, t2 a2, t3 a3, t4 a4) { \
4143 : if (!IsContextStable()) \
4144 : return NS_OK; \
4145 : OBTAIN_UNIFORM_LOCATION(#name ": location") \
4146 : MakeContextCurrent(); gl->f##glname(location, a1, a2, a3, a4); return NS_OK; \
4147 : }
4148 :
4149 0 : SIMPLE_METHOD_UNIFORM_1(Uniform1i, Uniform1i, WebGLint)
4150 0 : SIMPLE_METHOD_UNIFORM_2(Uniform2i, Uniform2i, WebGLint, WebGLint)
4151 0 : SIMPLE_METHOD_UNIFORM_3(Uniform3i, Uniform3i, WebGLint, WebGLint, WebGLint)
4152 0 : SIMPLE_METHOD_UNIFORM_4(Uniform4i, Uniform4i, WebGLint, WebGLint, WebGLint, WebGLint)
4153 :
4154 0 : SIMPLE_METHOD_UNIFORM_1(Uniform1f, Uniform1f, WebGLfloat)
4155 0 : SIMPLE_METHOD_UNIFORM_2(Uniform2f, Uniform2f, WebGLfloat, WebGLfloat)
4156 0 : SIMPLE_METHOD_UNIFORM_3(Uniform3f, Uniform3f, WebGLfloat, WebGLfloat, WebGLfloat)
4157 0 : SIMPLE_METHOD_UNIFORM_4(Uniform4f, Uniform4f, WebGLfloat, WebGLfloat, WebGLfloat, WebGLfloat)
4158 :
4159 0 : SIMPLE_ARRAY_METHOD_UNIFORM(Uniform1iv, 1, TYPE_INT32, WebGLint)
4160 0 : SIMPLE_ARRAY_METHOD_UNIFORM(Uniform2iv, 2, TYPE_INT32, WebGLint)
4161 0 : SIMPLE_ARRAY_METHOD_UNIFORM(Uniform3iv, 3, TYPE_INT32, WebGLint)
4162 0 : SIMPLE_ARRAY_METHOD_UNIFORM(Uniform4iv, 4, TYPE_INT32, WebGLint)
4163 :
4164 0 : SIMPLE_ARRAY_METHOD_UNIFORM(Uniform1fv, 1, TYPE_FLOAT32, WebGLfloat)
4165 0 : SIMPLE_ARRAY_METHOD_UNIFORM(Uniform2fv, 2, TYPE_FLOAT32, WebGLfloat)
4166 0 : SIMPLE_ARRAY_METHOD_UNIFORM(Uniform3fv, 3, TYPE_FLOAT32, WebGLfloat)
4167 0 : SIMPLE_ARRAY_METHOD_UNIFORM(Uniform4fv, 4, TYPE_FLOAT32, WebGLfloat)
4168 :
4169 0 : SIMPLE_MATRIX_METHOD_UNIFORM(UniformMatrix2fv, 2, TYPE_FLOAT32, WebGLfloat)
4170 0 : SIMPLE_MATRIX_METHOD_UNIFORM(UniformMatrix3fv, 3, TYPE_FLOAT32, WebGLfloat)
4171 0 : SIMPLE_MATRIX_METHOD_UNIFORM(UniformMatrix4fv, 4, TYPE_FLOAT32, WebGLfloat)
4172 :
4173 : NS_IMETHODIMP
4174 0 : WebGLContext::VertexAttrib1f(PRUint32 index, WebGLfloat x0)
4175 : {
4176 0 : if (!IsContextStable())
4177 0 : return NS_OK;
4178 :
4179 0 : MakeContextCurrent();
4180 :
4181 0 : if (index) {
4182 0 : gl->fVertexAttrib1f(index, x0);
4183 : } else {
4184 0 : mVertexAttrib0Vector[0] = x0;
4185 0 : mVertexAttrib0Vector[1] = 0;
4186 0 : mVertexAttrib0Vector[2] = 0;
4187 0 : mVertexAttrib0Vector[3] = 1;
4188 0 : if (gl->IsGLES2())
4189 0 : gl->fVertexAttrib1f(index, x0);
4190 : }
4191 :
4192 0 : return NS_OK;
4193 : }
4194 :
4195 : NS_IMETHODIMP
4196 0 : WebGLContext::VertexAttrib2f(PRUint32 index, WebGLfloat x0, WebGLfloat x1)
4197 : {
4198 0 : if (!IsContextStable())
4199 0 : return NS_OK;
4200 :
4201 0 : MakeContextCurrent();
4202 :
4203 0 : if (index) {
4204 0 : gl->fVertexAttrib2f(index, x0, x1);
4205 : } else {
4206 0 : mVertexAttrib0Vector[0] = x0;
4207 0 : mVertexAttrib0Vector[1] = x1;
4208 0 : mVertexAttrib0Vector[2] = 0;
4209 0 : mVertexAttrib0Vector[3] = 1;
4210 0 : if (gl->IsGLES2())
4211 0 : gl->fVertexAttrib2f(index, x0, x1);
4212 : }
4213 :
4214 0 : return NS_OK;
4215 : }
4216 :
4217 : NS_IMETHODIMP
4218 0 : WebGLContext::VertexAttrib3f(PRUint32 index, WebGLfloat x0, WebGLfloat x1, WebGLfloat x2)
4219 : {
4220 0 : if (!IsContextStable())
4221 0 : return NS_OK;
4222 :
4223 0 : MakeContextCurrent();
4224 :
4225 0 : if (index) {
4226 0 : gl->fVertexAttrib3f(index, x0, x1, x2);
4227 : } else {
4228 0 : mVertexAttrib0Vector[0] = x0;
4229 0 : mVertexAttrib0Vector[1] = x1;
4230 0 : mVertexAttrib0Vector[2] = x2;
4231 0 : mVertexAttrib0Vector[3] = 1;
4232 0 : if (gl->IsGLES2())
4233 0 : gl->fVertexAttrib3f(index, x0, x1, x2);
4234 : }
4235 :
4236 0 : return NS_OK;
4237 : }
4238 :
4239 : NS_IMETHODIMP
4240 0 : WebGLContext::VertexAttrib4f(PRUint32 index, WebGLfloat x0, WebGLfloat x1,
4241 : WebGLfloat x2, WebGLfloat x3)
4242 : {
4243 0 : if (!IsContextStable())
4244 0 : return NS_OK;
4245 :
4246 0 : MakeContextCurrent();
4247 :
4248 0 : if (index) {
4249 0 : gl->fVertexAttrib4f(index, x0, x1, x2, x3);
4250 : } else {
4251 0 : mVertexAttrib0Vector[0] = x0;
4252 0 : mVertexAttrib0Vector[1] = x1;
4253 0 : mVertexAttrib0Vector[2] = x2;
4254 0 : mVertexAttrib0Vector[3] = x3;
4255 0 : if (gl->IsGLES2())
4256 0 : gl->fVertexAttrib4f(index, x0, x1, x2, x3);
4257 : }
4258 :
4259 0 : return NS_OK;
4260 : }
4261 :
4262 : #define SIMPLE_ARRAY_METHOD_NO_COUNT(name, cnt, arrayType, ptrType) \
4263 : NS_IMETHODIMP \
4264 : WebGLContext::name(PRInt32) { \
4265 : return NS_ERROR_NOT_IMPLEMENTED; \
4266 : } \
4267 : NS_IMETHODIMP \
4268 : WebGLContext::name##_array(WebGLuint idx, JSObject *wa) \
4269 : { \
4270 : if (!IsContextStable()) \
4271 : return NS_OK; \
4272 : if (!wa || JS_GetTypedArrayType(wa) != js::TypedArray::arrayType) \
4273 : return ErrorInvalidOperation(#name ": array must be " #arrayType); \
4274 : if (JS_GetTypedArrayLength(wa) < cnt) \
4275 : return ErrorInvalidOperation(#name ": array must be >= %d elements", cnt); \
4276 : MakeContextCurrent(); \
4277 : ptrType *ptr = (ptrType *)JS_GetTypedArrayData(wa); \
4278 : if (idx) { \
4279 : gl->f##name(idx, ptr); \
4280 : } else { \
4281 : mVertexAttrib0Vector[0] = ptr[0]; \
4282 : mVertexAttrib0Vector[1] = cnt > 1 ? ptr[1] : ptrType(0); \
4283 : mVertexAttrib0Vector[2] = cnt > 2 ? ptr[2] : ptrType(0); \
4284 : mVertexAttrib0Vector[3] = cnt > 3 ? ptr[3] : ptrType(1); \
4285 : if (gl->IsGLES2()) \
4286 : gl->f##name(idx, ptr); \
4287 : } \
4288 : return NS_OK; \
4289 : }
4290 :
4291 0 : SIMPLE_ARRAY_METHOD_NO_COUNT(VertexAttrib1fv, 1, TYPE_FLOAT32, WebGLfloat)
4292 0 : SIMPLE_ARRAY_METHOD_NO_COUNT(VertexAttrib2fv, 2, TYPE_FLOAT32, WebGLfloat)
4293 0 : SIMPLE_ARRAY_METHOD_NO_COUNT(VertexAttrib3fv, 3, TYPE_FLOAT32, WebGLfloat)
4294 0 : SIMPLE_ARRAY_METHOD_NO_COUNT(VertexAttrib4fv, 4, TYPE_FLOAT32, WebGLfloat)
4295 :
4296 : NS_IMETHODIMP
4297 0 : WebGLContext::UseProgram(nsIWebGLProgram *pobj)
4298 : {
4299 0 : if (!IsContextStable())
4300 0 : return NS_OK;
4301 :
4302 : WebGLProgram *prog;
4303 : WebGLuint progname;
4304 : bool isNull;
4305 0 : if (!GetConcreteObjectAndGLName("useProgram", pobj, &prog, &progname, &isNull))
4306 0 : return NS_OK;
4307 :
4308 0 : MakeContextCurrent();
4309 :
4310 0 : if (prog && !prog->LinkStatus())
4311 0 : return ErrorInvalidOperation("UseProgram: program was not linked successfully");
4312 :
4313 0 : gl->fUseProgram(progname);
4314 :
4315 0 : mCurrentProgram = prog;
4316 :
4317 0 : return NS_OK;
4318 : }
4319 :
4320 : NS_IMETHODIMP
4321 0 : WebGLContext::ValidateProgram(nsIWebGLProgram *pobj)
4322 : {
4323 0 : if (!IsContextStable())
4324 0 : return NS_OK;
4325 :
4326 : WebGLuint progname;
4327 0 : if (!GetGLName<WebGLProgram>("validateProgram", pobj, &progname))
4328 0 : return NS_OK;
4329 :
4330 0 : MakeContextCurrent();
4331 :
4332 : #ifdef XP_MACOSX
4333 : // see bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed with Mac OS 10.6.7
4334 : LogMessageIfVerbose("validateProgram: implemented as a no-operation on Mac to work around crashes");
4335 : return NS_OK;
4336 : #endif
4337 :
4338 0 : gl->fValidateProgram(progname);
4339 :
4340 0 : return NS_OK;
4341 : }
4342 :
4343 : NS_IMETHODIMP
4344 0 : WebGLContext::CreateFramebuffer(nsIWebGLFramebuffer **retval)
4345 : {
4346 0 : if (!IsContextStable())
4347 0 : return NS_OK;
4348 :
4349 0 : *retval = 0;
4350 :
4351 0 : WebGLFramebuffer *globj = new WebGLFramebuffer(this);
4352 0 : NS_ADDREF(*retval = globj);
4353 :
4354 0 : return NS_OK;
4355 : }
4356 :
4357 : NS_IMETHODIMP
4358 0 : WebGLContext::CreateRenderbuffer(nsIWebGLRenderbuffer **retval)
4359 : {
4360 0 : if (!IsContextStable())
4361 0 : return NS_OK;
4362 :
4363 0 : *retval = 0;
4364 :
4365 0 : WebGLRenderbuffer *globj = new WebGLRenderbuffer(this);
4366 0 : NS_ADDREF(*retval = globj);
4367 :
4368 0 : return NS_OK;
4369 : }
4370 :
4371 : NS_IMETHODIMP
4372 0 : WebGLContext::Viewport(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height)
4373 : {
4374 0 : if (!IsContextStable())
4375 0 : return NS_OK;
4376 :
4377 0 : if (width < 0 || height < 0)
4378 0 : return ErrorInvalidValue("Viewport: negative size");
4379 :
4380 0 : MakeContextCurrent();
4381 0 : gl->fViewport(x, y, width, height);
4382 0 : return NS_OK;
4383 : }
4384 :
4385 : NS_IMETHODIMP
4386 0 : WebGLContext::CompileShader(nsIWebGLShader *sobj)
4387 : {
4388 0 : if (!IsContextStable())
4389 0 : return NS_OK;
4390 :
4391 : WebGLShader *shader;
4392 : WebGLuint shadername;
4393 0 : if (!GetConcreteObjectAndGLName("compileShader", sobj, &shader, &shadername))
4394 0 : return NS_OK;
4395 :
4396 0 : MakeContextCurrent();
4397 :
4398 0 : ShShaderOutput targetShaderSourceLanguage = gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
4399 0 : bool useShaderSourceTranslation = true;
4400 :
4401 : #ifdef ANDROID
4402 : // see bug 709947. On Android, we can't use the ESSL backend because of strange crashes (might be
4403 : // an allocator mismatch). So we use the GLSL backend, and discard the output, instead just passing
4404 : // the original WebGL shader source to the GL (since that's ESSL already). The problem is that means
4405 : // we can't use shader translations on Android, in particular we can't use long identifier shortening,
4406 : // which means we can't reach 100% conformance. We need to fix that by debugging the ESSL backend
4407 : // memory crashes.
4408 : targetShaderSourceLanguage = SH_GLSL_OUTPUT;
4409 : useShaderSourceTranslation = false;
4410 : #endif
4411 :
4412 : #if defined(USE_ANGLE)
4413 0 : if (shader->NeedsTranslation() && mShaderValidation) {
4414 0 : ShHandle compiler = 0;
4415 : ShBuiltInResources resources;
4416 0 : memset(&resources, 0, sizeof(ShBuiltInResources));
4417 :
4418 0 : resources.MaxVertexAttribs = mGLMaxVertexAttribs;
4419 0 : resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
4420 0 : resources.MaxVaryingVectors = mGLMaxVaryingVectors;
4421 0 : resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
4422 0 : resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
4423 0 : resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
4424 0 : resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
4425 0 : resources.MaxDrawBuffers = 1;
4426 0 : if (mEnabledExtensions[WebGL_OES_standard_derivatives])
4427 0 : resources.OES_standard_derivatives = 1;
4428 :
4429 : // We're storing an actual instance of StripComments because, if we don't, the
4430 : // cleanSource nsAString instance will be destroyed before the reference is
4431 : // actually used.
4432 0 : StripComments stripComments(shader->Source());
4433 0 : const nsAString& cleanSource = nsString(stripComments.result().Elements(), stripComments.length());
4434 0 : if (!ValidateGLSLString(cleanSource, "compileShader"))
4435 0 : return NS_OK;
4436 :
4437 0 : const nsPromiseFlatString& flatSource = PromiseFlatString(cleanSource);
4438 :
4439 : // shaderSource() already checks that the source stripped of comments is in the
4440 : // 7-bit ASCII range, so we can skip the NS_IsAscii() check.
4441 0 : const nsCString& sourceCString = NS_LossyConvertUTF16toASCII(flatSource);
4442 :
4443 0 : const PRUint32 maxSourceLength = (PRUint32(1)<<18) - 1;
4444 0 : if (sourceCString.Length() > maxSourceLength)
4445 0 : return ErrorInvalidValue("compileShader: source has more than %d characters", maxSourceLength);
4446 :
4447 0 : const char *s = sourceCString.get();
4448 :
4449 0 : compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
4450 : SH_WEBGL_SPEC,
4451 : targetShaderSourceLanguage,
4452 0 : &resources);
4453 :
4454 0 : int compileOptions = 0;
4455 0 : if (useShaderSourceTranslation) {
4456 : compileOptions |= SH_OBJECT_CODE
4457 : | SH_MAP_LONG_VARIABLE_NAMES
4458 0 : | SH_ATTRIBUTES_UNIFORMS;
4459 : #ifdef XP_MACOSX
4460 : // work around bug 665578
4461 : if (!nsCocoaFeatures::OnLionOrLater() && gl->Vendor() == gl::GLContext::VendorATI)
4462 : compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
4463 : #endif
4464 : }
4465 :
4466 0 : if (!ShCompile(compiler, &s, 1, compileOptions)) {
4467 0 : int len = 0;
4468 0 : ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &len);
4469 :
4470 0 : if (len) {
4471 0 : nsCAutoString info;
4472 0 : info.SetLength(len);
4473 0 : ShGetInfoLog(compiler, info.BeginWriting());
4474 0 : shader->SetTranslationFailure(info);
4475 : } else {
4476 0 : shader->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log"));
4477 : }
4478 0 : ShDestruct(compiler);
4479 0 : return NS_OK;
4480 : }
4481 :
4482 0 : int num_attributes = 0;
4483 0 : ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTES, &num_attributes);
4484 0 : int num_uniforms = 0;
4485 0 : ShGetInfo(compiler, SH_ACTIVE_UNIFORMS, &num_uniforms);
4486 0 : int attrib_max_length = 0;
4487 0 : ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrib_max_length);
4488 0 : int uniform_max_length = 0;
4489 0 : ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_max_length);
4490 0 : int mapped_max_length = 0;
4491 0 : ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_max_length);
4492 :
4493 0 : shader->mAttribMaxNameLength = attrib_max_length;
4494 :
4495 0 : shader->mAttributes.Clear();
4496 0 : shader->mUniforms.Clear();
4497 0 : nsAutoArrayPtr<char> attribute_name(new char[attrib_max_length+1]);
4498 0 : nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]);
4499 0 : nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]);
4500 :
4501 0 : if (useShaderSourceTranslation) {
4502 0 : for (int i = 0; i < num_attributes; i++) {
4503 : int length, size;
4504 : ShDataType type;
4505 : ShGetActiveAttrib(compiler, i,
4506 : &length, &size, &type,
4507 : attribute_name,
4508 0 : mapped_name);
4509 : shader->mAttributes.AppendElement(WebGLMappedIdentifier(
4510 0 : nsDependentCString(attribute_name),
4511 0 : nsDependentCString(mapped_name)));
4512 : }
4513 :
4514 0 : for (int i = 0; i < num_uniforms; i++) {
4515 : int length, size;
4516 : ShDataType type;
4517 : ShGetActiveUniform(compiler, i,
4518 : &length, &size, &type,
4519 : uniform_name,
4520 0 : mapped_name);
4521 : shader->mUniforms.AppendElement(WebGLMappedIdentifier(
4522 0 : nsDependentCString(uniform_name),
4523 0 : nsDependentCString(mapped_name)));
4524 : }
4525 :
4526 0 : int len = 0;
4527 0 : ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &len);
4528 :
4529 0 : nsCAutoString translatedSrc;
4530 0 : translatedSrc.SetLength(len);
4531 0 : ShGetObjectCode(compiler, translatedSrc.BeginWriting());
4532 :
4533 0 : nsPromiseFlatCString translatedSrc2(translatedSrc);
4534 0 : const char *ts = translatedSrc2.get();
4535 :
4536 0 : gl->fShaderSource(shadername, 1, &ts, NULL);
4537 : } else { // not useShaderSourceTranslation
4538 : // we just pass the raw untranslated shader source. We then can't use ANGLE idenfier mapping.
4539 : // that's really bad, as that means we can't be 100% conformant. We should work towards always
4540 : // using ANGLE identifier mapping.
4541 0 : gl->fShaderSource(shadername, 1, &s, NULL);
4542 : }
4543 :
4544 0 : shader->SetTranslationSuccess();
4545 :
4546 0 : ShDestruct(compiler);
4547 :
4548 0 : gl->fCompileShader(shadername);
4549 : }
4550 : #endif
4551 :
4552 0 : return NS_OK;
4553 : }
4554 :
4555 : NS_IMETHODIMP
4556 0 : WebGLContext::CompressedTexImage2D(PRInt32)
4557 : {
4558 0 : NS_RUNTIMEABORT("CompressedTexImage2D(PRInt32) should never be called");
4559 :
4560 0 : return NS_ERROR_FAILURE;
4561 : }
4562 :
4563 : NS_IMETHODIMP
4564 0 : WebGLContext::CompressedTexImage2D_array(WebGLenum target, WebGLint level, WebGLenum internalformat,
4565 : WebGLsizei width, WebGLsizei height, WebGLint border,
4566 : JSObject *pixels)
4567 : {
4568 0 : if (!IsContextStable())
4569 0 : return NS_OK;
4570 :
4571 0 : WebGLTexture *tex = activeBoundTextureForTarget(target);
4572 0 : if (!tex)
4573 0 : return ErrorInvalidOperation("compressedTexImage2D: no texture is bound to this target");
4574 :
4575 0 : return ErrorInvalidEnum("compressedTexImage2D: compressed textures are not supported");
4576 : }
4577 :
4578 : NS_IMETHODIMP
4579 0 : WebGLContext::CompressedTexSubImage2D(PRInt32)
4580 : {
4581 0 : NS_RUNTIMEABORT("CompressedTexSubImage2D(PRInt32) should never be called");
4582 :
4583 0 : return NS_ERROR_FAILURE;
4584 : }
4585 :
4586 : NS_IMETHODIMP
4587 0 : WebGLContext::CompressedTexSubImage2D_array(WebGLenum target, WebGLint level, WebGLint xoffset,
4588 : WebGLint yoffset, WebGLsizei width, WebGLsizei height,
4589 : WebGLenum format, JSObject *pixels)
4590 : {
4591 0 : if (!IsContextStable())
4592 0 : return NS_OK;
4593 :
4594 0 : WebGLTexture *tex = activeBoundTextureForTarget(target);
4595 0 : if (!tex)
4596 0 : return ErrorInvalidOperation("compressedTexSubImage2D: no texture is bound to this target");
4597 :
4598 0 : return ErrorInvalidEnum("compressedTexSubImage2D: compressed textures are not supported");
4599 : }
4600 :
4601 : NS_IMETHODIMP
4602 0 : WebGLContext::GetShaderParameter(nsIWebGLShader *sobj, WebGLenum pname, nsIVariant **retval)
4603 : {
4604 0 : if (!IsContextStable())
4605 0 : return NS_OK;
4606 :
4607 0 : *retval = nsnull;
4608 :
4609 : WebGLShader *shader;
4610 : WebGLuint shadername;
4611 0 : if (!GetConcreteObjectAndGLName("getShaderParameter: shader", sobj, &shader, &shadername))
4612 0 : return NS_OK;
4613 :
4614 0 : nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
4615 0 : NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
4616 :
4617 0 : MakeContextCurrent();
4618 :
4619 0 : switch (pname) {
4620 : case LOCAL_GL_SHADER_TYPE:
4621 : case LOCAL_GL_INFO_LOG_LENGTH:
4622 : {
4623 0 : GLint i = 0;
4624 0 : gl->fGetShaderiv(shadername, pname, &i);
4625 0 : wrval->SetAsInt32(i);
4626 : }
4627 0 : break;
4628 : case LOCAL_GL_SHADER_SOURCE_LENGTH:
4629 : {
4630 0 : wrval->SetAsInt32(PRInt32(shader->Source().Length()) + 1);
4631 : }
4632 0 : break;
4633 : case LOCAL_GL_DELETE_STATUS:
4634 0 : wrval->SetAsBool(shader->IsDeleteRequested());
4635 0 : break;
4636 : case LOCAL_GL_COMPILE_STATUS:
4637 : {
4638 0 : GLint i = 0;
4639 0 : gl->fGetShaderiv(shadername, pname, &i);
4640 0 : wrval->SetAsBool(bool(i));
4641 : }
4642 0 : break;
4643 : default:
4644 0 : return NS_ERROR_NOT_IMPLEMENTED;
4645 : }
4646 :
4647 0 : *retval = wrval.forget().get();
4648 :
4649 0 : return NS_OK;
4650 : }
4651 :
4652 : NS_IMETHODIMP
4653 0 : WebGLContext::GetShaderInfoLog(nsIWebGLShader *sobj, nsAString& retval)
4654 : {
4655 0 : if (!IsContextStable())
4656 : {
4657 0 : retval.SetIsVoid(true);
4658 0 : return NS_OK;
4659 : }
4660 :
4661 : WebGLShader *shader;
4662 : WebGLuint shadername;
4663 0 : if (!GetConcreteObjectAndGLName("getShaderInfoLog: shader", sobj, &shader, &shadername))
4664 0 : return NS_OK;
4665 :
4666 0 : const nsCString& tlog = shader->TranslationLog();
4667 0 : if (!tlog.IsVoid()) {
4668 0 : CopyASCIItoUTF16(tlog, retval);
4669 0 : return NS_OK;
4670 : }
4671 :
4672 0 : MakeContextCurrent();
4673 :
4674 0 : GLint k = -1;
4675 0 : gl->fGetShaderiv(shadername, LOCAL_GL_INFO_LOG_LENGTH, &k);
4676 0 : if (k == -1)
4677 0 : return NS_ERROR_FAILURE; // XXX GL Error? should never happen.
4678 :
4679 0 : if (k == 0) {
4680 0 : retval.Truncate();
4681 0 : return NS_OK;
4682 : }
4683 :
4684 0 : nsCAutoString log;
4685 0 : log.SetCapacity(k);
4686 :
4687 0 : gl->fGetShaderInfoLog(shadername, k, &k, (char*) log.BeginWriting());
4688 :
4689 0 : log.SetLength(k);
4690 :
4691 0 : CopyASCIItoUTF16(log, retval);
4692 :
4693 0 : return NS_OK;
4694 : }
4695 :
4696 : NS_IMETHODIMP
4697 0 : WebGLContext::GetShaderPrecisionFormat(WebGLenum shadertype, WebGLenum precisiontype, nsIWebGLShaderPrecisionFormat **retval)
4698 : {
4699 0 : *retval = nsnull;
4700 0 : if (!IsContextStable())
4701 0 : return NS_OK;
4702 :
4703 0 : switch (shadertype) {
4704 : case LOCAL_GL_FRAGMENT_SHADER:
4705 : case LOCAL_GL_VERTEX_SHADER:
4706 : break;
4707 : default:
4708 0 : return ErrorInvalidEnumInfo("getShaderPrecisionFormat: shadertype", shadertype);
4709 : }
4710 :
4711 0 : switch (precisiontype) {
4712 : case LOCAL_GL_LOW_FLOAT:
4713 : case LOCAL_GL_MEDIUM_FLOAT:
4714 : case LOCAL_GL_HIGH_FLOAT:
4715 : case LOCAL_GL_LOW_INT:
4716 : case LOCAL_GL_MEDIUM_INT:
4717 : case LOCAL_GL_HIGH_INT:
4718 : break;
4719 : default:
4720 0 : return ErrorInvalidEnumInfo("getShaderPrecisionFormat: precisiontype", precisiontype);
4721 : }
4722 :
4723 0 : MakeContextCurrent();
4724 :
4725 : GLint range[2], precision;
4726 0 : gl->fGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision);
4727 :
4728 : WebGLShaderPrecisionFormat *retShaderPrecisionFormat
4729 0 : = new WebGLShaderPrecisionFormat(range[0], range[1], precision);
4730 0 : NS_ADDREF(*retval = retShaderPrecisionFormat);
4731 :
4732 0 : return NS_OK;
4733 : }
4734 :
4735 : NS_IMETHODIMP
4736 0 : WebGLContext::GetShaderSource(nsIWebGLShader *sobj, nsAString& retval)
4737 : {
4738 0 : if (!IsContextStable())
4739 : {
4740 0 : retval.SetIsVoid(true);
4741 0 : return NS_OK;
4742 : }
4743 :
4744 : WebGLShader *shader;
4745 : WebGLuint shadername;
4746 0 : if (!GetConcreteObjectAndGLName("getShaderSource: shader", sobj, &shader, &shadername))
4747 0 : return NS_OK;
4748 :
4749 0 : retval.Assign(shader->Source());
4750 :
4751 0 : return NS_OK;
4752 : }
4753 :
4754 : NS_IMETHODIMP
4755 0 : WebGLContext::ShaderSource(nsIWebGLShader *sobj, const nsAString& source)
4756 : {
4757 0 : if (!IsContextStable())
4758 0 : return NS_OK;
4759 :
4760 : WebGLShader *shader;
4761 : WebGLuint shadername;
4762 0 : if (!GetConcreteObjectAndGLName("shaderSource: shader", sobj, &shader, &shadername))
4763 0 : return NS_OK;
4764 :
4765 : // We're storing an actual instance of StripComments because, if we don't, the
4766 : // cleanSource nsAString instance will be destroyed before the reference is
4767 : // actually used.
4768 0 : StripComments stripComments(source);
4769 0 : const nsAString& cleanSource = nsString(stripComments.result().Elements(), stripComments.length());
4770 0 : if (!ValidateGLSLString(cleanSource, "compileShader"))
4771 0 : return NS_OK;
4772 :
4773 0 : shader->SetSource(source);
4774 :
4775 0 : shader->SetNeedsTranslation();
4776 :
4777 0 : return NS_OK;
4778 : }
4779 :
4780 : NS_IMETHODIMP
4781 0 : WebGLContext::VertexAttribPointer(WebGLuint index, WebGLint size, WebGLenum type,
4782 : WebGLboolean normalized, WebGLsizei stride,
4783 : WebGLsizeiptr byteOffset)
4784 : {
4785 0 : if (!IsContextStable())
4786 0 : return NS_OK;
4787 :
4788 0 : if (mBoundArrayBuffer == nsnull)
4789 0 : return ErrorInvalidOperation("VertexAttribPointer: must have valid GL_ARRAY_BUFFER binding");
4790 :
4791 0 : WebGLsizei requiredAlignment = 1;
4792 0 : switch (type) {
4793 : case LOCAL_GL_BYTE:
4794 : case LOCAL_GL_UNSIGNED_BYTE:
4795 0 : requiredAlignment = 1;
4796 0 : break;
4797 : case LOCAL_GL_SHORT:
4798 : case LOCAL_GL_UNSIGNED_SHORT:
4799 0 : requiredAlignment = 2;
4800 0 : break;
4801 : // XXX case LOCAL_GL_FIXED:
4802 : case LOCAL_GL_FLOAT:
4803 0 : requiredAlignment = 4;
4804 0 : break;
4805 : default:
4806 0 : return ErrorInvalidEnumInfo("VertexAttribPointer: type", type);
4807 : }
4808 :
4809 : // requiredAlignment should always be a power of two.
4810 0 : WebGLsizei requiredAlignmentMask = requiredAlignment - 1;
4811 :
4812 0 : if (!ValidateAttribIndex(index, "vertexAttribPointer"))
4813 0 : return NS_OK;
4814 :
4815 0 : if (size < 1 || size > 4)
4816 0 : return ErrorInvalidValue("VertexAttribPointer: invalid element size");
4817 :
4818 0 : if (stride < 0 || stride > 255) // see WebGL spec section 6.6 "Vertex Attribute Data Stride"
4819 0 : return ErrorInvalidValue("VertexAttribPointer: negative or too large stride");
4820 :
4821 0 : if (byteOffset < 0)
4822 0 : return ErrorInvalidValue("VertexAttribPointer: negative offset");
4823 :
4824 0 : if (stride & requiredAlignmentMask) {
4825 : return ErrorInvalidOperation("VertexAttribPointer: stride doesn't satisfy the alignment "
4826 0 : "requirement of given type");
4827 : }
4828 :
4829 0 : if (byteOffset & requiredAlignmentMask) {
4830 : return ErrorInvalidOperation("VertexAttribPointer: byteOffset doesn't satisfy the alignment "
4831 0 : "requirement of given type");
4832 :
4833 : }
4834 :
4835 : /* XXX make work with bufferSubData & heterogeneous types
4836 : if (type != mBoundArrayBuffer->GLType())
4837 : return ErrorInvalidOperation("VertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType());
4838 : */
4839 :
4840 0 : WebGLVertexAttribData &vd = mAttribBuffers[index];
4841 :
4842 0 : vd.buf = mBoundArrayBuffer;
4843 0 : vd.stride = stride;
4844 0 : vd.size = size;
4845 0 : vd.byteOffset = byteOffset;
4846 0 : vd.type = type;
4847 0 : vd.normalized = normalized;
4848 :
4849 0 : MakeContextCurrent();
4850 :
4851 : gl->fVertexAttribPointer(index, size, type, normalized,
4852 : stride,
4853 0 : reinterpret_cast<void*>(byteOffset));
4854 :
4855 0 : return NS_OK;
4856 : }
4857 :
4858 : NS_IMETHODIMP
4859 0 : WebGLContext::TexImage2D(PRInt32)
4860 : {
4861 0 : if (!IsContextStable())
4862 0 : return NS_OK;
4863 :
4864 0 : return NS_ERROR_FAILURE;
4865 : }
4866 :
4867 0 : GLenum WebGLContext::CheckedTexImage2D(GLenum target,
4868 : GLint level,
4869 : GLenum internalFormat,
4870 : GLsizei width,
4871 : GLsizei height,
4872 : GLint border,
4873 : GLenum format,
4874 : GLenum type,
4875 : const GLvoid *data)
4876 : {
4877 0 : WebGLTexture *tex = activeBoundTextureForTarget(target);
4878 0 : NS_ABORT_IF_FALSE(tex != nsnull, "no texture bound");
4879 :
4880 0 : bool sizeMayChange = true;
4881 0 : size_t face = WebGLTexture::FaceForTarget(target);
4882 :
4883 0 : if (tex->HasImageInfoAt(level, face)) {
4884 0 : const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(level, face);
4885 0 : sizeMayChange = width != imageInfo.Width() ||
4886 0 : height != imageInfo.Height() ||
4887 0 : format != imageInfo.Format() ||
4888 0 : type != imageInfo.Type();
4889 : }
4890 :
4891 0 : if (sizeMayChange) {
4892 0 : UpdateWebGLErrorAndClearGLError();
4893 0 : gl->fTexImage2D(target, level, internalFormat, width, height, border, format, type, data);
4894 0 : GLenum error = LOCAL_GL_NO_ERROR;
4895 0 : UpdateWebGLErrorAndClearGLError(&error);
4896 0 : return error;
4897 : } else {
4898 0 : gl->fTexImage2D(target, level, internalFormat, width, height, border, format, type, data);
4899 0 : return LOCAL_GL_NO_ERROR;
4900 : }
4901 : }
4902 :
4903 : nsresult
4904 0 : WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum internalformat,
4905 : WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero,
4906 : WebGLint border,
4907 : WebGLenum format, WebGLenum type,
4908 : void *data, PRUint32 byteLength,
4909 : int jsArrayType, // a TypedArray format enum, or -1 if not relevant
4910 : int srcFormat, bool srcPremultiplied)
4911 : {
4912 0 : switch (target) {
4913 : case LOCAL_GL_TEXTURE_2D:
4914 0 : break;
4915 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4916 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4917 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4918 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4919 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4920 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
4921 0 : if (width != height)
4922 0 : return ErrorInvalidValue("texImage2D: with cube map targets, width and height must be equal");
4923 0 : break;
4924 : default:
4925 0 : return ErrorInvalidEnumInfo("texImage2D: target", target);
4926 : }
4927 :
4928 0 : switch (format) {
4929 : case LOCAL_GL_RGB:
4930 : case LOCAL_GL_RGBA:
4931 : case LOCAL_GL_ALPHA:
4932 : case LOCAL_GL_LUMINANCE:
4933 : case LOCAL_GL_LUMINANCE_ALPHA:
4934 : break;
4935 : default:
4936 0 : return ErrorInvalidEnumInfo("texImage2D: internal format", internalformat);
4937 : }
4938 :
4939 0 : if (format != internalformat)
4940 0 : return ErrorInvalidOperation("texImage2D: format does not match internalformat");
4941 :
4942 0 : WebGLsizei maxTextureSize = MaxTextureSizeForTarget(target);
4943 :
4944 0 : if (level < 0)
4945 0 : return ErrorInvalidValue("texImage2D: level must be >= 0");
4946 :
4947 0 : if (!(maxTextureSize >> level))
4948 0 : return ErrorInvalidValue("texImage2D: 2^level exceeds maximum texture size");
4949 :
4950 0 : if (width < 0 || height < 0)
4951 0 : return ErrorInvalidValue("texImage2D: width and height must be >= 0");
4952 :
4953 0 : if (width > maxTextureSize || height > maxTextureSize)
4954 0 : return ErrorInvalidValue("texImage2D: width or height exceeds maximum texture size");
4955 :
4956 0 : if (level >= 1) {
4957 0 : if (!(is_pot_assuming_nonnegative(width) &&
4958 0 : is_pot_assuming_nonnegative(height)))
4959 0 : return ErrorInvalidValue("texImage2D: with level > 0, width and height must be powers of two");
4960 : }
4961 :
4962 0 : if (border != 0)
4963 0 : return ErrorInvalidValue("TexImage2D: border must be 0");
4964 :
4965 0 : PRUint32 texelSize = 0;
4966 0 : if (!ValidateTexFormatAndType(format, type, jsArrayType, &texelSize, "texImage2D"))
4967 0 : return NS_OK;
4968 :
4969 : CheckedUint32 checked_neededByteLength =
4970 0 : GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
4971 :
4972 0 : CheckedUint32 checked_plainRowSize = CheckedUint32(width) * texelSize;
4973 :
4974 : CheckedUint32 checked_alignedRowSize =
4975 0 : RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
4976 :
4977 0 : if (!checked_neededByteLength.valid())
4978 0 : return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size");
4979 :
4980 0 : PRUint32 bytesNeeded = checked_neededByteLength.value();
4981 :
4982 0 : if (byteLength && byteLength < bytesNeeded)
4983 : return ErrorInvalidOperation("TexImage2D: not enough data for operation (need %d, have %d)",
4984 0 : bytesNeeded, byteLength);
4985 :
4986 0 : WebGLTexture *tex = activeBoundTextureForTarget(target);
4987 :
4988 0 : if (!tex)
4989 0 : return ErrorInvalidOperation("texImage2D: no texture is bound to this target");
4990 :
4991 0 : MakeContextCurrent();
4992 :
4993 : // Handle ES2 and GL differences in floating point internal formats. Note that
4994 : // format == internalformat, as checked above and as required by ES.
4995 0 : internalformat = InternalFormatForFormatAndType(format, type, gl->IsGLES2());
4996 :
4997 0 : GLenum error = LOCAL_GL_NO_ERROR;
4998 :
4999 0 : if (byteLength) {
5000 0 : int dstFormat = GetWebGLTexelFormat(format, type);
5001 0 : int actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
5002 0 : size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
5003 :
5004 0 : size_t dstPlainRowSize = texelSize * width;
5005 0 : size_t unpackAlignment = mPixelStoreUnpackAlignment;
5006 0 : size_t dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment;
5007 :
5008 0 : if (actualSrcFormat == dstFormat &&
5009 : srcPremultiplied == mPixelStorePremultiplyAlpha &&
5010 : srcStride == dstStride &&
5011 0 : !mPixelStoreFlipY)
5012 : {
5013 : // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
5014 : error = CheckedTexImage2D(target, level, internalformat,
5015 0 : width, height, border, format, type, data);
5016 : }
5017 : else
5018 : {
5019 0 : nsAutoArrayPtr<PRUint8> convertedData(new PRUint8[bytesNeeded]);
5020 : ConvertImage(width, height, srcStride, dstStride,
5021 : (PRUint8*)data, convertedData,
5022 : actualSrcFormat, srcPremultiplied,
5023 0 : dstFormat, mPixelStorePremultiplyAlpha, texelSize);
5024 : error = CheckedTexImage2D(target, level, internalformat,
5025 0 : width, height, border, format, type, convertedData);
5026 : }
5027 : } else {
5028 : // We need some zero pages, because GL doesn't guarantee the
5029 : // contents of a texture allocated with NULL data.
5030 : // Hopefully calloc will just mmap zero pages here.
5031 0 : void *tempZeroData = calloc(1, bytesNeeded);
5032 0 : if (!tempZeroData)
5033 0 : return ErrorOutOfMemory("texImage2D: could not allocate %d bytes (for zero fill)", bytesNeeded);
5034 :
5035 : error = CheckedTexImage2D(target, level, internalformat,
5036 0 : width, height, border, format, type, tempZeroData);
5037 :
5038 0 : free(tempZeroData);
5039 : }
5040 :
5041 0 : if (error) {
5042 0 : LogMessageIfVerbose("texImage2D generated error %s", ErrorName(error));
5043 0 : return NS_OK;
5044 : }
5045 :
5046 0 : tex->SetImageInfo(target, level, width, height, format, type);
5047 :
5048 0 : return NS_OK;
5049 : }
5050 :
5051 : NS_IMETHODIMP
5052 0 : WebGLContext::TexImage2D_array(WebGLenum target, WebGLint level, WebGLenum internalformat,
5053 : WebGLsizei width, WebGLsizei height, WebGLint border,
5054 : WebGLenum format, WebGLenum type,
5055 : JSObject *pixels)
5056 : {
5057 0 : if (!IsContextStable())
5058 0 : return NS_OK;
5059 :
5060 : return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
5061 : pixels ? JS_GetTypedArrayData(pixels) : 0,
5062 : pixels ? JS_GetTypedArrayByteLength(pixels) : 0,
5063 0 : pixels ? (int)JS_GetTypedArrayType(pixels) : -1,
5064 0 : WebGLTexelFormat::Auto, false);
5065 : }
5066 :
5067 : NS_IMETHODIMP
5068 0 : WebGLContext::TexImage2D_imageData(WebGLenum target, WebGLint level, WebGLenum internalformat,
5069 : WebGLsizei width, WebGLsizei height, WebGLint border,
5070 : WebGLenum format, WebGLenum type,
5071 : JSObject *pixels)
5072 : {
5073 0 : if (!IsContextStable())
5074 0 : return NS_OK;
5075 :
5076 : return TexImage2D_base(target, level, internalformat, width, height, 4*width, border, format, type,
5077 : pixels ? JS_GetTypedArrayData(pixels) : 0,
5078 : pixels ? JS_GetTypedArrayByteLength(pixels) : 0,
5079 : -1,
5080 0 : WebGLTexelFormat::RGBA8, false);
5081 : }
5082 :
5083 : NS_IMETHODIMP
5084 0 : WebGLContext::TexImage2D_dom(WebGLenum target, WebGLint level, WebGLenum internalformat,
5085 : WebGLenum format, GLenum type, Element* elt)
5086 : {
5087 0 : if (!IsContextStable())
5088 0 : return NS_OK;
5089 :
5090 0 : nsRefPtr<gfxImageSurface> isurf;
5091 :
5092 : int srcFormat;
5093 0 : nsresult rv = DOMElementToImageSurface(elt, getter_AddRefs(isurf), &srcFormat);
5094 0 : if (NS_FAILED(rv))
5095 0 : return rv;
5096 :
5097 0 : PRUint32 byteLength = isurf->Stride() * isurf->Height();
5098 :
5099 : return TexImage2D_base(target, level, internalformat,
5100 : isurf->Width(), isurf->Height(), isurf->Stride(), 0,
5101 : format, type,
5102 0 : isurf->Data(), byteLength,
5103 : -1,
5104 0 : srcFormat, mPixelStorePremultiplyAlpha);
5105 : }
5106 :
5107 : NS_IMETHODIMP
5108 0 : WebGLContext::TexSubImage2D(PRInt32)
5109 : {
5110 0 : if (!IsContextStable())
5111 0 : return NS_OK;
5112 :
5113 0 : return NS_ERROR_FAILURE;
5114 : }
5115 :
5116 : nsresult
5117 0 : WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
5118 : WebGLint xoffset, WebGLint yoffset,
5119 : WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero,
5120 : WebGLenum format, WebGLenum type,
5121 : void *pixels, PRUint32 byteLength,
5122 : int jsArrayType,
5123 : int srcFormat, bool srcPremultiplied)
5124 : {
5125 0 : switch (target) {
5126 : case LOCAL_GL_TEXTURE_2D:
5127 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
5128 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
5129 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
5130 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
5131 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
5132 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
5133 : break;
5134 : default:
5135 0 : return ErrorInvalidEnumInfo("texSubImage2D: target", target);
5136 : }
5137 :
5138 0 : WebGLsizei maxTextureSize = MaxTextureSizeForTarget(target);
5139 :
5140 0 : if (level < 0)
5141 0 : return ErrorInvalidValue("texSubImage2D: level must be >= 0");
5142 :
5143 0 : if (!(maxTextureSize >> level))
5144 0 : return ErrorInvalidValue("texSubImage2D: 2^level exceeds maximum texture size");
5145 :
5146 0 : if (width < 0 || height < 0)
5147 0 : return ErrorInvalidValue("texSubImage2D: width and height must be >= 0");
5148 :
5149 0 : if (width > maxTextureSize || height > maxTextureSize)
5150 0 : return ErrorInvalidValue("texSubImage2D: width or height exceeds maximum texture size");
5151 :
5152 0 : if (level >= 1) {
5153 0 : if (!(is_pot_assuming_nonnegative(width) &&
5154 0 : is_pot_assuming_nonnegative(height)))
5155 0 : return ErrorInvalidValue("texSubImage2D: with level > 0, width and height must be powers of two");
5156 : }
5157 :
5158 0 : PRUint32 texelSize = 0;
5159 0 : if (!ValidateTexFormatAndType(format, type, jsArrayType, &texelSize, "texSubImage2D"))
5160 0 : return NS_OK;
5161 :
5162 0 : if (width == 0 || height == 0)
5163 0 : return NS_OK; // ES 2.0 says it has no effect, we better return right now
5164 :
5165 : CheckedUint32 checked_neededByteLength =
5166 0 : GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
5167 :
5168 0 : CheckedUint32 checked_plainRowSize = CheckedUint32(width) * texelSize;
5169 :
5170 : CheckedUint32 checked_alignedRowSize =
5171 0 : RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
5172 :
5173 0 : if (!checked_neededByteLength.valid())
5174 0 : return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
5175 :
5176 0 : PRUint32 bytesNeeded = checked_neededByteLength.value();
5177 :
5178 0 : if (byteLength < bytesNeeded)
5179 0 : return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
5180 :
5181 0 : WebGLTexture *tex = activeBoundTextureForTarget(target);
5182 :
5183 0 : if (!tex)
5184 0 : return ErrorInvalidOperation("texSubImage2D: no texture is bound to this target");
5185 :
5186 0 : size_t face = WebGLTexture::FaceForTarget(target);
5187 :
5188 0 : if (!tex->HasImageInfoAt(level, face))
5189 0 : return ErrorInvalidOperation("texSubImage2D: no texture image previously defined for this level and face");
5190 :
5191 0 : const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(level, face);
5192 0 : if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, imageInfo.Width(), imageInfo.Height()))
5193 0 : return ErrorInvalidValue("texSubImage2D: subtexture rectangle out of bounds");
5194 :
5195 : // Require the format and type in texSubImage2D to match that of the existing texture as created by texImage2D
5196 0 : if (imageInfo.Format() != format || imageInfo.Type() != type)
5197 0 : return ErrorInvalidOperation("texSubImage2D: format or type doesn't match the existing texture");
5198 :
5199 0 : MakeContextCurrent();
5200 :
5201 0 : int dstFormat = GetWebGLTexelFormat(format, type);
5202 0 : int actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
5203 0 : size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
5204 :
5205 0 : size_t dstPlainRowSize = texelSize * width;
5206 : // There are checks above to ensure that this won't overflow.
5207 0 : size_t dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mPixelStoreUnpackAlignment).value();
5208 :
5209 0 : if (actualSrcFormat == dstFormat &&
5210 : srcPremultiplied == mPixelStorePremultiplyAlpha &&
5211 : srcStride == dstStride &&
5212 0 : !mPixelStoreFlipY)
5213 : {
5214 : // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
5215 0 : gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
5216 : }
5217 : else
5218 : {
5219 0 : nsAutoArrayPtr<PRUint8> convertedData(new PRUint8[bytesNeeded]);
5220 : ConvertImage(width, height, srcStride, dstStride,
5221 : (const PRUint8*)pixels, convertedData,
5222 : actualSrcFormat, srcPremultiplied,
5223 0 : dstFormat, mPixelStorePremultiplyAlpha, texelSize);
5224 :
5225 0 : gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, convertedData);
5226 : }
5227 :
5228 0 : return NS_OK;
5229 : }
5230 :
5231 : NS_IMETHODIMP
5232 0 : WebGLContext::TexSubImage2D_array(WebGLenum target, WebGLint level,
5233 : WebGLint xoffset, WebGLint yoffset,
5234 : WebGLsizei width, WebGLsizei height,
5235 : WebGLenum format, WebGLenum type,
5236 : JSObject *pixels)
5237 : {
5238 0 : if (!IsContextStable())
5239 0 : return NS_OK;
5240 :
5241 0 : if (!pixels)
5242 0 : return ErrorInvalidValue("TexSubImage2D: pixels must not be null!");
5243 :
5244 : return TexSubImage2D_base(target, level, xoffset, yoffset,
5245 : width, height, 0, format, type,
5246 : JS_GetTypedArrayData(pixels), JS_GetTypedArrayByteLength(pixels),
5247 0 : JS_GetTypedArrayType(pixels),
5248 0 : WebGLTexelFormat::Auto, false);
5249 : }
5250 :
5251 : NS_IMETHODIMP
5252 0 : WebGLContext::TexSubImage2D_imageData(WebGLenum target, WebGLint level,
5253 : WebGLint xoffset, WebGLint yoffset,
5254 : WebGLsizei width, WebGLsizei height,
5255 : WebGLenum format, WebGLenum type,
5256 : JSObject *pixels)
5257 : {
5258 0 : if (!IsContextStable())
5259 0 : return NS_OK;
5260 :
5261 0 : if (!pixels)
5262 0 : return ErrorInvalidValue("TexSubImage2D: pixels must not be null!");
5263 :
5264 : return TexSubImage2D_base(target, level, xoffset, yoffset,
5265 : width, height, 4*width, format, type,
5266 : JS_GetTypedArrayData(pixels), JS_GetTypedArrayByteLength(pixels),
5267 : -1,
5268 0 : WebGLTexelFormat::RGBA8, false);
5269 : }
5270 :
5271 : NS_IMETHODIMP
5272 0 : WebGLContext::TexSubImage2D_dom(WebGLenum target, WebGLint level,
5273 : WebGLint xoffset, WebGLint yoffset,
5274 : WebGLenum format, WebGLenum type,
5275 : Element *elt)
5276 : {
5277 0 : if (!IsContextStable())
5278 0 : return NS_OK;
5279 :
5280 0 : nsRefPtr<gfxImageSurface> isurf;
5281 :
5282 : int srcFormat;
5283 0 : nsresult rv = DOMElementToImageSurface(elt, getter_AddRefs(isurf), &srcFormat);
5284 0 : if (NS_FAILED(rv))
5285 0 : return rv;
5286 :
5287 0 : PRUint32 byteLength = isurf->Stride() * isurf->Height();
5288 :
5289 : return TexSubImage2D_base(target, level,
5290 : xoffset, yoffset,
5291 : isurf->Width(), isurf->Height(), isurf->Stride(),
5292 : format, type,
5293 0 : isurf->Data(), byteLength,
5294 : -1,
5295 0 : srcFormat, mPixelStorePremultiplyAlpha);
5296 : }
5297 :
5298 : bool
5299 0 : WebGLContext::LoseContext()
5300 : {
5301 0 : if (!IsContextStable())
5302 0 : return false;
5303 :
5304 0 : mContextLostDueToTest = true;
5305 0 : ForceLoseContext();
5306 :
5307 0 : return true;
5308 : }
5309 :
5310 : bool
5311 0 : WebGLContext::RestoreContext()
5312 : {
5313 0 : if (IsContextStable() || !mAllowRestore) {
5314 0 : return false;
5315 : }
5316 :
5317 0 : ForceRestoreContext();
5318 :
5319 0 : return true;
5320 : }
5321 :
5322 : bool
5323 0 : BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *unitSize)
5324 : {
5325 0 : switch (uType) {
5326 : case LOCAL_GL_INT:
5327 : case LOCAL_GL_INT_VEC2:
5328 : case LOCAL_GL_INT_VEC3:
5329 : case LOCAL_GL_INT_VEC4:
5330 : case LOCAL_GL_SAMPLER_2D:
5331 : case LOCAL_GL_SAMPLER_CUBE:
5332 0 : *baseType = LOCAL_GL_INT;
5333 0 : break;
5334 : case LOCAL_GL_FLOAT:
5335 : case LOCAL_GL_FLOAT_VEC2:
5336 : case LOCAL_GL_FLOAT_VEC3:
5337 : case LOCAL_GL_FLOAT_VEC4:
5338 : case LOCAL_GL_FLOAT_MAT2:
5339 : case LOCAL_GL_FLOAT_MAT3:
5340 : case LOCAL_GL_FLOAT_MAT4:
5341 0 : *baseType = LOCAL_GL_FLOAT;
5342 0 : break;
5343 : case LOCAL_GL_BOOL:
5344 : case LOCAL_GL_BOOL_VEC2:
5345 : case LOCAL_GL_BOOL_VEC3:
5346 : case LOCAL_GL_BOOL_VEC4:
5347 0 : *baseType = LOCAL_GL_BOOL; // pretend these are int
5348 0 : break;
5349 : default:
5350 0 : return false;
5351 : }
5352 :
5353 0 : switch (uType) {
5354 : case LOCAL_GL_INT:
5355 : case LOCAL_GL_FLOAT:
5356 : case LOCAL_GL_BOOL:
5357 : case LOCAL_GL_SAMPLER_2D:
5358 : case LOCAL_GL_SAMPLER_CUBE:
5359 0 : *unitSize = 1;
5360 0 : break;
5361 : case LOCAL_GL_INT_VEC2:
5362 : case LOCAL_GL_FLOAT_VEC2:
5363 : case LOCAL_GL_BOOL_VEC2:
5364 0 : *unitSize = 2;
5365 0 : break;
5366 : case LOCAL_GL_INT_VEC3:
5367 : case LOCAL_GL_FLOAT_VEC3:
5368 : case LOCAL_GL_BOOL_VEC3:
5369 0 : *unitSize = 3;
5370 0 : break;
5371 : case LOCAL_GL_INT_VEC4:
5372 : case LOCAL_GL_FLOAT_VEC4:
5373 : case LOCAL_GL_BOOL_VEC4:
5374 0 : *unitSize = 4;
5375 0 : break;
5376 : case LOCAL_GL_FLOAT_MAT2:
5377 0 : *unitSize = 4;
5378 0 : break;
5379 : case LOCAL_GL_FLOAT_MAT3:
5380 0 : *unitSize = 9;
5381 0 : break;
5382 : case LOCAL_GL_FLOAT_MAT4:
5383 0 : *unitSize = 16;
5384 0 : break;
5385 : default:
5386 0 : return false;
5387 : }
5388 :
5389 0 : return true;
5390 : }
5391 :
5392 :
5393 0 : int mozilla::GetWebGLTexelFormat(GLenum format, GLenum type)
5394 : {
5395 0 : if (type == LOCAL_GL_UNSIGNED_BYTE) {
5396 0 : switch (format) {
5397 : case LOCAL_GL_RGBA:
5398 0 : return WebGLTexelFormat::RGBA8;
5399 : case LOCAL_GL_RGB:
5400 0 : return WebGLTexelFormat::RGB8;
5401 : case LOCAL_GL_ALPHA:
5402 0 : return WebGLTexelFormat::A8;
5403 : case LOCAL_GL_LUMINANCE:
5404 0 : return WebGLTexelFormat::R8;
5405 : case LOCAL_GL_LUMINANCE_ALPHA:
5406 0 : return WebGLTexelFormat::RA8;
5407 : default:
5408 0 : NS_ASSERTION(false, "Coding mistake?! Should never reach this point.");
5409 0 : return WebGLTexelFormat::Generic;
5410 : }
5411 0 : } else if (type == LOCAL_GL_FLOAT) {
5412 : // OES_texture_float
5413 0 : switch (format) {
5414 : case LOCAL_GL_RGBA:
5415 0 : return WebGLTexelFormat::RGBA32F;
5416 : case LOCAL_GL_RGB:
5417 0 : return WebGLTexelFormat::RGB32F;
5418 : case LOCAL_GL_ALPHA:
5419 0 : return WebGLTexelFormat::A32F;
5420 : case LOCAL_GL_LUMINANCE:
5421 0 : return WebGLTexelFormat::R32F;
5422 : case LOCAL_GL_LUMINANCE_ALPHA:
5423 0 : return WebGLTexelFormat::RA32F;
5424 : default:
5425 0 : NS_ASSERTION(false, "Coding mistake?! Should never reach this point.");
5426 0 : return WebGLTexelFormat::Generic;
5427 : }
5428 : } else {
5429 0 : switch (type) {
5430 : case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
5431 0 : return WebGLTexelFormat::RGBA4444;
5432 : case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
5433 0 : return WebGLTexelFormat::RGBA5551;
5434 : case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
5435 0 : return WebGLTexelFormat::RGB565;
5436 : default:
5437 0 : NS_ASSERTION(false, "Coding mistake?! Should never reach this point.");
5438 0 : return WebGLTexelFormat::Generic;
5439 : }
5440 : }
5441 : }
5442 :
5443 : WebGLenum
5444 0 : InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2)
5445 : {
5446 : // ES2 requires that format == internalformat; floating-point is
5447 : // indicated purely by the type that's loaded. For desktop GL, we
5448 : // have to specify a floating point internal format.
5449 0 : if (isGLES2)
5450 0 : return format;
5451 :
5452 0 : switch (type) {
5453 : case LOCAL_GL_UNSIGNED_BYTE:
5454 : case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
5455 : case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
5456 : case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
5457 0 : return format;
5458 :
5459 : case LOCAL_GL_FLOAT:
5460 0 : switch (format) {
5461 : case LOCAL_GL_RGBA:
5462 0 : return LOCAL_GL_RGBA32F_ARB;
5463 : case LOCAL_GL_RGB:
5464 0 : return LOCAL_GL_RGB32F_ARB;
5465 : case LOCAL_GL_ALPHA:
5466 0 : return LOCAL_GL_ALPHA32F_ARB;
5467 : case LOCAL_GL_LUMINANCE:
5468 0 : return LOCAL_GL_LUMINANCE32F_ARB;
5469 : case LOCAL_GL_LUMINANCE_ALPHA:
5470 0 : return LOCAL_GL_LUMINANCE_ALPHA32F_ARB;
5471 : }
5472 0 : break;
5473 :
5474 : default:
5475 0 : break;
5476 : }
5477 :
5478 0 : NS_ASSERTION(false, "Coding mistake -- bad format/type passed?");
5479 0 : return 0;
5480 : }
5481 :
|