LCOV - code coverage report
Current view: top level - dom/canvas - WebGLContextGL.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1118 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 100 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "WebGLContext.h"
       7             : #include "WebGL2Context.h"
       8             : 
       9             : #include "WebGLActiveInfo.h"
      10             : #include "WebGLContextUtils.h"
      11             : #include "WebGLBuffer.h"
      12             : #include "WebGLVertexAttribData.h"
      13             : #include "WebGLShader.h"
      14             : #include "WebGLProgram.h"
      15             : #include "WebGLUniformLocation.h"
      16             : #include "WebGLFormats.h"
      17             : #include "WebGLFramebuffer.h"
      18             : #include "WebGLRenderbuffer.h"
      19             : #include "WebGLShaderPrecisionFormat.h"
      20             : #include "WebGLTexture.h"
      21             : #include "WebGLExtensions.h"
      22             : #include "WebGLVertexArray.h"
      23             : 
      24             : #include "nsDebug.h"
      25             : #include "nsReadableUtils.h"
      26             : #include "nsString.h"
      27             : 
      28             : #include "gfxContext.h"
      29             : #include "gfxPlatform.h"
      30             : #include "GLContext.h"
      31             : 
      32             : #include "nsContentUtils.h"
      33             : #include "nsError.h"
      34             : #include "nsLayoutUtils.h"
      35             : 
      36             : #include "CanvasUtils.h"
      37             : #include "gfxUtils.h"
      38             : 
      39             : #include "jsfriendapi.h"
      40             : 
      41             : #include "WebGLTexelConversions.h"
      42             : #include "WebGLValidateStrings.h"
      43             : #include <algorithm>
      44             : 
      45             : // needed to check if current OS is lower than 10.7
      46             : #if defined(MOZ_WIDGET_COCOA)
      47             : #include "nsCocoaFeatures.h"
      48             : #endif
      49             : 
      50             : #include "mozilla/DebugOnly.h"
      51             : #include "mozilla/dom/BindingUtils.h"
      52             : #include "mozilla/dom/ImageData.h"
      53             : #include "mozilla/dom/ToJSValue.h"
      54             : #include "mozilla/EndianUtils.h"
      55             : #include "mozilla/RefPtr.h"
      56             : #include "mozilla/UniquePtrExtensions.h"
      57             : 
      58             : namespace mozilla {
      59             : 
      60             : bool
      61           0 : WebGLContext::ValidateObject(const char* funcName, const WebGLProgram& object)
      62             : {
      63           0 :     return ValidateObject(funcName, object, true);
      64             : }
      65             : 
      66             : bool
      67           0 : WebGLContext::ValidateObject(const char* funcName, const WebGLShader& object)
      68             : {
      69           0 :     return ValidateObject(funcName, object, true);
      70             : }
      71             : 
      72             : using namespace mozilla::dom;
      73             : using namespace mozilla::gfx;
      74             : using namespace mozilla::gl;
      75             : 
      76             : //
      77             : //  WebGL API
      78             : //
      79             : 
      80             : void
      81           0 : WebGLContext::ActiveTexture(GLenum texture)
      82             : {
      83           0 :     if (IsContextLost())
      84           0 :         return;
      85             : 
      86           0 :     if (texture < LOCAL_GL_TEXTURE0 ||
      87           0 :         texture >= LOCAL_GL_TEXTURE0 + uint32_t(mGLMaxTextureUnits))
      88             :     {
      89           0 :         return ErrorInvalidEnum(
      90             :             "ActiveTexture: texture unit %d out of range. "
      91             :             "Accepted values range from TEXTURE0 to TEXTURE0 + %d. "
      92             :             "Notice that TEXTURE0 != 0.",
      93           0 :             texture, mGLMaxTextureUnits);
      94             :     }
      95             : 
      96           0 :     MakeContextCurrent();
      97           0 :     mActiveTexture = texture - LOCAL_GL_TEXTURE0;
      98           0 :     gl->fActiveTexture(texture);
      99             : }
     100             : 
     101             : void
     102           0 : WebGLContext::AttachShader(WebGLProgram& program, WebGLShader& shader)
     103             : {
     104           0 :     if (IsContextLost())
     105           0 :         return;
     106             : 
     107           0 :     if (!ValidateObject("attachShader: program", program) ||
     108           0 :         !ValidateObject("attachShader: shader", shader))
     109             :     {
     110           0 :         return;
     111             :     }
     112             : 
     113           0 :     program.AttachShader(&shader);
     114             : }
     115             : 
     116             : void
     117           0 : WebGLContext::BindAttribLocation(WebGLProgram& prog, GLuint location,
     118             :                                  const nsAString& name)
     119             : {
     120           0 :     if (IsContextLost())
     121           0 :         return;
     122             : 
     123           0 :     if (!ValidateObject("bindAttribLocation: program", prog))
     124           0 :         return;
     125             : 
     126           0 :     prog.BindAttribLocation(location, name);
     127             : }
     128             : 
     129             : void
     130           0 : WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer* wfb)
     131             : {
     132           0 :     if (IsContextLost())
     133           0 :         return;
     134             : 
     135           0 :     if (!ValidateFramebufferTarget(target, "bindFramebuffer"))
     136           0 :         return;
     137             : 
     138           0 :     if (wfb && !ValidateObject("bindFramebuffer", *wfb))
     139           0 :         return;
     140             : 
     141           0 :     MakeContextCurrent();
     142             : 
     143           0 :     if (!wfb) {
     144           0 :         gl->fBindFramebuffer(target, 0);
     145             :     } else {
     146           0 :         GLuint framebuffername = wfb->mGLName;
     147           0 :         gl->fBindFramebuffer(target, framebuffername);
     148             : #ifdef ANDROID
     149             :         wfb->mIsFB = true;
     150             : #endif
     151             :     }
     152             : 
     153           0 :     switch (target) {
     154             :     case LOCAL_GL_FRAMEBUFFER:
     155           0 :         mBoundDrawFramebuffer = wfb;
     156           0 :         mBoundReadFramebuffer = wfb;
     157           0 :         break;
     158             :     case LOCAL_GL_DRAW_FRAMEBUFFER:
     159           0 :         mBoundDrawFramebuffer = wfb;
     160           0 :         break;
     161             :     case LOCAL_GL_READ_FRAMEBUFFER:
     162           0 :         mBoundReadFramebuffer = wfb;
     163           0 :         break;
     164             :     default:
     165           0 :         break;
     166             :     }
     167             : }
     168             : 
     169             : void
     170           0 : WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer* wrb)
     171             : {
     172           0 :     if (IsContextLost())
     173           0 :         return;
     174             : 
     175           0 :     if (target != LOCAL_GL_RENDERBUFFER)
     176           0 :         return ErrorInvalidEnumInfo("bindRenderbuffer: target", target);
     177             : 
     178           0 :     if (wrb && !ValidateObject("bindRenderbuffer", *wrb))
     179           0 :         return;
     180             : 
     181             :     // Usually, we would now call into glBindRenderbuffer. However, since we have to
     182             :     // potentially emulate packed-depth-stencil, there's not a specific renderbuffer that
     183             :     // we know we should bind here.
     184             :     // Instead, we do all renderbuffer binding lazily.
     185             : 
     186           0 :     if (wrb) {
     187           0 :         wrb->mHasBeenBound = true;
     188             :     }
     189             : 
     190           0 :     mBoundRenderbuffer = wrb;
     191             : }
     192             : 
     193           0 : void WebGLContext::BlendEquation(GLenum mode)
     194             : {
     195           0 :     if (IsContextLost())
     196           0 :         return;
     197             : 
     198           0 :     if (!ValidateBlendEquationEnum(mode, "blendEquation: mode"))
     199           0 :         return;
     200             : 
     201           0 :     MakeContextCurrent();
     202           0 :     gl->fBlendEquation(mode);
     203             : }
     204             : 
     205           0 : void WebGLContext::BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
     206             : {
     207           0 :     if (IsContextLost())
     208           0 :         return;
     209             : 
     210           0 :     if (!ValidateBlendEquationEnum(modeRGB, "blendEquationSeparate: modeRGB") ||
     211           0 :         !ValidateBlendEquationEnum(modeAlpha, "blendEquationSeparate: modeAlpha"))
     212           0 :         return;
     213             : 
     214           0 :     MakeContextCurrent();
     215           0 :     gl->fBlendEquationSeparate(modeRGB, modeAlpha);
     216             : }
     217             : 
     218           0 : void WebGLContext::BlendFunc(GLenum sfactor, GLenum dfactor)
     219             : {
     220           0 :     if (IsContextLost())
     221           0 :         return;
     222             : 
     223           0 :     if (!ValidateBlendFuncSrcEnum(sfactor, "blendFunc: sfactor") ||
     224           0 :         !ValidateBlendFuncDstEnum(dfactor, "blendFunc: dfactor"))
     225           0 :         return;
     226             : 
     227           0 :     if (!ValidateBlendFuncEnumsCompatibility(sfactor, dfactor, "blendFuncSeparate: srcRGB and dstRGB"))
     228           0 :         return;
     229             : 
     230           0 :     MakeContextCurrent();
     231           0 :     gl->fBlendFunc(sfactor, dfactor);
     232             : }
     233             : 
     234             : void
     235           0 : WebGLContext::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
     236             :                                 GLenum srcAlpha, GLenum dstAlpha)
     237             : {
     238           0 :     if (IsContextLost())
     239           0 :         return;
     240             : 
     241           0 :     if (!ValidateBlendFuncSrcEnum(srcRGB, "blendFuncSeparate: srcRGB") ||
     242           0 :         !ValidateBlendFuncSrcEnum(srcAlpha, "blendFuncSeparate: srcAlpha") ||
     243           0 :         !ValidateBlendFuncDstEnum(dstRGB, "blendFuncSeparate: dstRGB") ||
     244           0 :         !ValidateBlendFuncDstEnum(dstAlpha, "blendFuncSeparate: dstAlpha"))
     245           0 :         return;
     246             : 
     247             :     // note that we only check compatibity for the RGB enums, no need to for the Alpha enums, see
     248             :     // "Section 6.8 forgetting to mention alpha factors?" thread on the public_webgl mailing list
     249           0 :     if (!ValidateBlendFuncEnumsCompatibility(srcRGB, dstRGB, "blendFuncSeparate: srcRGB and dstRGB"))
     250           0 :         return;
     251             : 
     252           0 :     MakeContextCurrent();
     253           0 :     gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
     254             : }
     255             : 
     256             : GLenum
     257           0 : WebGLContext::CheckFramebufferStatus(GLenum target)
     258             : {
     259           0 :     const char funcName[] = "checkFramebufferStatus";
     260           0 :     if (IsContextLost())
     261           0 :         return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
     262             : 
     263           0 :     if (!ValidateFramebufferTarget(target, funcName))
     264           0 :         return 0;
     265             : 
     266             :     WebGLFramebuffer* fb;
     267           0 :     switch (target) {
     268             :     case LOCAL_GL_FRAMEBUFFER:
     269             :     case LOCAL_GL_DRAW_FRAMEBUFFER:
     270           0 :         fb = mBoundDrawFramebuffer;
     271           0 :         break;
     272             : 
     273             :     case LOCAL_GL_READ_FRAMEBUFFER:
     274           0 :         fb = mBoundReadFramebuffer;
     275           0 :         break;
     276             : 
     277             :     default:
     278           0 :         MOZ_CRASH("GFX: Bad target.");
     279             :     }
     280             : 
     281           0 :     if (!fb)
     282           0 :         return LOCAL_GL_FRAMEBUFFER_COMPLETE;
     283             : 
     284           0 :     return fb->CheckFramebufferStatus(funcName).get();
     285             : }
     286             : 
     287             : already_AddRefed<WebGLProgram>
     288           0 : WebGLContext::CreateProgram()
     289             : {
     290           0 :     if (IsContextLost())
     291           0 :         return nullptr;
     292           0 :     RefPtr<WebGLProgram> globj = new WebGLProgram(this);
     293           0 :     return globj.forget();
     294             : }
     295             : 
     296             : already_AddRefed<WebGLShader>
     297           0 : WebGLContext::CreateShader(GLenum type)
     298             : {
     299           0 :     if (IsContextLost())
     300           0 :         return nullptr;
     301             : 
     302           0 :     if (type != LOCAL_GL_VERTEX_SHADER &&
     303             :         type != LOCAL_GL_FRAGMENT_SHADER)
     304             :     {
     305           0 :         ErrorInvalidEnumInfo("createShader: type", type);
     306           0 :         return nullptr;
     307             :     }
     308             : 
     309           0 :     RefPtr<WebGLShader> shader = new WebGLShader(this, type);
     310           0 :     return shader.forget();
     311             : }
     312             : 
     313             : void
     314           0 : WebGLContext::CullFace(GLenum face)
     315             : {
     316           0 :     if (IsContextLost())
     317           0 :         return;
     318             : 
     319           0 :     if (!ValidateFaceEnum(face, "cullFace"))
     320           0 :         return;
     321             : 
     322           0 :     MakeContextCurrent();
     323           0 :     gl->fCullFace(face);
     324             : }
     325             : 
     326             : void
     327           0 : WebGLContext::DeleteFramebuffer(WebGLFramebuffer* fbuf)
     328             : {
     329           0 :     if (!ValidateDeleteObject("deleteFramebuffer", fbuf))
     330           0 :         return;
     331             : 
     332           0 :     fbuf->RequestDelete();
     333             : 
     334           0 :     if (mBoundReadFramebuffer == mBoundDrawFramebuffer) {
     335           0 :         if (mBoundDrawFramebuffer == fbuf) {
     336             :             BindFramebuffer(LOCAL_GL_FRAMEBUFFER,
     337           0 :                             static_cast<WebGLFramebuffer*>(nullptr));
     338             :         }
     339           0 :     } else if (mBoundDrawFramebuffer == fbuf) {
     340             :         BindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER,
     341           0 :                         static_cast<WebGLFramebuffer*>(nullptr));
     342           0 :     } else if (mBoundReadFramebuffer == fbuf) {
     343             :         BindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
     344           0 :                         static_cast<WebGLFramebuffer*>(nullptr));
     345             :     }
     346             : }
     347             : 
     348             : void
     349           0 : WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer* rbuf)
     350             : {
     351           0 :     const char funcName[] = "deleteRenderbuffer";
     352           0 :     if (!ValidateDeleteObject(funcName, rbuf))
     353           0 :         return;
     354             : 
     355           0 :     if (mBoundDrawFramebuffer)
     356           0 :         mBoundDrawFramebuffer->DetachRenderbuffer(funcName, rbuf);
     357             : 
     358           0 :     if (mBoundReadFramebuffer)
     359           0 :         mBoundReadFramebuffer->DetachRenderbuffer(funcName, rbuf);
     360             : 
     361           0 :     rbuf->InvalidateStatusOfAttachedFBs(funcName);
     362             : 
     363           0 :     if (mBoundRenderbuffer == rbuf)
     364           0 :         BindRenderbuffer(LOCAL_GL_RENDERBUFFER, nullptr);
     365             : 
     366           0 :     rbuf->RequestDelete();
     367             : }
     368             : 
     369             : void
     370           0 : WebGLContext::DeleteTexture(WebGLTexture* tex)
     371             : {
     372           0 :     const char funcName[] = "deleteTexture";
     373           0 :     if (!ValidateDeleteObject(funcName, tex))
     374           0 :         return;
     375             : 
     376           0 :     if (mBoundDrawFramebuffer)
     377           0 :         mBoundDrawFramebuffer->DetachTexture(funcName, tex);
     378             : 
     379           0 :     if (mBoundReadFramebuffer)
     380           0 :         mBoundReadFramebuffer->DetachTexture(funcName, tex);
     381             : 
     382           0 :     GLuint activeTexture = mActiveTexture;
     383           0 :     for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
     384           0 :         if (mBound2DTextures[i] == tex ||
     385           0 :             mBoundCubeMapTextures[i] == tex ||
     386           0 :             mBound3DTextures[i] == tex ||
     387           0 :             mBound2DArrayTextures[i] == tex)
     388             :         {
     389           0 :             ActiveTexture(LOCAL_GL_TEXTURE0 + i);
     390           0 :             BindTexture(tex->Target().get(), nullptr);
     391             :         }
     392             :     }
     393           0 :     ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture);
     394             : 
     395           0 :     tex->RequestDelete();
     396             : }
     397             : 
     398             : void
     399           0 : WebGLContext::DeleteProgram(WebGLProgram* prog)
     400             : {
     401           0 :     if (!ValidateDeleteObject("deleteProgram", prog))
     402           0 :         return;
     403             : 
     404           0 :     prog->RequestDelete();
     405             : }
     406             : 
     407             : void
     408           0 : WebGLContext::DeleteShader(WebGLShader* shader)
     409             : {
     410           0 :     if (!ValidateDeleteObject("deleteShader", shader))
     411           0 :         return;
     412             : 
     413           0 :     shader->RequestDelete();
     414             : }
     415             : 
     416             : void
     417           0 : WebGLContext::DetachShader(WebGLProgram& program, const WebGLShader& shader)
     418             : {
     419           0 :     if (IsContextLost())
     420           0 :         return;
     421             : 
     422             :     // It's valid to attempt to detach a deleted shader, since it's still a
     423             :     // shader.
     424           0 :     if (!ValidateObject("detachShader: program", program) ||
     425           0 :         !ValidateObjectAllowDeleted("detachShader: shader", shader))
     426             :     {
     427           0 :         return;
     428             :     }
     429             : 
     430           0 :     program.DetachShader(&shader);
     431             : }
     432             : 
     433             : void
     434           0 : WebGLContext::DepthFunc(GLenum func)
     435             : {
     436           0 :     if (IsContextLost())
     437           0 :         return;
     438             : 
     439           0 :     if (!ValidateComparisonEnum(func, "depthFunc"))
     440           0 :         return;
     441             : 
     442           0 :     MakeContextCurrent();
     443           0 :     gl->fDepthFunc(func);
     444             : }
     445             : 
     446             : void
     447           0 : WebGLContext::DepthRange(GLfloat zNear, GLfloat zFar)
     448             : {
     449           0 :     if (IsContextLost())
     450           0 :         return;
     451             : 
     452           0 :     if (zNear > zFar)
     453           0 :         return ErrorInvalidOperation("depthRange: the near value is greater than the far value!");
     454             : 
     455           0 :     MakeContextCurrent();
     456           0 :     gl->fDepthRange(zNear, zFar);
     457             : }
     458             : 
     459             : void
     460           0 : WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment,
     461             :                                       GLenum rbtarget, WebGLRenderbuffer* wrb)
     462             : {
     463           0 :     const char funcName[] = "framebufferRenderbuffer";
     464           0 :     if (IsContextLost())
     465           0 :         return;
     466             : 
     467           0 :     if (!ValidateFramebufferTarget(target, funcName))
     468           0 :         return;
     469             : 
     470             :     WebGLFramebuffer* fb;
     471           0 :     switch (target) {
     472             :     case LOCAL_GL_FRAMEBUFFER:
     473             :     case LOCAL_GL_DRAW_FRAMEBUFFER:
     474           0 :         fb = mBoundDrawFramebuffer;
     475           0 :         break;
     476             : 
     477             :     case LOCAL_GL_READ_FRAMEBUFFER:
     478           0 :         fb = mBoundReadFramebuffer;
     479           0 :         break;
     480             : 
     481             :     default:
     482           0 :         MOZ_CRASH("GFX: Bad target.");
     483             :     }
     484             : 
     485           0 :     if (!fb)
     486           0 :         return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
     487             : 
     488           0 :     fb->FramebufferRenderbuffer(funcName, attachment, rbtarget, wrb);
     489             : }
     490             : 
     491             : void
     492           0 : WebGLContext::FramebufferTexture2D(GLenum target,
     493             :                                    GLenum attachment,
     494             :                                    GLenum textarget,
     495             :                                    WebGLTexture* tobj,
     496             :                                    GLint level)
     497             : {
     498           0 :     const char funcName[] = "framebufferTexture2D";
     499           0 :     if (IsContextLost())
     500           0 :         return;
     501             : 
     502           0 :     if (!ValidateFramebufferTarget(target, funcName))
     503           0 :         return;
     504             : 
     505             :     WebGLFramebuffer* fb;
     506           0 :     switch (target) {
     507             :     case LOCAL_GL_FRAMEBUFFER:
     508             :     case LOCAL_GL_DRAW_FRAMEBUFFER:
     509           0 :         fb = mBoundDrawFramebuffer;
     510           0 :         break;
     511             : 
     512             :     case LOCAL_GL_READ_FRAMEBUFFER:
     513           0 :         fb = mBoundReadFramebuffer;
     514           0 :         break;
     515             : 
     516             :     default:
     517           0 :         MOZ_CRASH("GFX: Bad target.");
     518             :     }
     519             : 
     520           0 :     if (!fb)
     521           0 :         return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
     522             : 
     523           0 :     fb->FramebufferTexture2D(funcName, attachment, textarget, tobj, level);
     524             : }
     525             : 
     526             : void
     527           0 : WebGLContext::FrontFace(GLenum mode)
     528             : {
     529           0 :     if (IsContextLost())
     530           0 :         return;
     531             : 
     532           0 :     switch (mode) {
     533             :         case LOCAL_GL_CW:
     534             :         case LOCAL_GL_CCW:
     535           0 :             break;
     536             :         default:
     537           0 :             return ErrorInvalidEnumInfo("frontFace: mode", mode);
     538             :     }
     539             : 
     540           0 :     MakeContextCurrent();
     541           0 :     gl->fFrontFace(mode);
     542             : }
     543             : 
     544             : already_AddRefed<WebGLActiveInfo>
     545           0 : WebGLContext::GetActiveAttrib(const WebGLProgram& prog, GLuint index)
     546             : {
     547           0 :     if (IsContextLost())
     548           0 :         return nullptr;
     549             : 
     550           0 :     if (!ValidateObject("getActiveAttrib: program", prog))
     551           0 :         return nullptr;
     552             : 
     553           0 :     return prog.GetActiveAttrib(index);
     554             : }
     555             : 
     556             : already_AddRefed<WebGLActiveInfo>
     557           0 : WebGLContext::GetActiveUniform(const WebGLProgram& prog, GLuint index)
     558             : {
     559           0 :     if (IsContextLost())
     560           0 :         return nullptr;
     561             : 
     562           0 :     if (!ValidateObject("getActiveUniform: program", prog))
     563           0 :         return nullptr;
     564             : 
     565           0 :     return prog.GetActiveUniform(index);
     566             : }
     567             : 
     568             : void
     569           0 : WebGLContext::GetAttachedShaders(const WebGLProgram& prog,
     570             :                                  dom::Nullable<nsTArray<RefPtr<WebGLShader>>>& retval)
     571             : {
     572           0 :     retval.SetNull();
     573           0 :     if (IsContextLost())
     574           0 :         return;
     575             : 
     576           0 :     if (!ValidateObject("getAttachedShaders", prog))
     577           0 :         return;
     578             : 
     579           0 :     prog.GetAttachedShaders(&retval.SetValue());
     580             : }
     581             : 
     582             : GLint
     583           0 : WebGLContext::GetAttribLocation(const WebGLProgram& prog, const nsAString& name)
     584             : {
     585           0 :     if (IsContextLost())
     586           0 :         return -1;
     587             : 
     588           0 :     if (!ValidateObject("getAttribLocation: program", prog))
     589           0 :         return -1;
     590             : 
     591           0 :     return prog.GetAttribLocation(name);
     592             : }
     593             : 
     594             : JS::Value
     595           0 : WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
     596             : {
     597           0 :     const char funcName[] = "getBufferParameter";
     598           0 :     if (IsContextLost())
     599           0 :         return JS::NullValue();
     600             : 
     601           0 :     const auto& slot = ValidateBufferSlot(funcName, target);
     602           0 :     if (!slot)
     603           0 :         return JS::NullValue();
     604           0 :     const auto& buffer = *slot;
     605             : 
     606           0 :     if (!buffer) {
     607           0 :         ErrorInvalidOperation("%s: Buffer for `target` is null.", funcName);
     608           0 :         return JS::NullValue();
     609             :     }
     610             : 
     611           0 :     switch (pname) {
     612             :     case LOCAL_GL_BUFFER_SIZE:
     613           0 :         return JS::NumberValue(buffer->ByteLength());
     614             : 
     615             :     case LOCAL_GL_BUFFER_USAGE:
     616           0 :         return JS::NumberValue(buffer->Usage());
     617             : 
     618             :     default:
     619           0 :         ErrorInvalidEnumInfo("getBufferParameter: parameter", pname);
     620           0 :         return JS::NullValue();
     621             :     }
     622             : }
     623             : 
     624             : JS::Value
     625           0 : WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx,
     626             :                                                 GLenum target,
     627             :                                                 GLenum attachment,
     628             :                                                 GLenum pname,
     629             :                                                 ErrorResult& rv)
     630             : {
     631           0 :     const char funcName[] = "getFramebufferAttachmentParameter";
     632             : 
     633           0 :     if (IsContextLost())
     634           0 :         return JS::NullValue();
     635             : 
     636           0 :     if (!ValidateFramebufferTarget(target, funcName))
     637           0 :         return JS::NullValue();
     638             : 
     639             :     WebGLFramebuffer* fb;
     640           0 :     switch (target) {
     641             :     case LOCAL_GL_FRAMEBUFFER:
     642             :     case LOCAL_GL_DRAW_FRAMEBUFFER:
     643           0 :         fb = mBoundDrawFramebuffer;
     644           0 :         break;
     645             : 
     646             :     case LOCAL_GL_READ_FRAMEBUFFER:
     647           0 :         fb = mBoundReadFramebuffer;
     648           0 :         break;
     649             : 
     650             :     default:
     651           0 :         MOZ_CRASH("GFX: Bad target.");
     652             :     }
     653             : 
     654           0 :     MakeContextCurrent();
     655             : 
     656           0 :     if (fb)
     657           0 :         return fb->GetAttachmentParameter(funcName, cx, target, attachment, pname, &rv);
     658             : 
     659             :     ////////////////////////////////////
     660             : 
     661           0 :     if (!IsWebGL2()) {
     662             :         ErrorInvalidOperation("%s: Querying against the default framebuffer is not"
     663             :                               " allowed in WebGL 1.",
     664           0 :                               funcName);
     665           0 :         return JS::NullValue();
     666             :     }
     667             : 
     668           0 :     switch (attachment) {
     669             :     case LOCAL_GL_BACK:
     670             :     case LOCAL_GL_DEPTH:
     671             :     case LOCAL_GL_STENCIL:
     672           0 :         break;
     673             : 
     674             :     default:
     675             :         ErrorInvalidEnum("%s: For the default framebuffer, can only query COLOR, DEPTH,"
     676             :                          " or STENCIL.",
     677           0 :                          funcName);
     678           0 :         return JS::NullValue();
     679             :     }
     680             : 
     681           0 :     switch (pname) {
     682             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
     683           0 :         switch (attachment) {
     684             :         case LOCAL_GL_BACK:
     685           0 :             break;
     686             :         case LOCAL_GL_DEPTH:
     687           0 :             if (!mOptions.depth) {
     688           0 :               return JS::Int32Value(LOCAL_GL_NONE);
     689             :             }
     690           0 :             break;
     691             :         case LOCAL_GL_STENCIL:
     692           0 :             if (!mOptions.stencil) {
     693           0 :               return JS::Int32Value(LOCAL_GL_NONE);
     694             :             }
     695           0 :             break;
     696             :         default:
     697             :             ErrorInvalidEnum("%s: With the default framebuffer, can only query COLOR, DEPTH,"
     698             :                              " or STENCIL for GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE",
     699           0 :                              funcName);
     700           0 :             return JS::NullValue();
     701             :         }
     702           0 :         return JS::Int32Value(LOCAL_GL_FRAMEBUFFER_DEFAULT);
     703             : 
     704             :     ////////////////
     705             : 
     706             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
     707             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
     708             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
     709           0 :         if (attachment == LOCAL_GL_BACK)
     710           0 :             return JS::NumberValue(8);
     711           0 :         return JS::NumberValue(0);
     712             : 
     713             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
     714           0 :         if (attachment == LOCAL_GL_BACK) {
     715           0 :             if (mOptions.alpha) {
     716           0 :                 return JS::NumberValue(8);
     717             :             }
     718           0 :             ErrorInvalidOperation("The default framebuffer doesn't contain an alpha buffer");
     719           0 :             return JS::NullValue();
     720             :         }
     721           0 :         return JS::NumberValue(0);
     722             : 
     723             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
     724           0 :         if (attachment == LOCAL_GL_DEPTH) {
     725           0 :             if (mOptions.depth) {
     726           0 :                 return JS::NumberValue(24);
     727             :             }
     728           0 :             ErrorInvalidOperation("The default framebuffer doesn't contain an depth buffer");
     729           0 :             return JS::NullValue();
     730             :         }
     731           0 :         return JS::NumberValue(0);
     732             : 
     733             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
     734           0 :         if (attachment == LOCAL_GL_STENCIL) {
     735           0 :             if (mOptions.stencil) {
     736           0 :                 return JS::NumberValue(8);
     737             :             }
     738           0 :             ErrorInvalidOperation("The default framebuffer doesn't contain an stencil buffer");
     739           0 :             return JS::NullValue();
     740             :         }
     741           0 :         return JS::NumberValue(0);
     742             : 
     743             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
     744           0 :         if (attachment == LOCAL_GL_STENCIL) {
     745           0 :             if (mOptions.stencil) {
     746           0 :                 return JS::NumberValue(LOCAL_GL_UNSIGNED_INT);
     747             :             }
     748           0 :             ErrorInvalidOperation("The default framebuffer doesn't contain an stencil buffer");
     749           0 :         } else if (attachment == LOCAL_GL_DEPTH) {
     750           0 :             if (mOptions.depth) {
     751           0 :                 return JS::NumberValue(LOCAL_GL_UNSIGNED_NORMALIZED);
     752             :             }
     753           0 :             ErrorInvalidOperation("The default framebuffer doesn't contain an depth buffer");
     754             :         } else { // LOCAL_GL_BACK
     755           0 :             return JS::NumberValue(LOCAL_GL_UNSIGNED_NORMALIZED);
     756             :         }
     757           0 :         return JS::NullValue();
     758             : 
     759             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
     760           0 :         if (attachment == LOCAL_GL_STENCIL) {
     761           0 :             if (!mOptions.stencil) {
     762           0 :                 ErrorInvalidOperation("The default framebuffer doesn't contain an stencil buffer");
     763           0 :                 return JS::NullValue();
     764             :             }
     765           0 :         } else if (attachment == LOCAL_GL_DEPTH) {
     766           0 :             if (!mOptions.depth) {
     767           0 :                 ErrorInvalidOperation("The default framebuffer doesn't contain an depth buffer");
     768           0 :                 return JS::NullValue();
     769             :             }
     770             :         }
     771           0 :         return JS::NumberValue(LOCAL_GL_LINEAR);
     772             :     }
     773             : 
     774           0 :     ErrorInvalidEnum("%s: Invalid pname: 0x%04x", funcName, pname);
     775           0 :     return JS::NullValue();
     776             : }
     777             : 
     778             : JS::Value
     779           0 : WebGLContext::GetRenderbufferParameter(GLenum target, GLenum pname)
     780             : {
     781           0 :     if (IsContextLost())
     782           0 :         return JS::NullValue();
     783             : 
     784           0 :     if (target != LOCAL_GL_RENDERBUFFER) {
     785           0 :         ErrorInvalidEnumInfo("getRenderbufferParameter: target", target);
     786           0 :         return JS::NullValue();
     787             :     }
     788             : 
     789           0 :     if (!mBoundRenderbuffer) {
     790           0 :         ErrorInvalidOperation("getRenderbufferParameter: no render buffer is bound");
     791           0 :         return JS::NullValue();
     792             :     }
     793             : 
     794           0 :     MakeContextCurrent();
     795             : 
     796           0 :     switch (pname) {
     797             :     case LOCAL_GL_RENDERBUFFER_SAMPLES:
     798           0 :         if (!IsWebGL2())
     799           0 :             break;
     800             :         MOZ_FALLTHROUGH;
     801             : 
     802             :     case LOCAL_GL_RENDERBUFFER_WIDTH:
     803             :     case LOCAL_GL_RENDERBUFFER_HEIGHT:
     804             :     case LOCAL_GL_RENDERBUFFER_RED_SIZE:
     805             :     case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
     806             :     case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
     807             :     case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
     808             :     case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
     809             :     case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
     810             :     case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
     811             :     {
     812             :         // RB emulation means we have to ask the RB itself.
     813           0 :         GLint i = mBoundRenderbuffer->GetRenderbufferParameter(target, pname);
     814           0 :         return JS::Int32Value(i);
     815             :     }
     816             : 
     817             :     default:
     818           0 :         break;
     819             :     }
     820             : 
     821           0 :     ErrorInvalidEnumInfo("getRenderbufferParameter: parameter", pname);
     822           0 :     return JS::NullValue();
     823             : }
     824             : 
     825             : already_AddRefed<WebGLTexture>
     826           0 : WebGLContext::CreateTexture()
     827             : {
     828           0 :     if (IsContextLost())
     829           0 :         return nullptr;
     830             : 
     831           0 :     GLuint tex = 0;
     832           0 :     MakeContextCurrent();
     833           0 :     gl->fGenTextures(1, &tex);
     834             : 
     835           0 :     RefPtr<WebGLTexture> globj = new WebGLTexture(this, tex);
     836           0 :     return globj.forget();
     837             : }
     838             : 
     839             : static GLenum
     840           0 : GetAndClearError(GLenum* errorVar)
     841             : {
     842           0 :     MOZ_ASSERT(errorVar);
     843           0 :     GLenum ret = *errorVar;
     844           0 :     *errorVar = LOCAL_GL_NO_ERROR;
     845           0 :     return ret;
     846             : }
     847             : 
     848             : GLenum
     849           0 : WebGLContext::GetError()
     850             : {
     851             :     /* WebGL 1.0: Section 5.14.3: Setting and getting state:
     852             :      *   If the context's webgl context lost flag is set, returns
     853             :      *   CONTEXT_LOST_WEBGL the first time this method is called.
     854             :      *   Afterward, returns NO_ERROR until the context has been
     855             :      *   restored.
     856             :      *
     857             :      * WEBGL_lose_context:
     858             :      *   [When this extension is enabled: ] loseContext and
     859             :      *   restoreContext are allowed to generate INVALID_OPERATION errors
     860             :      *   even when the context is lost.
     861             :      */
     862             : 
     863           0 :     if (IsContextLost()) {
     864           0 :         if (mEmitContextLostErrorOnce) {
     865           0 :             mEmitContextLostErrorOnce = false;
     866           0 :             return LOCAL_GL_CONTEXT_LOST_WEBGL;
     867             :         }
     868             :         // Don't return yet, since WEBGL_lose_contexts contradicts the
     869             :         // original spec, and allows error generation while lost.
     870             :     }
     871             : 
     872           0 :     GLenum err = GetAndClearError(&mWebGLError);
     873           0 :     if (err != LOCAL_GL_NO_ERROR)
     874           0 :         return err;
     875             : 
     876           0 :     if (IsContextLost())
     877           0 :         return LOCAL_GL_NO_ERROR;
     878             : 
     879             :     // Either no WebGL-side error, or it's already been cleared.
     880             :     // UnderlyingGL-side errors, now.
     881             : 
     882           0 :     MakeContextCurrent();
     883           0 :     GetAndFlushUnderlyingGLErrors();
     884             : 
     885           0 :     err = GetAndClearError(&mUnderlyingGLError);
     886           0 :     return err;
     887             : }
     888             : 
     889             : JS::Value
     890           0 : WebGLContext::GetProgramParameter(const WebGLProgram& prog, GLenum pname)
     891             : {
     892           0 :     if (IsContextLost())
     893           0 :         return JS::NullValue();
     894             : 
     895           0 :     if (!ValidateObjectAllowDeleted("getProgramParameter: program", prog))
     896           0 :         return JS::NullValue();
     897             : 
     898           0 :     return prog.GetProgramParameter(pname);
     899             : }
     900             : 
     901             : void
     902           0 : WebGLContext::GetProgramInfoLog(const WebGLProgram& prog, nsAString& retval)
     903             : {
     904           0 :     retval.SetIsVoid(true);
     905             : 
     906           0 :     if (IsContextLost())
     907           0 :         return;
     908             : 
     909           0 :     if (!ValidateObject("getProgramInfoLog: program", prog))
     910           0 :         return;
     911             : 
     912           0 :     prog.GetProgramInfoLog(&retval);
     913             : }
     914             : 
     915             : JS::Value
     916           0 : WebGLContext::GetUniform(JSContext* js, const WebGLProgram& prog,
     917             :                          const WebGLUniformLocation& loc)
     918             : {
     919           0 :     if (IsContextLost())
     920           0 :         return JS::NullValue();
     921             : 
     922           0 :     if (!ValidateObject("getUniform: `program`", prog))
     923           0 :         return JS::NullValue();
     924             : 
     925           0 :     if (!ValidateObjectAllowDeleted("getUniform: `location`", loc))
     926           0 :         return JS::NullValue();
     927             : 
     928           0 :     if (!loc.ValidateForProgram(&prog, "getUniform"))
     929           0 :         return JS::NullValue();
     930             : 
     931           0 :     return loc.GetUniform(js);
     932             : }
     933             : 
     934             : already_AddRefed<WebGLUniformLocation>
     935           0 : WebGLContext::GetUniformLocation(const WebGLProgram& prog, const nsAString& name)
     936             : {
     937           0 :     if (IsContextLost())
     938           0 :         return nullptr;
     939             : 
     940           0 :     if (!ValidateObject("getUniformLocation: program", prog))
     941           0 :         return nullptr;
     942             : 
     943           0 :     return prog.GetUniformLocation(name);
     944             : }
     945             : 
     946             : void
     947           0 : WebGLContext::Hint(GLenum target, GLenum mode)
     948             : {
     949           0 :     if (IsContextLost())
     950           0 :         return;
     951             : 
     952           0 :     bool isValid = false;
     953             : 
     954           0 :     switch (target) {
     955             :     case LOCAL_GL_GENERATE_MIPMAP_HINT:
     956           0 :         mGenerateMipmapHint = mode;
     957             : 
     958             :         // Deprecated and removed in desktop GL Core profiles.
     959           0 :         if (gl->IsCoreProfile())
     960           0 :             return;
     961             : 
     962           0 :         isValid = true;
     963           0 :         break;
     964             : 
     965             :     case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
     966           0 :         if (IsWebGL2() ||
     967           0 :             IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
     968             :         {
     969           0 :             isValid = true;
     970             :         }
     971           0 :         break;
     972             :     }
     973             : 
     974           0 :     if (!isValid)
     975           0 :         return ErrorInvalidEnum("hint: invalid hint");
     976             : 
     977           0 :     MakeContextCurrent();
     978           0 :     gl->fHint(target, mode);
     979             : }
     980             : 
     981             : bool
     982           0 : WebGLContext::IsFramebuffer(const WebGLFramebuffer* fb)
     983             : {
     984           0 :     if (!ValidateIsObject("isFramebuffer", fb))
     985           0 :         return false;
     986             : 
     987             : #ifdef ANDROID
     988             :     if (gl->WorkAroundDriverBugs() &&
     989             :         gl->Renderer() == GLRenderer::AndroidEmulator)
     990             :     {
     991             :         return fb->mIsFB;
     992             :     }
     993             : #endif
     994             : 
     995           0 :     MakeContextCurrent();
     996           0 :     return gl->fIsFramebuffer(fb->mGLName);
     997             : }
     998             : 
     999             : bool
    1000           0 : WebGLContext::IsProgram(const WebGLProgram* prog)
    1001             : {
    1002           0 :     if (!ValidateIsObject("isProgram", prog))
    1003           0 :         return false;
    1004             : 
    1005           0 :     return true;
    1006             : }
    1007             : 
    1008             : bool
    1009           0 : WebGLContext::IsRenderbuffer(const WebGLRenderbuffer* rb)
    1010             : {
    1011           0 :     if (!ValidateIsObject("isRenderbuffer", rb))
    1012           0 :         return false;
    1013             : 
    1014           0 :     return rb->mHasBeenBound;
    1015             : }
    1016             : 
    1017             : bool
    1018           0 : WebGLContext::IsShader(const WebGLShader* shader)
    1019             : {
    1020           0 :     if (!ValidateIsObject("isShader", shader))
    1021           0 :         return false;
    1022             : 
    1023           0 :     return true;
    1024             : }
    1025             : 
    1026             : void
    1027           0 : WebGLContext::LinkProgram(WebGLProgram& prog)
    1028             : {
    1029           0 :     if (IsContextLost())
    1030           0 :         return;
    1031             : 
    1032           0 :     if (!ValidateObject("linkProgram", prog))
    1033           0 :         return;
    1034             : 
    1035           0 :     prog.LinkProgram();
    1036             : 
    1037           0 :     if (!prog.IsLinked()) {
    1038             :         // If we failed to link, but `prog == mCurrentProgram`, we are *not* supposed to
    1039             :         // null out mActiveProgramLinkInfo.
    1040           0 :         return;
    1041             :     }
    1042             : 
    1043           0 :     if (&prog == mCurrentProgram) {
    1044           0 :         mActiveProgramLinkInfo = prog.LinkInfo();
    1045             : 
    1046           0 :         if (gl->WorkAroundDriverBugs() &&
    1047           0 :             gl->Vendor() == gl::GLVendor::NVIDIA)
    1048             :         {
    1049           0 :             gl->fUseProgram(prog.mGLName);
    1050             :         }
    1051             :     }
    1052             : }
    1053             : 
    1054             : void
    1055           0 : WebGLContext::PixelStorei(GLenum pname, GLint param)
    1056             : {
    1057           0 :     if (IsContextLost())
    1058           0 :         return;
    1059             : 
    1060           0 :     if (IsWebGL2()) {
    1061           0 :         uint32_t* pValueSlot = nullptr;
    1062           0 :         switch (pname) {
    1063             :         case LOCAL_GL_UNPACK_IMAGE_HEIGHT:
    1064           0 :             pValueSlot = &mPixelStore_UnpackImageHeight;
    1065           0 :             break;
    1066             : 
    1067             :         case LOCAL_GL_UNPACK_SKIP_IMAGES:
    1068           0 :             pValueSlot = &mPixelStore_UnpackSkipImages;
    1069           0 :             break;
    1070             : 
    1071             :         case LOCAL_GL_UNPACK_ROW_LENGTH:
    1072           0 :             pValueSlot = &mPixelStore_UnpackRowLength;
    1073           0 :             break;
    1074             : 
    1075             :         case LOCAL_GL_UNPACK_SKIP_ROWS:
    1076           0 :             pValueSlot = &mPixelStore_UnpackSkipRows;
    1077           0 :             break;
    1078             : 
    1079             :         case LOCAL_GL_UNPACK_SKIP_PIXELS:
    1080           0 :             pValueSlot = &mPixelStore_UnpackSkipPixels;
    1081           0 :             break;
    1082             : 
    1083             :         case LOCAL_GL_PACK_ROW_LENGTH:
    1084           0 :             pValueSlot = &mPixelStore_PackRowLength;
    1085           0 :             break;
    1086             : 
    1087             :         case LOCAL_GL_PACK_SKIP_ROWS:
    1088           0 :             pValueSlot = &mPixelStore_PackSkipRows;
    1089           0 :             break;
    1090             : 
    1091             :         case LOCAL_GL_PACK_SKIP_PIXELS:
    1092           0 :             pValueSlot = &mPixelStore_PackSkipPixels;
    1093           0 :             break;
    1094             :         }
    1095             : 
    1096           0 :         if (pValueSlot) {
    1097           0 :             if (param < 0) {
    1098           0 :                 ErrorInvalidValue("pixelStorei: param must be >= 0.");
    1099           0 :                 return;
    1100             :             }
    1101             : 
    1102           0 :             MakeContextCurrent();
    1103           0 :             gl->fPixelStorei(pname, param);
    1104           0 :             *pValueSlot = param;
    1105           0 :             return;
    1106             :         }
    1107             :     }
    1108             : 
    1109           0 :     switch (pname) {
    1110             :     case UNPACK_FLIP_Y_WEBGL:
    1111           0 :         mPixelStore_FlipY = bool(param);
    1112           0 :         return;
    1113             : 
    1114             :     case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
    1115           0 :         mPixelStore_PremultiplyAlpha = bool(param);
    1116           0 :         return;
    1117             : 
    1118             :     case UNPACK_COLORSPACE_CONVERSION_WEBGL:
    1119           0 :         switch (param) {
    1120             :         case LOCAL_GL_NONE:
    1121             :         case BROWSER_DEFAULT_WEBGL:
    1122           0 :             mPixelStore_ColorspaceConversion = param;
    1123           0 :             return;
    1124             : 
    1125             :         default:
    1126           0 :             ErrorInvalidEnumInfo("pixelStorei: colorspace conversion parameter",
    1127           0 :                                  param);
    1128           0 :             return;
    1129             :         }
    1130             : 
    1131             :     case UNPACK_REQUIRE_FASTPATH:
    1132           0 :         if (IsExtensionEnabled(WebGLExtensionID::MOZ_debug)) {
    1133           0 :             mPixelStore_RequireFastPath = bool(param);
    1134           0 :             return;
    1135             :         }
    1136           0 :         break;
    1137             : 
    1138             :     case LOCAL_GL_PACK_ALIGNMENT:
    1139             :     case LOCAL_GL_UNPACK_ALIGNMENT:
    1140           0 :         switch (param) {
    1141             :         case 1:
    1142             :         case 2:
    1143             :         case 4:
    1144             :         case 8:
    1145           0 :             if (pname == LOCAL_GL_PACK_ALIGNMENT)
    1146           0 :                 mPixelStore_PackAlignment = param;
    1147           0 :             else if (pname == LOCAL_GL_UNPACK_ALIGNMENT)
    1148           0 :                 mPixelStore_UnpackAlignment = param;
    1149             : 
    1150           0 :             MakeContextCurrent();
    1151           0 :             gl->fPixelStorei(pname, param);
    1152           0 :             return;
    1153             : 
    1154             :         default:
    1155           0 :             ErrorInvalidValue("pixelStorei: invalid pack/unpack alignment value");
    1156           0 :             return;
    1157             :         }
    1158             : 
    1159             : 
    1160             : 
    1161             :     default:
    1162           0 :         break;
    1163             :     }
    1164             : 
    1165           0 :     ErrorInvalidEnumInfo("pixelStorei: parameter", pname);
    1166             : }
    1167             : 
    1168             : bool
    1169           0 : WebGLContext::DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat, GLint x, GLint y,
    1170             :                                      GLsizei width, GLsizei height, GLenum format,
    1171             :                                      GLenum destType, void* dest, uint32_t destSize,
    1172             :                                      uint32_t rowStride)
    1173             : {
    1174             :     // On at least Win+NV, we'll get PBO errors if we don't have at least
    1175             :     // `rowStride * height` bytes available to read into.
    1176           0 :     const auto naiveBytesNeeded = CheckedUint32(rowStride) * height;
    1177           0 :     const bool isDangerCloseToEdge = (!naiveBytesNeeded.isValid() ||
    1178           0 :                                       naiveBytesNeeded.value() > destSize);
    1179           0 :     const bool useParanoidHandling = (gl->WorkAroundDriverBugs() &&
    1180           0 :                                       isDangerCloseToEdge &&
    1181           0 :                                       mBoundPixelPackBuffer);
    1182           0 :     if (!useParanoidHandling) {
    1183           0 :         gl->fReadPixels(x, y, width, height, format, destType, dest);
    1184           0 :         return true;
    1185             :     }
    1186             : 
    1187             :     // Read everything but the last row.
    1188           0 :     const auto bodyHeight = height - 1;
    1189           0 :     if (bodyHeight) {
    1190           0 :         gl->fReadPixels(x, y, width, bodyHeight, format, destType, dest);
    1191             :     }
    1192             : 
    1193             :     // Now read the last row.
    1194           0 :     gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 1);
    1195           0 :     gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0);
    1196           0 :     gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0);
    1197             : 
    1198           0 :     const auto tailRowOffset = (char*)dest + rowStride * bodyHeight;
    1199           0 :     gl->fReadPixels(x, y+bodyHeight, width, 1, format, destType, tailRowOffset);
    1200             : 
    1201           0 :     gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mPixelStore_PackAlignment);
    1202           0 :     gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore_PackRowLength);
    1203           0 :     gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows);
    1204           0 :     return true;
    1205             : }
    1206             : 
    1207             : static bool
    1208           0 : GetJSScalarFromGLType(GLenum type, js::Scalar::Type* const out_scalarType)
    1209             : {
    1210           0 :     switch (type) {
    1211             :     case LOCAL_GL_BYTE:
    1212           0 :         *out_scalarType = js::Scalar::Int8;
    1213           0 :         return true;
    1214             : 
    1215             :     case LOCAL_GL_UNSIGNED_BYTE:
    1216           0 :         *out_scalarType = js::Scalar::Uint8;
    1217           0 :         return true;
    1218             : 
    1219             :     case LOCAL_GL_SHORT:
    1220           0 :         *out_scalarType = js::Scalar::Int16;
    1221           0 :         return true;
    1222             : 
    1223             :     case LOCAL_GL_HALF_FLOAT:
    1224             :     case LOCAL_GL_HALF_FLOAT_OES:
    1225             :     case LOCAL_GL_UNSIGNED_SHORT:
    1226             :     case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
    1227             :     case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
    1228             :     case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
    1229           0 :         *out_scalarType = js::Scalar::Uint16;
    1230           0 :         return true;
    1231             : 
    1232             :     case LOCAL_GL_UNSIGNED_INT:
    1233             :     case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
    1234             :     case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
    1235             :     case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
    1236             :     case LOCAL_GL_UNSIGNED_INT_24_8:
    1237           0 :         *out_scalarType = js::Scalar::Uint32;
    1238           0 :         return true;
    1239             :     case LOCAL_GL_INT:
    1240           0 :         *out_scalarType = js::Scalar::Int32;
    1241           0 :         return true;
    1242             : 
    1243             :     case LOCAL_GL_FLOAT:
    1244           0 :         *out_scalarType = js::Scalar::Float32;
    1245           0 :         return true;
    1246             : 
    1247             :     default:
    1248           0 :         return false;
    1249             :     }
    1250             : }
    1251             : 
    1252             : bool
    1253           0 : WebGLContext::ReadPixels_SharedPrecheck(CallerType aCallerType,
    1254             :                                         ErrorResult& out_error)
    1255             : {
    1256           0 :     if (IsContextLost())
    1257           0 :         return false;
    1258             : 
    1259           0 :     if (mCanvasElement &&
    1260           0 :         mCanvasElement->IsWriteOnly() &&
    1261             :         aCallerType != CallerType::System)
    1262             :     {
    1263           0 :         GenerateWarning("readPixels: Not allowed");
    1264           0 :         out_error.Throw(NS_ERROR_DOM_SECURITY_ERR);
    1265           0 :         return false;
    1266             :     }
    1267             : 
    1268           0 :     return true;
    1269             : }
    1270             : 
    1271             : bool
    1272           0 : WebGLContext::ValidatePackSize(const char* funcName, uint32_t width, uint32_t height,
    1273             :                                uint8_t bytesPerPixel, uint32_t* const out_rowStride,
    1274             :                                uint32_t* const out_endOffset)
    1275             : {
    1276           0 :     if (!width || !height) {
    1277           0 :         *out_rowStride = 0;
    1278           0 :         *out_endOffset = 0;
    1279           0 :         return true;
    1280             :     }
    1281             : 
    1282             :     // GLES 3.0.4, p116 (PACK_ functions like UNPACK_)
    1283             : 
    1284           0 :     const auto rowLength = (mPixelStore_PackRowLength ? mPixelStore_PackRowLength
    1285           0 :                                                       : width);
    1286           0 :     const auto skipPixels = mPixelStore_PackSkipPixels;
    1287           0 :     const auto skipRows = mPixelStore_PackSkipRows;
    1288           0 :     const auto alignment = mPixelStore_PackAlignment;
    1289             : 
    1290           0 :     const auto usedPixelsPerRow = CheckedUint32(skipPixels) + width;
    1291           0 :     const auto usedRowsPerImage = CheckedUint32(skipRows) + height;
    1292             : 
    1293           0 :     if (!usedPixelsPerRow.isValid() || usedPixelsPerRow.value() > rowLength) {
    1294           0 :         ErrorInvalidOperation("%s: SKIP_PIXELS + width > ROW_LENGTH.", funcName);
    1295           0 :         return false;
    1296             :     }
    1297             : 
    1298           0 :     const auto rowLengthBytes = CheckedUint32(rowLength) * bytesPerPixel;
    1299           0 :     const auto rowStride = RoundUpToMultipleOf(rowLengthBytes, alignment);
    1300             : 
    1301           0 :     const auto usedBytesPerRow = usedPixelsPerRow * bytesPerPixel;
    1302           0 :     const auto usedBytesPerImage = (usedRowsPerImage - 1) * rowStride + usedBytesPerRow;
    1303             : 
    1304           0 :     if (!rowStride.isValid() || !usedBytesPerImage.isValid()) {
    1305           0 :         ErrorInvalidOperation("%s: Invalid UNPACK_ params.", funcName);
    1306           0 :         return false;
    1307             :     }
    1308             : 
    1309           0 :     *out_rowStride = rowStride.value();
    1310           0 :     *out_endOffset = usedBytesPerImage.value();
    1311           0 :     return true;
    1312             : }
    1313             : 
    1314             : void
    1315           0 : WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
    1316             :                          GLenum type, const dom::ArrayBufferView& dstView,
    1317             :                          GLuint dstElemOffset, CallerType aCallerType,
    1318             :                          ErrorResult& out_error)
    1319             : {
    1320           0 :     const char funcName[] = "readPixels";
    1321           0 :     if (!ReadPixels_SharedPrecheck(aCallerType, out_error))
    1322           0 :         return;
    1323             : 
    1324           0 :     if (mBoundPixelPackBuffer) {
    1325           0 :         ErrorInvalidOperation("%s: PIXEL_PACK_BUFFER must be null.", funcName);
    1326           0 :         return;
    1327             :     }
    1328             : 
    1329             :     ////
    1330             : 
    1331             :     js::Scalar::Type reqScalarType;
    1332           0 :     if (!GetJSScalarFromGLType(type, &reqScalarType)) {
    1333           0 :         ErrorInvalidEnum("%s: Bad `type`.", funcName);
    1334           0 :         return;
    1335             :     }
    1336             : 
    1337           0 :     const auto& viewElemType = dstView.Type();
    1338           0 :     if (viewElemType != reqScalarType) {
    1339           0 :         ErrorInvalidOperation("%s: `pixels` type does not match `type`.", funcName);
    1340           0 :         return;
    1341             :     }
    1342             : 
    1343             :     ////
    1344             : 
    1345             :     uint8_t* bytes;
    1346             :     size_t byteLen;
    1347           0 :     if (!ValidateArrayBufferView(funcName, dstView, dstElemOffset, 0, &bytes, &byteLen))
    1348           0 :         return;
    1349             : 
    1350             :     ////
    1351             : 
    1352           0 :     ReadPixelsImpl(x, y, width, height, format, type, bytes, byteLen);
    1353             : }
    1354             : 
    1355             : void
    1356           0 : WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
    1357             :                          GLenum type, WebGLsizeiptr offset,
    1358             :                          CallerType aCallerType, ErrorResult& out_error)
    1359             : {
    1360           0 :     const char funcName[] = "readPixels";
    1361           0 :     if (!ReadPixels_SharedPrecheck(aCallerType, out_error))
    1362           0 :         return;
    1363             : 
    1364           0 :     const auto& buffer = ValidateBufferSelection(funcName, LOCAL_GL_PIXEL_PACK_BUFFER);
    1365           0 :     if (!buffer)
    1366           0 :         return;
    1367             : 
    1368             :     //////
    1369             : 
    1370           0 :     if (!ValidateNonNegative(funcName, "offset", offset))
    1371           0 :         return;
    1372             : 
    1373             :     {
    1374           0 :         const auto bytesPerType = webgl::BytesPerPixel({LOCAL_GL_RED, type});
    1375             : 
    1376           0 :         if (offset % bytesPerType != 0) {
    1377             :             ErrorInvalidOperation("%s: `offset` must be divisible by the size of `type`"
    1378             :                                   " in bytes.",
    1379           0 :                                   funcName);
    1380           0 :             return;
    1381             :         }
    1382             :     }
    1383             : 
    1384             :     //////
    1385             : 
    1386           0 :     const auto bytesAvailable = buffer->ByteLength();
    1387           0 :     const auto checkedBytesAfterOffset = CheckedUint32(bytesAvailable) - offset;
    1388             : 
    1389           0 :     uint32_t bytesAfterOffset = 0;
    1390           0 :     if (checkedBytesAfterOffset.isValid()) {
    1391           0 :         bytesAfterOffset = checkedBytesAfterOffset.value();
    1392             :     }
    1393             : 
    1394           0 :     gl->MakeCurrent();
    1395           0 :     const ScopedLazyBind lazyBind(gl, LOCAL_GL_PIXEL_PACK_BUFFER, buffer);
    1396             : 
    1397           0 :     ReadPixelsImpl(x, y, width, height, format, type, (void*)offset, bytesAfterOffset);
    1398             : }
    1399             : 
    1400             : static webgl::PackingInfo
    1401           0 : DefaultReadPixelPI(const webgl::FormatUsageInfo* usage)
    1402             : {
    1403           0 :     MOZ_ASSERT(usage->IsRenderable());
    1404             : 
    1405           0 :     switch (usage->format->componentType) {
    1406             :     case webgl::ComponentType::NormUInt:
    1407           0 :         return { LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE };
    1408             : 
    1409             :     case webgl::ComponentType::Int:
    1410           0 :         return { LOCAL_GL_RGBA_INTEGER, LOCAL_GL_INT };
    1411             : 
    1412             :     case webgl::ComponentType::UInt:
    1413           0 :         return { LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_INT };
    1414             : 
    1415             :     case webgl::ComponentType::Float:
    1416           0 :         return { LOCAL_GL_RGBA, LOCAL_GL_FLOAT };
    1417             : 
    1418             :     default:
    1419           0 :         MOZ_CRASH();
    1420             :     }
    1421             : }
    1422             : 
    1423             : static bool
    1424           0 : ArePossiblePackEnums(const WebGLContext* webgl, const webgl::PackingInfo& pi)
    1425             : {
    1426             :     // OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid
    1427             :     // combination for glReadPixels()...
    1428             : 
    1429             :     // So yeah, we are actually checking that these are valid as /unpack/ formats, instead
    1430             :     // of /pack/ formats here, but it should cover the INVALID_ENUM cases.
    1431           0 :     if (!webgl->mFormatUsage->AreUnpackEnumsValid(pi.format, pi.type))
    1432           0 :         return false;
    1433             : 
    1434             :     // Only valid when pulled from:
    1435             :     // * GLES 2.0.25 p105:
    1436             :     //   "table 3.4, excluding formats LUMINANCE and LUMINANCE_ALPHA."
    1437             :     // * GLES 3.0.4 p193:
    1438             :     //   "table 3.2, excluding formats DEPTH_COMPONENT and DEPTH_STENCIL."
    1439           0 :     switch (pi.format) {
    1440             :     case LOCAL_GL_LUMINANCE:
    1441             :     case LOCAL_GL_LUMINANCE_ALPHA:
    1442             :     case LOCAL_GL_DEPTH_COMPONENT:
    1443             :     case LOCAL_GL_DEPTH_STENCIL:
    1444           0 :         return false;
    1445             :     }
    1446             : 
    1447           0 :     if (pi.type == LOCAL_GL_UNSIGNED_INT_24_8)
    1448           0 :         return false;
    1449             : 
    1450           0 :     return true;
    1451             : }
    1452             : 
    1453             : webgl::PackingInfo
    1454           0 : WebGLContext::ValidImplementationColorReadPI(const webgl::FormatUsageInfo* usage) const
    1455             : {
    1456           0 :     const auto defaultPI = DefaultReadPixelPI(usage);
    1457             : 
    1458             :     // ES2_compatibility always returns RGBA/UNSIGNED_BYTE, so branch on actual IsGLES().
    1459             :     // Also OSX+NV generates an error here.
    1460           0 :     if (!gl->IsGLES())
    1461           0 :         return defaultPI;
    1462             : 
    1463             :     webgl::PackingInfo implPI;
    1464           0 :     gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, (GLint*)&implPI.format);
    1465           0 :     gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, (GLint*)&implPI.type);
    1466             : 
    1467           0 :     if (!ArePossiblePackEnums(this, implPI))
    1468           0 :         return defaultPI;
    1469             : 
    1470           0 :     return implPI;
    1471             : }
    1472             : 
    1473             : static bool
    1474           0 : ValidateReadPixelsFormatAndType(const webgl::FormatUsageInfo* srcUsage,
    1475             :                                 const webgl::PackingInfo& pi, gl::GLContext* gl,
    1476             :                                 WebGLContext* webgl)
    1477             : {
    1478           0 :     const char funcName[] = "readPixels";
    1479             : 
    1480           0 :     if (!ArePossiblePackEnums(webgl, pi)) {
    1481           0 :         webgl->ErrorInvalidEnum("%s: Unexpected format or type.", funcName);
    1482           0 :         return false;
    1483             :     }
    1484             : 
    1485           0 :     const auto defaultPI = DefaultReadPixelPI(srcUsage);
    1486           0 :     if (pi == defaultPI)
    1487           0 :         return true;
    1488             : 
    1489             :     ////
    1490             : 
    1491             :     // OpenGL ES 3.0.4 p194 - When the internal format of the rendering surface is
    1492             :     // RGB10_A2, a third combination of format RGBA and type UNSIGNED_INT_2_10_10_10_REV
    1493             :     // is accepted.
    1494             : 
    1495           0 :     if (webgl->IsWebGL2() &&
    1496           0 :         srcUsage->format->effectiveFormat == webgl::EffectiveFormat::RGB10_A2 &&
    1497           0 :         pi.format == LOCAL_GL_RGBA &&
    1498           0 :         pi.type == LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV)
    1499             :     {
    1500           0 :         return true;
    1501             :     }
    1502             : 
    1503             :     ////
    1504             : 
    1505           0 :     MOZ_ASSERT(gl->IsCurrent());
    1506           0 :     const auto implPI = webgl->ValidImplementationColorReadPI(srcUsage);
    1507           0 :     if (pi == implPI)
    1508           0 :         return true;
    1509             : 
    1510             :     ////
    1511             : 
    1512           0 :     webgl->ErrorInvalidOperation("%s: Incompatible format or type.", funcName);
    1513           0 :     return false;
    1514             : }
    1515             : 
    1516             : void
    1517           0 : WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeight,
    1518             :                              GLenum packFormat, GLenum packType, void* dest,
    1519             :                              uint32_t dataLen)
    1520             : {
    1521           0 :     if (rawWidth < 0 || rawHeight < 0) {
    1522           0 :         ErrorInvalidValue("readPixels: negative size passed");
    1523           0 :         return;
    1524             :     }
    1525             : 
    1526           0 :     const uint32_t width(rawWidth);
    1527           0 :     const uint32_t height(rawHeight);
    1528             : 
    1529             :     //////
    1530             : 
    1531           0 :     MakeContextCurrent();
    1532             : 
    1533             :     const webgl::FormatUsageInfo* srcFormat;
    1534             :     uint32_t srcWidth;
    1535             :     uint32_t srcHeight;
    1536           0 :     if (!ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight))
    1537           0 :         return;
    1538             : 
    1539             :     //////
    1540             : 
    1541           0 :     const webgl::PackingInfo pi = {packFormat, packType};
    1542           0 :     if (!ValidateReadPixelsFormatAndType(srcFormat, pi, gl, this))
    1543           0 :         return;
    1544             : 
    1545             :     uint8_t bytesPerPixel;
    1546           0 :     if (!webgl::GetBytesPerPixel(pi, &bytesPerPixel)) {
    1547           0 :         ErrorInvalidOperation("readPixels: Unsupported format and type.");
    1548           0 :         return;
    1549             :     }
    1550             : 
    1551             :     //////
    1552             : 
    1553             :     uint32_t rowStride;
    1554             :     uint32_t bytesNeeded;
    1555           0 :     if (!ValidatePackSize("readPixels", width, height, bytesPerPixel, &rowStride,
    1556             :                           &bytesNeeded))
    1557             :     {
    1558           0 :         return;
    1559             :     }
    1560             : 
    1561           0 :     if (bytesNeeded > dataLen) {
    1562           0 :         ErrorInvalidOperation("readPixels: buffer too small");
    1563           0 :         return;
    1564             :     }
    1565             : 
    1566             :     ////
    1567             : 
    1568             :     int32_t readX, readY;
    1569             :     int32_t writeX, writeY;
    1570             :     int32_t rwWidth, rwHeight;
    1571           0 :     if (!Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth) ||
    1572           0 :         !Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight))
    1573             :     {
    1574           0 :         ErrorOutOfMemory("readPixels: Bad subrect selection.");
    1575           0 :         return;
    1576             :     }
    1577             : 
    1578             :     ////////////////
    1579             :     // Now that the errors are out of the way, on to actually reading!
    1580             : 
    1581           0 :     OnBeforeReadCall();
    1582             : 
    1583           0 :     if (!rwWidth || !rwHeight) {
    1584             :         // Disjoint rects, so we're done already.
    1585           0 :         DummyReadFramebufferOperation("readPixels");
    1586           0 :         return;
    1587             :     }
    1588             : 
    1589           0 :     if (uint32_t(rwWidth) == width &&
    1590           0 :         uint32_t(rwHeight) == height)
    1591             :     {
    1592           0 :         DoReadPixelsAndConvert(srcFormat->format, x, y, width, height, packFormat,
    1593           0 :                                packType, dest, dataLen, rowStride);
    1594           0 :         return;
    1595             :     }
    1596             : 
    1597             :     // Read request contains out-of-bounds pixels. Unfortunately:
    1598             :     // GLES 3.0.4 p194 "Obtaining Pixels from the Framebuffer":
    1599             :     // "If any of these pixels lies outside of the window allocated to the current GL
    1600             :     //  context, or outside of the image attached to the currently bound framebuffer
    1601             :     //  object, then the values obtained for those pixels are undefined."
    1602             : 
    1603             :     // This is a slow-path, so warn people away!
    1604             :     GenerateWarning("readPixels: Out-of-bounds reads with readPixels are deprecated, and"
    1605           0 :                     " may be slow.");
    1606             : 
    1607             :     ////////////////////////////////////
    1608             :     // Read only the in-bounds pixels.
    1609             : 
    1610           0 :     if (IsWebGL2()) {
    1611           0 :         if (!mPixelStore_PackRowLength) {
    1612           0 :             gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH,
    1613           0 :                              mPixelStore_PackSkipPixels + width);
    1614             :         }
    1615           0 :         gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore_PackSkipPixels + writeX);
    1616           0 :         gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows + writeY);
    1617             : 
    1618           0 :         DoReadPixelsAndConvert(srcFormat->format, readX, readY, rwWidth, rwHeight,
    1619           0 :                                packFormat, packType, dest, dataLen, rowStride);
    1620             : 
    1621           0 :         gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore_PackRowLength);
    1622           0 :         gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore_PackSkipPixels);
    1623           0 :         gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows);
    1624             :     } else {
    1625             :         // I *did* say "hilariously slow".
    1626             : 
    1627           0 :         uint8_t* row = (uint8_t*)dest + writeX * bytesPerPixel;
    1628           0 :         row += writeY * rowStride;
    1629           0 :         for (uint32_t j = 0; j < uint32_t(rwHeight); j++) {
    1630           0 :             DoReadPixelsAndConvert(srcFormat->format, readX, readY+j, rwWidth, 1,
    1631           0 :                                    packFormat, packType, row, dataLen, rowStride);
    1632           0 :             row += rowStride;
    1633             :         }
    1634             :     }
    1635             : }
    1636             : 
    1637             : void
    1638           0 : WebGLContext::RenderbufferStorage_base(const char* funcName, GLenum target,
    1639             :                                        GLsizei samples, GLenum internalFormat,
    1640             :                                        GLsizei width, GLsizei height)
    1641             : {
    1642           0 :     if (IsContextLost())
    1643           0 :         return;
    1644             : 
    1645           0 :     if (target != LOCAL_GL_RENDERBUFFER) {
    1646           0 :         ErrorInvalidEnumInfo("`target`", funcName, target);
    1647           0 :         return;
    1648             :     }
    1649             : 
    1650           0 :     if (!mBoundRenderbuffer) {
    1651           0 :         ErrorInvalidOperation("%s: Called on renderbuffer 0.", funcName);
    1652           0 :         return;
    1653             :     }
    1654             : 
    1655           0 :     if (samples < 0) {
    1656           0 :         ErrorInvalidValue("%s: `samples` must be >= 0.", funcName);
    1657           0 :         return;
    1658             :     }
    1659             : 
    1660           0 :     if (width < 0 || height < 0) {
    1661           0 :         ErrorInvalidValue("%s: `width` and `height` must be >= 0.", funcName);
    1662           0 :         return;
    1663             :     }
    1664             : 
    1665           0 :     mBoundRenderbuffer->RenderbufferStorage(funcName, uint32_t(samples), internalFormat,
    1666           0 :                                             uint32_t(width), uint32_t(height));
    1667             : }
    1668             : 
    1669             : void
    1670           0 : WebGLContext::RenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height)
    1671             : {
    1672             :     RenderbufferStorage_base("renderbufferStorage", target, 0, internalFormat, width,
    1673           0 :                              height);
    1674           0 : }
    1675             : 
    1676             : void
    1677           0 : WebGLContext::Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
    1678             : {
    1679           0 :     if (IsContextLost())
    1680           0 :         return;
    1681             : 
    1682           0 :     if (width < 0 || height < 0)
    1683           0 :         return ErrorInvalidValue("scissor: negative size");
    1684             : 
    1685           0 :     MakeContextCurrent();
    1686           0 :     gl->fScissor(x, y, width, height);
    1687             : }
    1688             : 
    1689             : void
    1690           0 : WebGLContext::StencilFunc(GLenum func, GLint ref, GLuint mask)
    1691             : {
    1692           0 :     if (IsContextLost())
    1693           0 :         return;
    1694             : 
    1695           0 :     if (!ValidateComparisonEnum(func, "stencilFunc: func"))
    1696           0 :         return;
    1697             : 
    1698           0 :     mStencilRefFront = ref;
    1699           0 :     mStencilRefBack = ref;
    1700           0 :     mStencilValueMaskFront = mask;
    1701           0 :     mStencilValueMaskBack = mask;
    1702             : 
    1703           0 :     MakeContextCurrent();
    1704           0 :     gl->fStencilFunc(func, ref, mask);
    1705             : }
    1706             : 
    1707             : void
    1708           0 : WebGLContext::StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
    1709             : {
    1710           0 :     if (IsContextLost())
    1711           0 :         return;
    1712             : 
    1713           0 :     if (!ValidateFaceEnum(face, "stencilFuncSeparate: face") ||
    1714           0 :         !ValidateComparisonEnum(func, "stencilFuncSeparate: func"))
    1715           0 :         return;
    1716             : 
    1717           0 :     switch (face) {
    1718             :         case LOCAL_GL_FRONT_AND_BACK:
    1719           0 :             mStencilRefFront = ref;
    1720           0 :             mStencilRefBack = ref;
    1721           0 :             mStencilValueMaskFront = mask;
    1722           0 :             mStencilValueMaskBack = mask;
    1723           0 :             break;
    1724             :         case LOCAL_GL_FRONT:
    1725           0 :             mStencilRefFront = ref;
    1726           0 :             mStencilValueMaskFront = mask;
    1727           0 :             break;
    1728             :         case LOCAL_GL_BACK:
    1729           0 :             mStencilRefBack = ref;
    1730           0 :             mStencilValueMaskBack = mask;
    1731           0 :             break;
    1732             :     }
    1733             : 
    1734           0 :     MakeContextCurrent();
    1735           0 :     gl->fStencilFuncSeparate(face, func, ref, mask);
    1736             : }
    1737             : 
    1738             : void
    1739           0 : WebGLContext::StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
    1740             : {
    1741           0 :     if (IsContextLost())
    1742           0 :         return;
    1743             : 
    1744           0 :     if (!ValidateStencilOpEnum(sfail, "stencilOp: sfail") ||
    1745           0 :         !ValidateStencilOpEnum(dpfail, "stencilOp: dpfail") ||
    1746           0 :         !ValidateStencilOpEnum(dppass, "stencilOp: dppass"))
    1747           0 :         return;
    1748             : 
    1749           0 :     MakeContextCurrent();
    1750           0 :     gl->fStencilOp(sfail, dpfail, dppass);
    1751             : }
    1752             : 
    1753             : void
    1754           0 : WebGLContext::StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)
    1755             : {
    1756           0 :     if (IsContextLost())
    1757           0 :         return;
    1758             : 
    1759           0 :     if (!ValidateFaceEnum(face, "stencilOpSeparate: face") ||
    1760           0 :         !ValidateStencilOpEnum(sfail, "stencilOpSeparate: sfail") ||
    1761           0 :         !ValidateStencilOpEnum(dpfail, "stencilOpSeparate: dpfail") ||
    1762           0 :         !ValidateStencilOpEnum(dppass, "stencilOpSeparate: dppass"))
    1763           0 :         return;
    1764             : 
    1765           0 :     MakeContextCurrent();
    1766           0 :     gl->fStencilOpSeparate(face, sfail, dpfail, dppass);
    1767             : }
    1768             : 
    1769             : ////////////////////////////////////////////////////////////////////////////////
    1770             : // Uniform setters.
    1771             : 
    1772             : class ValidateIfSampler
    1773             : {
    1774             :     const WebGLUniformLocation* const mLoc;
    1775             :     const size_t mDataCount;
    1776             :     const GLint* const mData;
    1777             :     bool mIsValidatedSampler;
    1778             : 
    1779             : public:
    1780           0 :     ValidateIfSampler(WebGLContext* webgl, const char* funcName,
    1781             :                       WebGLUniformLocation* loc, size_t dataCount, const GLint* data,
    1782             :                       bool* const out_error)
    1783           0 :         : mLoc(loc)
    1784             :         , mDataCount(dataCount)
    1785             :         , mData(data)
    1786           0 :         , mIsValidatedSampler(false)
    1787             :     {
    1788           0 :         if (!mLoc->mInfo->mSamplerTexList) {
    1789           0 :             *out_error = false;
    1790           0 :             return;
    1791             :         }
    1792             : 
    1793           0 :         for (size_t i = 0; i < mDataCount; i++) {
    1794           0 :             const auto& val = mData[i];
    1795           0 :             if (val < 0 || uint32_t(val) >= webgl->GLMaxTextureUnits()) {
    1796           0 :                 webgl->ErrorInvalidValue("%s: This uniform location is a sampler, but %d"
    1797             :                                          " is not a valid texture unit.",
    1798           0 :                                          funcName, val);
    1799           0 :                 *out_error = true;
    1800           0 :                 return;
    1801             :             }
    1802             :         }
    1803             : 
    1804           0 :         mIsValidatedSampler = true;
    1805           0 :         *out_error = false;
    1806             :     }
    1807             : 
    1808           0 :     ~ValidateIfSampler() {
    1809           0 :         if (!mIsValidatedSampler)
    1810           0 :             return;
    1811             : 
    1812           0 :         auto& samplerValues = mLoc->mInfo->mSamplerValues;
    1813             : 
    1814           0 :         for (size_t i = 0; i < mDataCount; i++) {
    1815           0 :             const size_t curIndex = mLoc->mArrayIndex + i;
    1816           0 :             if (curIndex >= samplerValues.size())
    1817           0 :                 break;
    1818             : 
    1819           0 :             samplerValues[curIndex] = mData[i];
    1820             :         }
    1821           0 :     }
    1822             : };
    1823             : 
    1824             : ////////////////////
    1825             : 
    1826             : void
    1827           0 : WebGLContext::Uniform1i(WebGLUniformLocation* loc, GLint a1)
    1828             : {
    1829           0 :     const char funcName[] = "uniform1i";
    1830           0 :     if (!ValidateUniformSetter(loc, 1, LOCAL_GL_INT, funcName))
    1831           0 :         return;
    1832             : 
    1833             :     bool error;
    1834           0 :     const ValidateIfSampler validate(this, funcName, loc, 1, &a1, &error);
    1835           0 :     if (error)
    1836           0 :         return;
    1837             : 
    1838           0 :     MakeContextCurrent();
    1839           0 :     gl->fUniform1i(loc->mLoc, a1);
    1840             : }
    1841             : 
    1842             : void
    1843           0 : WebGLContext::Uniform2i(WebGLUniformLocation* loc, GLint a1, GLint a2)
    1844             : {
    1845           0 :     const char funcName[] = "uniform2i";
    1846           0 :     if (!ValidateUniformSetter(loc, 2, LOCAL_GL_INT, funcName))
    1847           0 :         return;
    1848             : 
    1849           0 :     MakeContextCurrent();
    1850           0 :     gl->fUniform2i(loc->mLoc, a1, a2);
    1851             : }
    1852             : 
    1853             : void
    1854           0 : WebGLContext::Uniform3i(WebGLUniformLocation* loc, GLint a1, GLint a2, GLint a3)
    1855             : {
    1856           0 :     const char funcName[] = "uniform3i";
    1857           0 :     if (!ValidateUniformSetter(loc, 3, LOCAL_GL_INT, funcName))
    1858           0 :         return;
    1859             : 
    1860           0 :     MakeContextCurrent();
    1861           0 :     gl->fUniform3i(loc->mLoc, a1, a2, a3);
    1862             : }
    1863             : 
    1864             : void
    1865           0 : WebGLContext::Uniform4i(WebGLUniformLocation* loc, GLint a1, GLint a2, GLint a3,
    1866             :                         GLint a4)
    1867             : {
    1868           0 :     const char funcName[] = "uniform4i";
    1869           0 :     if (!ValidateUniformSetter(loc, 4, LOCAL_GL_INT, funcName))
    1870           0 :         return;
    1871             : 
    1872           0 :     MakeContextCurrent();
    1873           0 :     gl->fUniform4i(loc->mLoc, a1, a2, a3, a4);
    1874             : }
    1875             : 
    1876             : //////////
    1877             : 
    1878             : void
    1879           0 : WebGLContext::Uniform1f(WebGLUniformLocation* loc, GLfloat a1)
    1880             : {
    1881           0 :     const char funcName[] = "uniform1f";
    1882           0 :     if (!ValidateUniformSetter(loc, 1, LOCAL_GL_FLOAT, funcName))
    1883           0 :         return;
    1884             : 
    1885           0 :     MakeContextCurrent();
    1886           0 :     gl->fUniform1f(loc->mLoc, a1);
    1887             : }
    1888             : 
    1889             : void
    1890           0 : WebGLContext::Uniform2f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2)
    1891             : {
    1892           0 :     const char funcName[] = "uniform2f";
    1893           0 :     if (!ValidateUniformSetter(loc, 2, LOCAL_GL_FLOAT, funcName))
    1894           0 :         return;
    1895             : 
    1896           0 :     MakeContextCurrent();
    1897           0 :     gl->fUniform2f(loc->mLoc, a1, a2);
    1898             : }
    1899             : 
    1900             : void
    1901           0 : WebGLContext::Uniform3f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2,
    1902             :                         GLfloat a3)
    1903             : {
    1904           0 :     const char funcName[] = "uniform3f";
    1905           0 :     if (!ValidateUniformSetter(loc, 3, LOCAL_GL_FLOAT, funcName))
    1906           0 :         return;
    1907             : 
    1908           0 :     MakeContextCurrent();
    1909           0 :     gl->fUniform3f(loc->mLoc, a1, a2, a3);
    1910             : }
    1911             : 
    1912             : void
    1913           0 : WebGLContext::Uniform4f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2,
    1914             :                         GLfloat a3, GLfloat a4)
    1915             : {
    1916           0 :     const char funcName[] = "uniform4f";
    1917           0 :     if (!ValidateUniformSetter(loc, 4, LOCAL_GL_FLOAT, funcName))
    1918           0 :         return;
    1919             : 
    1920           0 :     MakeContextCurrent();
    1921           0 :     gl->fUniform4f(loc->mLoc, a1, a2, a3, a4);
    1922             : }
    1923             : 
    1924             : ////////////////////////////////////////
    1925             : // Array
    1926             : 
    1927             : static bool
    1928           0 : ValidateArrOffsetAndCount(WebGLContext* webgl, const char* funcName, size_t elemsAvail,
    1929             :                           GLuint elemOffset, GLuint elemCountOverride,
    1930             :                           size_t* const out_elemCount)
    1931             : {
    1932           0 :     if (elemOffset > elemsAvail) {
    1933           0 :         webgl->ErrorInvalidValue("%s: Bad offset into list.", funcName);
    1934           0 :         return false;
    1935             :     }
    1936           0 :     elemsAvail -= elemOffset;
    1937             : 
    1938           0 :     if (elemCountOverride) {
    1939           0 :         if (elemCountOverride > elemsAvail) {
    1940           0 :             webgl->ErrorInvalidValue("%s: Bad count override for sub-list.", funcName);
    1941           0 :             return false;
    1942             :         }
    1943           0 :         elemsAvail = elemCountOverride;
    1944             :     }
    1945             : 
    1946           0 :     *out_elemCount = elemsAvail;
    1947           0 :     return true;
    1948             : }
    1949             : 
    1950             : void
    1951           0 : WebGLContext::UniformNiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
    1952             :                          const Int32Arr& arr, GLuint elemOffset, GLuint elemCountOverride)
    1953             : {
    1954             :     size_t elemCount;
    1955           0 :     if (!ValidateArrOffsetAndCount(this, funcName, arr.elemCount, elemOffset,
    1956             :                                    elemCountOverride, &elemCount))
    1957             :     {
    1958           0 :         return;
    1959             :     }
    1960           0 :     const auto elemBytes = arr.elemBytes + elemOffset;
    1961             : 
    1962             :     uint32_t numElementsToUpload;
    1963           0 :     if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_INT, elemCount, funcName,
    1964             :                                     &numElementsToUpload))
    1965             :     {
    1966           0 :         return;
    1967             :     }
    1968             : 
    1969             :     bool error;
    1970             :     const ValidateIfSampler samplerValidator(this, funcName, loc, numElementsToUpload,
    1971           0 :                                              elemBytes, &error);
    1972           0 :     if (error)
    1973           0 :         return;
    1974             : 
    1975             :     static const decltype(&gl::GLContext::fUniform1iv) kFuncList[] = {
    1976             :         &gl::GLContext::fUniform1iv,
    1977             :         &gl::GLContext::fUniform2iv,
    1978             :         &gl::GLContext::fUniform3iv,
    1979             :         &gl::GLContext::fUniform4iv
    1980             :     };
    1981           0 :     const auto func = kFuncList[N-1];
    1982             : 
    1983           0 :     MakeContextCurrent();
    1984           0 :     (gl->*func)(loc->mLoc, numElementsToUpload, elemBytes);
    1985             : }
    1986             : 
    1987             : void
    1988           0 : WebGLContext::UniformNuiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
    1989             :                           const Uint32Arr& arr, GLuint elemOffset,
    1990             :                           GLuint elemCountOverride)
    1991             : {
    1992             :     size_t elemCount;
    1993           0 :     if (!ValidateArrOffsetAndCount(this, funcName, arr.elemCount, elemOffset,
    1994             :                                    elemCountOverride, &elemCount))
    1995             :     {
    1996           0 :         return;
    1997             :     }
    1998           0 :     const auto elemBytes = arr.elemBytes + elemOffset;
    1999             : 
    2000             :     uint32_t numElementsToUpload;
    2001           0 :     if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_UNSIGNED_INT, elemCount, funcName,
    2002             :                                     &numElementsToUpload))
    2003             :     {
    2004           0 :         return;
    2005             :     }
    2006           0 :     MOZ_ASSERT(!loc->mInfo->mSamplerTexList, "Should not be a sampler.");
    2007             : 
    2008             :     static const decltype(&gl::GLContext::fUniform1uiv) kFuncList[] = {
    2009             :         &gl::GLContext::fUniform1uiv,
    2010             :         &gl::GLContext::fUniform2uiv,
    2011             :         &gl::GLContext::fUniform3uiv,
    2012             :         &gl::GLContext::fUniform4uiv
    2013             :     };
    2014           0 :     const auto func = kFuncList[N-1];
    2015             : 
    2016           0 :     MakeContextCurrent();
    2017           0 :     (gl->*func)(loc->mLoc, numElementsToUpload, elemBytes);
    2018             : }
    2019             : 
    2020             : void
    2021           0 : WebGLContext::UniformNfv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
    2022             :                          const Float32Arr& arr, GLuint elemOffset,
    2023             :                          GLuint elemCountOverride)
    2024             : {
    2025             :     size_t elemCount;
    2026           0 :     if (!ValidateArrOffsetAndCount(this, funcName, arr.elemCount, elemOffset,
    2027             :                                    elemCountOverride, &elemCount))
    2028             :     {
    2029           0 :         return;
    2030             :     }
    2031           0 :     const auto elemBytes = arr.elemBytes + elemOffset;
    2032             : 
    2033             :     uint32_t numElementsToUpload;
    2034           0 :     if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_FLOAT, elemCount, funcName,
    2035             :                                     &numElementsToUpload))
    2036             :     {
    2037           0 :         return;
    2038             :     }
    2039           0 :     MOZ_ASSERT(!loc->mInfo->mSamplerTexList, "Should not be a sampler.");
    2040             : 
    2041             :     static const decltype(&gl::GLContext::fUniform1fv) kFuncList[] = {
    2042             :         &gl::GLContext::fUniform1fv,
    2043             :         &gl::GLContext::fUniform2fv,
    2044             :         &gl::GLContext::fUniform3fv,
    2045             :         &gl::GLContext::fUniform4fv
    2046             :     };
    2047           0 :     const auto func = kFuncList[N-1];
    2048             : 
    2049           0 :     MakeContextCurrent();
    2050           0 :     (gl->*func)(loc->mLoc, numElementsToUpload, elemBytes);
    2051             : }
    2052             : 
    2053             : static inline void
    2054           0 : MatrixAxBToRowMajor(const uint8_t width, const uint8_t height,
    2055             :                     const float* __restrict srcColMajor,
    2056             :                     float* __restrict dstRowMajor)
    2057             : {
    2058           0 :     for (uint8_t x = 0; x < width; ++x) {
    2059           0 :         for (uint8_t y = 0; y < height; ++y) {
    2060           0 :             dstRowMajor[y * width + x] = srcColMajor[x * height + y];
    2061             :         }
    2062             :     }
    2063           0 : }
    2064             : 
    2065             : void
    2066           0 : WebGLContext::UniformMatrixAxBfv(const char* funcName, uint8_t A, uint8_t B,
    2067             :                                  WebGLUniformLocation* loc, const bool transpose,
    2068             :                                  const Float32Arr& arr, GLuint elemOffset,
    2069             :                                  GLuint elemCountOverride)
    2070             : {
    2071             :     size_t elemCount;
    2072           0 :     if (!ValidateArrOffsetAndCount(this, funcName, arr.elemCount, elemOffset,
    2073             :                                    elemCountOverride, &elemCount))
    2074             :     {
    2075           0 :         return;
    2076             :     }
    2077           0 :     const auto elemBytes = arr.elemBytes + elemOffset;
    2078             : 
    2079             :     uint32_t numMatsToUpload;
    2080           0 :     if (!ValidateUniformMatrixArraySetter(loc, A, B, LOCAL_GL_FLOAT, elemCount,
    2081             :                                           transpose, funcName, &numMatsToUpload))
    2082             :     {
    2083           0 :         return;
    2084             :     }
    2085           0 :     MOZ_ASSERT(!loc->mInfo->mSamplerTexList, "Should not be a sampler.");
    2086             : 
    2087             :     ////
    2088             : 
    2089           0 :     bool uploadTranspose = transpose;
    2090           0 :     const float* uploadBytes = elemBytes;
    2091             : 
    2092           0 :     UniqueBuffer temp;
    2093           0 :     if (!transpose && gl->WorkAroundDriverBugs() && gl->IsANGLE() &&
    2094           0 :         gl->IsAtLeast(gl::ContextProfile::OpenGLES, 300))
    2095             :     {
    2096             :         // ANGLE is really slow at non-GL-transposed matrices.
    2097           0 :         const size_t kElemsPerMat = A * B;
    2098             : 
    2099           0 :         temp = malloc(numMatsToUpload * kElemsPerMat * sizeof(float));
    2100           0 :         if (!temp) {
    2101             :             ErrorOutOfMemory("%s: Failed to alloc temporary buffer for transposition.",
    2102           0 :                              funcName);
    2103           0 :             return;
    2104             :         }
    2105             : 
    2106           0 :         auto srcItr = (const float*)elemBytes;
    2107           0 :         auto dstItr = (float*)temp.get();
    2108           0 :         const auto srcEnd = srcItr + numMatsToUpload * kElemsPerMat;
    2109             : 
    2110           0 :         while (srcItr != srcEnd) {
    2111           0 :             MatrixAxBToRowMajor(A, B, srcItr, dstItr);
    2112           0 :             srcItr += kElemsPerMat;
    2113           0 :             dstItr += kElemsPerMat;
    2114             :         }
    2115             : 
    2116           0 :         uploadBytes = (const float*)temp.get();
    2117           0 :         uploadTranspose = true;
    2118             :     }
    2119             : 
    2120             :     ////
    2121             : 
    2122             :     static const decltype(&gl::GLContext::fUniformMatrix2fv) kFuncList[] = {
    2123             :         &gl::GLContext::fUniformMatrix2fv,
    2124             :         &gl::GLContext::fUniformMatrix2x3fv,
    2125             :         &gl::GLContext::fUniformMatrix2x4fv,
    2126             : 
    2127             :         &gl::GLContext::fUniformMatrix3x2fv,
    2128             :         &gl::GLContext::fUniformMatrix3fv,
    2129             :         &gl::GLContext::fUniformMatrix3x4fv,
    2130             : 
    2131             :         &gl::GLContext::fUniformMatrix4x2fv,
    2132             :         &gl::GLContext::fUniformMatrix4x3fv,
    2133             :         &gl::GLContext::fUniformMatrix4fv
    2134             :     };
    2135           0 :     const auto func = kFuncList[3*(A-2) + (B-2)];
    2136             : 
    2137           0 :     MakeContextCurrent();
    2138           0 :     (gl->*func)(loc->mLoc, numMatsToUpload, uploadTranspose, uploadBytes);
    2139             : }
    2140             : 
    2141             : ////////////////////////////////////////////////////////////////////////////////
    2142             : 
    2143             : void
    2144           0 : WebGLContext::UseProgram(WebGLProgram* prog)
    2145             : {
    2146           0 :     if (IsContextLost())
    2147           0 :         return;
    2148             : 
    2149           0 :     if (!prog) {
    2150           0 :         mCurrentProgram = nullptr;
    2151           0 :         mActiveProgramLinkInfo = nullptr;
    2152           0 :         return;
    2153             :     }
    2154             : 
    2155           0 :     if (!ValidateObject("useProgram", *prog))
    2156           0 :         return;
    2157             : 
    2158           0 :     if (prog->UseProgram()) {
    2159           0 :         mCurrentProgram = prog;
    2160           0 :         mActiveProgramLinkInfo = mCurrentProgram->LinkInfo();
    2161             :     }
    2162             : }
    2163             : 
    2164             : void
    2165           0 : WebGLContext::ValidateProgram(const WebGLProgram& prog)
    2166             : {
    2167           0 :     if (IsContextLost())
    2168           0 :         return;
    2169             : 
    2170           0 :     if (!ValidateObject("validateProgram", prog))
    2171           0 :         return;
    2172             : 
    2173           0 :     prog.ValidateProgram();
    2174             : }
    2175             : 
    2176             : already_AddRefed<WebGLFramebuffer>
    2177           0 : WebGLContext::CreateFramebuffer()
    2178             : {
    2179           0 :     if (IsContextLost())
    2180           0 :         return nullptr;
    2181             : 
    2182           0 :     GLuint fbo = 0;
    2183           0 :     MakeContextCurrent();
    2184           0 :     gl->fGenFramebuffers(1, &fbo);
    2185             : 
    2186           0 :     RefPtr<WebGLFramebuffer> globj = new WebGLFramebuffer(this, fbo);
    2187           0 :     return globj.forget();
    2188             : }
    2189             : 
    2190             : already_AddRefed<WebGLRenderbuffer>
    2191           0 : WebGLContext::CreateRenderbuffer()
    2192             : {
    2193           0 :     if (IsContextLost())
    2194           0 :         return nullptr;
    2195             : 
    2196           0 :     MakeContextCurrent();
    2197           0 :     RefPtr<WebGLRenderbuffer> globj = new WebGLRenderbuffer(this);
    2198           0 :     return globj.forget();
    2199             : }
    2200             : 
    2201             : void
    2202           0 : WebGLContext::Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
    2203             : {
    2204           0 :     if (IsContextLost())
    2205           0 :         return;
    2206             : 
    2207           0 :     if (width < 0 || height < 0)
    2208           0 :         return ErrorInvalidValue("viewport: negative size");
    2209             : 
    2210           0 :     width = std::min(width, (GLsizei)mImplMaxViewportDims[0]);
    2211           0 :     height = std::min(height, (GLsizei)mImplMaxViewportDims[1]);
    2212             : 
    2213           0 :     MakeContextCurrent();
    2214           0 :     gl->fViewport(x, y, width, height);
    2215             : 
    2216           0 :     mViewportX = x;
    2217           0 :     mViewportY = y;
    2218           0 :     mViewportWidth = width;
    2219           0 :     mViewportHeight = height;
    2220             : }
    2221             : 
    2222             : void
    2223           0 : WebGLContext::CompileShader(WebGLShader& shader)
    2224             : {
    2225           0 :     if (IsContextLost())
    2226           0 :         return;
    2227             : 
    2228           0 :     if (!ValidateObject("compileShader", shader))
    2229           0 :         return;
    2230             : 
    2231           0 :     shader.CompileShader();
    2232             : }
    2233             : 
    2234             : JS::Value
    2235           0 : WebGLContext::GetShaderParameter(const WebGLShader& shader, GLenum pname)
    2236             : {
    2237           0 :     if (IsContextLost())
    2238           0 :         return JS::NullValue();
    2239             : 
    2240           0 :     if (!ValidateObjectAllowDeleted("getShaderParameter: shader", shader))
    2241           0 :         return JS::NullValue();
    2242             : 
    2243           0 :     return shader.GetShaderParameter(pname);
    2244             : }
    2245             : 
    2246             : void
    2247           0 : WebGLContext::GetShaderInfoLog(const WebGLShader& shader, nsAString& retval)
    2248             : {
    2249           0 :     retval.SetIsVoid(true);
    2250             : 
    2251           0 :     if (IsContextLost())
    2252           0 :         return;
    2253             : 
    2254           0 :     if (!ValidateObject("getShaderInfoLog: shader", shader))
    2255           0 :         return;
    2256             : 
    2257           0 :     shader.GetShaderInfoLog(&retval);
    2258             : }
    2259             : 
    2260             : already_AddRefed<WebGLShaderPrecisionFormat>
    2261           0 : WebGLContext::GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype)
    2262             : {
    2263           0 :     if (IsContextLost())
    2264           0 :         return nullptr;
    2265             : 
    2266           0 :     switch (shadertype) {
    2267             :         case LOCAL_GL_FRAGMENT_SHADER:
    2268             :         case LOCAL_GL_VERTEX_SHADER:
    2269           0 :             break;
    2270             :         default:
    2271           0 :             ErrorInvalidEnumInfo("getShaderPrecisionFormat: shadertype", shadertype);
    2272           0 :             return nullptr;
    2273             :     }
    2274             : 
    2275           0 :     switch (precisiontype) {
    2276             :         case LOCAL_GL_LOW_FLOAT:
    2277             :         case LOCAL_GL_MEDIUM_FLOAT:
    2278             :         case LOCAL_GL_HIGH_FLOAT:
    2279             :         case LOCAL_GL_LOW_INT:
    2280             :         case LOCAL_GL_MEDIUM_INT:
    2281             :         case LOCAL_GL_HIGH_INT:
    2282           0 :             break;
    2283             :         default:
    2284           0 :             ErrorInvalidEnumInfo("getShaderPrecisionFormat: precisiontype", precisiontype);
    2285           0 :             return nullptr;
    2286             :     }
    2287             : 
    2288           0 :     MakeContextCurrent();
    2289             :     GLint range[2], precision;
    2290             : 
    2291           0 :     if (mDisableFragHighP &&
    2292           0 :         shadertype == LOCAL_GL_FRAGMENT_SHADER &&
    2293           0 :         (precisiontype == LOCAL_GL_HIGH_FLOAT ||
    2294             :          precisiontype == LOCAL_GL_HIGH_INT))
    2295             :     {
    2296           0 :       precision = 0;
    2297           0 :       range[0] = 0;
    2298           0 :       range[1] = 0;
    2299             :     } else {
    2300           0 :       gl->fGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision);
    2301             :     }
    2302             : 
    2303             :     RefPtr<WebGLShaderPrecisionFormat> retShaderPrecisionFormat
    2304           0 :         = new WebGLShaderPrecisionFormat(this, range[0], range[1], precision);
    2305           0 :     return retShaderPrecisionFormat.forget();
    2306             : }
    2307             : 
    2308             : void
    2309           0 : WebGLContext::GetShaderSource(const WebGLShader& shader, nsAString& retval)
    2310             : {
    2311           0 :     retval.SetIsVoid(true);
    2312             : 
    2313           0 :     if (IsContextLost())
    2314           0 :         return;
    2315             : 
    2316           0 :     if (!ValidateObject("getShaderSource: shader", shader))
    2317           0 :         return;
    2318             : 
    2319           0 :     shader.GetShaderSource(&retval);
    2320             : }
    2321             : 
    2322             : void
    2323           0 : WebGLContext::ShaderSource(WebGLShader& shader, const nsAString& source)
    2324             : {
    2325           0 :     if (IsContextLost())
    2326           0 :         return;
    2327             : 
    2328           0 :     if (!ValidateObject("shaderSource: shader", shader))
    2329           0 :         return;
    2330             : 
    2331           0 :     shader.ShaderSource(source);
    2332             : }
    2333             : 
    2334             : void
    2335           0 : WebGLContext::LoseContext()
    2336             : {
    2337           0 :     if (IsContextLost())
    2338           0 :         return ErrorInvalidOperation("loseContext: Context is already lost.");
    2339             : 
    2340           0 :     ForceLoseContext(true);
    2341             : }
    2342             : 
    2343             : void
    2344           0 : WebGLContext::RestoreContext()
    2345             : {
    2346           0 :     if (!IsContextLost())
    2347           0 :         return ErrorInvalidOperation("restoreContext: Context is not lost.");
    2348             : 
    2349           0 :     if (!mLastLossWasSimulated) {
    2350             :         return ErrorInvalidOperation("restoreContext: Context loss was not simulated."
    2351           0 :                                      " Cannot simulate restore.");
    2352             :     }
    2353             :     // If we're currently lost, and the last loss was simulated, then
    2354             :     // we're currently only simulated-lost, allowing us to call
    2355             :     // restoreContext().
    2356             : 
    2357           0 :     if (!mAllowContextRestore)
    2358           0 :         return ErrorInvalidOperation("restoreContext: Context cannot be restored.");
    2359             : 
    2360           0 :     ForceRestoreContext();
    2361             : }
    2362             : 
    2363             : void
    2364           0 : WebGLContext::BlendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
    2365           0 :     if (IsContextLost())
    2366           0 :         return;
    2367           0 :     MakeContextCurrent();
    2368           0 :     gl->fBlendColor(r, g, b, a);
    2369             : }
    2370             : 
    2371             : void
    2372           0 : WebGLContext::Flush() {
    2373           0 :     if (IsContextLost())
    2374           0 :         return;
    2375           0 :     MakeContextCurrent();
    2376           0 :     gl->fFlush();
    2377             : }
    2378             : 
    2379             : void
    2380           0 : WebGLContext::Finish() {
    2381           0 :     if (IsContextLost())
    2382           0 :         return;
    2383           0 :     MakeContextCurrent();
    2384           0 :     gl->fFinish();
    2385             : }
    2386             : 
    2387             : void
    2388           0 : WebGLContext::LineWidth(GLfloat width)
    2389             : {
    2390           0 :     if (IsContextLost())
    2391           0 :         return;
    2392             : 
    2393             :     // Doing it this way instead of `if (width <= 0.0)` handles NaNs.
    2394           0 :     const bool isValid = width > 0.0;
    2395           0 :     if (!isValid) {
    2396           0 :         ErrorInvalidValue("lineWidth: `width` must be positive and non-zero.");
    2397           0 :         return;
    2398             :     }
    2399             : 
    2400           0 :     mLineWidth = width;
    2401             : 
    2402           0 :     if (gl->IsCoreProfile() && width > 1.0) {
    2403           0 :         width = 1.0;
    2404             :     }
    2405             : 
    2406           0 :     MakeContextCurrent();
    2407           0 :     gl->fLineWidth(width);
    2408             : }
    2409             : 
    2410             : void
    2411           0 : WebGLContext::PolygonOffset(GLfloat factor, GLfloat units) {
    2412           0 :     if (IsContextLost())
    2413           0 :         return;
    2414           0 :     MakeContextCurrent();
    2415           0 :     gl->fPolygonOffset(factor, units);
    2416             : }
    2417             : 
    2418             : void
    2419           0 : WebGLContext::SampleCoverage(GLclampf value, WebGLboolean invert) {
    2420           0 :     if (IsContextLost())
    2421           0 :         return;
    2422           0 :     MakeContextCurrent();
    2423           0 :     gl->fSampleCoverage(value, invert);
    2424             : }
    2425             : 
    2426             : } // namespace mozilla

Generated by: LCOV version 1.13