content/canvas/src/WebGLContextGL.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/canvas/src/WebGLContextGL.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,4115 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "WebGLContext.h"
    1.10 +#include "WebGLContextUtils.h"
    1.11 +#include "WebGLBuffer.h"
    1.12 +#include "WebGLVertexAttribData.h"
    1.13 +#include "WebGLShader.h"
    1.14 +#include "WebGLProgram.h"
    1.15 +#include "WebGLUniformLocation.h"
    1.16 +#include "WebGLFramebuffer.h"
    1.17 +#include "WebGLRenderbuffer.h"
    1.18 +#include "WebGLShaderPrecisionFormat.h"
    1.19 +#include "WebGLTexture.h"
    1.20 +#include "WebGLExtensions.h"
    1.21 +#include "WebGLVertexArray.h"
    1.22 +
    1.23 +#include "nsString.h"
    1.24 +#include "nsDebug.h"
    1.25 +
    1.26 +#include "gfxContext.h"
    1.27 +#include "gfxPlatform.h"
    1.28 +#include "GLContext.h"
    1.29 +
    1.30 +#include "nsContentUtils.h"
    1.31 +#include "nsError.h"
    1.32 +#include "nsLayoutUtils.h"
    1.33 +
    1.34 +#include "CanvasUtils.h"
    1.35 +#include "gfxUtils.h"
    1.36 +
    1.37 +#include "jsfriendapi.h"
    1.38 +
    1.39 +#include "WebGLTexelConversions.h"
    1.40 +#include "WebGLValidateStrings.h"
    1.41 +#include <algorithm>
    1.42 +
    1.43 +// needed to check if current OS is lower than 10.7
    1.44 +#if defined(MOZ_WIDGET_COCOA)
    1.45 +#include "nsCocoaFeatures.h"
    1.46 +#endif
    1.47 +
    1.48 +#include "mozilla/dom/BindingUtils.h"
    1.49 +#include "mozilla/dom/ImageData.h"
    1.50 +#include "mozilla/dom/ToJSValue.h"
    1.51 +#include "mozilla/Endian.h"
    1.52 +
    1.53 +using namespace mozilla;
    1.54 +using namespace mozilla::dom;
    1.55 +using namespace mozilla::gl;
    1.56 +using namespace mozilla::gfx;
    1.57 +
    1.58 +static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize);
    1.59 +
    1.60 +const WebGLRectangleObject*
    1.61 +WebGLContext::CurValidFBRectObject() const
    1.62 +{
    1.63 +    const WebGLRectangleObject* rect = nullptr;
    1.64 +
    1.65 +    if (mBoundFramebuffer) {
    1.66 +        // We don't really need to ask the driver.
    1.67 +        // Use 'precheck' to just check that our internal state looks good.
    1.68 +        GLenum precheckStatus = mBoundFramebuffer->PrecheckFramebufferStatus();
    1.69 +        if (precheckStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE)
    1.70 +            rect = &mBoundFramebuffer->RectangleObject();
    1.71 +    } else {
    1.72 +        rect = static_cast<const WebGLRectangleObject*>(this);
    1.73 +    }
    1.74 +
    1.75 +    return rect;
    1.76 +}
    1.77 +
    1.78 +//
    1.79 +//  WebGL API
    1.80 +//
    1.81 +
    1.82 +void
    1.83 +WebGLContext::ActiveTexture(GLenum texture)
    1.84 +{
    1.85 +    if (IsContextLost())
    1.86 +        return;
    1.87 +
    1.88 +    if (texture < LOCAL_GL_TEXTURE0 ||
    1.89 +        texture >= LOCAL_GL_TEXTURE0 + uint32_t(mGLMaxTextureUnits))
    1.90 +    {
    1.91 +        return ErrorInvalidEnum(
    1.92 +            "ActiveTexture: texture unit %d out of range. "
    1.93 +            "Accepted values range from TEXTURE0 to TEXTURE0 + %d. "
    1.94 +            "Notice that TEXTURE0 != 0.",
    1.95 +            texture, mGLMaxTextureUnits);
    1.96 +    }
    1.97 +
    1.98 +    MakeContextCurrent();
    1.99 +    mActiveTexture = texture - LOCAL_GL_TEXTURE0;
   1.100 +    gl->fActiveTexture(texture);
   1.101 +}
   1.102 +
   1.103 +void
   1.104 +WebGLContext::AttachShader(WebGLProgram *program, WebGLShader *shader)
   1.105 +{
   1.106 +    if (IsContextLost())
   1.107 +        return;
   1.108 +
   1.109 +    if (!ValidateObject("attachShader: program", program) ||
   1.110 +        !ValidateObject("attachShader: shader", shader))
   1.111 +        return;
   1.112 +
   1.113 +    // Per GLSL ES 2.0, we can only have one of each type of shader
   1.114 +    // attached.  This renders the next test somewhat moot, but we'll
   1.115 +    // leave it for when we support more than one shader of each type.
   1.116 +    if (program->HasAttachedShaderOfType(shader->ShaderType()))
   1.117 +        return ErrorInvalidOperation("attachShader: only one of each type of shader may be attached to a program");
   1.118 +
   1.119 +    if (!program->AttachShader(shader))
   1.120 +        return ErrorInvalidOperation("attachShader: shader is already attached");
   1.121 +}
   1.122 +
   1.123 +
   1.124 +void
   1.125 +WebGLContext::BindAttribLocation(WebGLProgram *prog, GLuint location,
   1.126 +                                 const nsAString& name)
   1.127 +{
   1.128 +    if (IsContextLost())
   1.129 +        return;
   1.130 +
   1.131 +    if (!ValidateObject("bindAttribLocation: program", prog))
   1.132 +        return;
   1.133 +
   1.134 +    GLuint progname = prog->GLName();
   1.135 +
   1.136 +    if (!ValidateGLSLVariableName(name, "bindAttribLocation"))
   1.137 +        return;
   1.138 +
   1.139 +    if (!ValidateAttribIndex(location, "bindAttribLocation"))
   1.140 +        return;
   1.141 +
   1.142 +    NS_LossyConvertUTF16toASCII cname(name);
   1.143 +    nsCString mappedName;
   1.144 +    prog->MapIdentifier(cname, &mappedName);
   1.145 +
   1.146 +    MakeContextCurrent();
   1.147 +    gl->fBindAttribLocation(progname, location, mappedName.get());
   1.148 +}
   1.149 +
   1.150 +void
   1.151 +WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer *wfb)
   1.152 +{
   1.153 +    if (IsContextLost())
   1.154 +        return;
   1.155 +
   1.156 +    if (target != LOCAL_GL_FRAMEBUFFER)
   1.157 +        return ErrorInvalidEnum("bindFramebuffer: target must be GL_FRAMEBUFFER");
   1.158 +
   1.159 +    if (!ValidateObjectAllowDeletedOrNull("bindFramebuffer", wfb))
   1.160 +        return;
   1.161 +
   1.162 +    // silently ignore a deleted frame buffer
   1.163 +    if (wfb && wfb->IsDeleted())
   1.164 +        return;
   1.165 +
   1.166 +    MakeContextCurrent();
   1.167 +
   1.168 +    if (!wfb) {
   1.169 +        gl->fBindFramebuffer(target, 0);
   1.170 +    } else {
   1.171 +        GLuint framebuffername = wfb->GLName();
   1.172 +        gl->fBindFramebuffer(target, framebuffername);
   1.173 +        wfb->SetHasEverBeenBound(true);
   1.174 +    }
   1.175 +
   1.176 +    mBoundFramebuffer = wfb;
   1.177 +}
   1.178 +
   1.179 +void
   1.180 +WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer *wrb)
   1.181 +{
   1.182 +    if (IsContextLost())
   1.183 +        return;
   1.184 +
   1.185 +    if (target != LOCAL_GL_RENDERBUFFER)
   1.186 +        return ErrorInvalidEnumInfo("bindRenderbuffer: target", target);
   1.187 +
   1.188 +    if (!ValidateObjectAllowDeletedOrNull("bindRenderbuffer", wrb))
   1.189 +        return;
   1.190 +
   1.191 +    // silently ignore a deleted buffer
   1.192 +    if (wrb && wrb->IsDeleted())
   1.193 +        return;
   1.194 +
   1.195 +    if (wrb)
   1.196 +        wrb->SetHasEverBeenBound(true);
   1.197 +
   1.198 +    MakeContextCurrent();
   1.199 +
   1.200 +    // Sometimes we emulate renderbuffers (depth-stencil emu), so there's not
   1.201 +    // always a 1-1 mapping from `wrb` to GL name. Just have `wrb` handle it.
   1.202 +    if (wrb) {
   1.203 +        wrb->BindRenderbuffer();
   1.204 +    } else {
   1.205 +        gl->fBindRenderbuffer(target, 0);
   1.206 +    }
   1.207 +
   1.208 +    mBoundRenderbuffer = wrb;
   1.209 +}
   1.210 +
   1.211 +void
   1.212 +WebGLContext::BindTexture(GLenum target, WebGLTexture *newTex)
   1.213 +{
   1.214 +    if (IsContextLost())
   1.215 +        return;
   1.216 +
   1.217 +     if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex))
   1.218 +        return;
   1.219 +
   1.220 +    // silently ignore a deleted texture
   1.221 +    if (newTex && newTex->IsDeleted())
   1.222 +        return;
   1.223 +
   1.224 +    WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
   1.225 +
   1.226 +    if (target == LOCAL_GL_TEXTURE_2D) {
   1.227 +        currentTexPtr = &mBound2DTextures[mActiveTexture];
   1.228 +    } else if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
   1.229 +        currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
   1.230 +    } else {
   1.231 +        return ErrorInvalidEnumInfo("bindTexture: target", target);
   1.232 +    }
   1.233 +
   1.234 +    WebGLTextureFakeBlackStatus currentTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
   1.235 +    if (*currentTexPtr) {
   1.236 +        currentTexFakeBlackStatus = (*currentTexPtr)->ResolvedFakeBlackStatus();
   1.237 +    }
   1.238 +    WebGLTextureFakeBlackStatus newTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
   1.239 +    if (newTex) {
   1.240 +        newTexFakeBlackStatus = newTex->ResolvedFakeBlackStatus();
   1.241 +    }
   1.242 +
   1.243 +    *currentTexPtr = newTex;
   1.244 +
   1.245 +    if (currentTexFakeBlackStatus != newTexFakeBlackStatus) {
   1.246 +        SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
   1.247 +    }
   1.248 +
   1.249 +    MakeContextCurrent();
   1.250 +
   1.251 +    if (newTex)
   1.252 +        newTex->Bind(target);
   1.253 +    else
   1.254 +        gl->fBindTexture(target, 0 /* == texturename */);
   1.255 +}
   1.256 +
   1.257 +void WebGLContext::BlendEquation(GLenum mode)
   1.258 +{
   1.259 +    if (IsContextLost())
   1.260 +        return;
   1.261 +
   1.262 +    if (!ValidateBlendEquationEnum(mode, "blendEquation: mode"))
   1.263 +        return;
   1.264 +
   1.265 +    MakeContextCurrent();
   1.266 +    gl->fBlendEquation(mode);
   1.267 +}
   1.268 +
   1.269 +void WebGLContext::BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
   1.270 +{
   1.271 +    if (IsContextLost())
   1.272 +        return;
   1.273 +
   1.274 +    if (!ValidateBlendEquationEnum(modeRGB, "blendEquationSeparate: modeRGB") ||
   1.275 +        !ValidateBlendEquationEnum(modeAlpha, "blendEquationSeparate: modeAlpha"))
   1.276 +        return;
   1.277 +
   1.278 +    MakeContextCurrent();
   1.279 +    gl->fBlendEquationSeparate(modeRGB, modeAlpha);
   1.280 +}
   1.281 +
   1.282 +void WebGLContext::BlendFunc(GLenum sfactor, GLenum dfactor)
   1.283 +{
   1.284 +    if (IsContextLost())
   1.285 +        return;
   1.286 +
   1.287 +    if (!ValidateBlendFuncSrcEnum(sfactor, "blendFunc: sfactor") ||
   1.288 +        !ValidateBlendFuncDstEnum(dfactor, "blendFunc: dfactor"))
   1.289 +        return;
   1.290 +
   1.291 +    if (!ValidateBlendFuncEnumsCompatibility(sfactor, dfactor, "blendFuncSeparate: srcRGB and dstRGB"))
   1.292 +        return;
   1.293 +
   1.294 +    MakeContextCurrent();
   1.295 +    gl->fBlendFunc(sfactor, dfactor);
   1.296 +}
   1.297 +
   1.298 +void
   1.299 +WebGLContext::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
   1.300 +                                GLenum srcAlpha, GLenum dstAlpha)
   1.301 +{
   1.302 +    if (IsContextLost())
   1.303 +        return;
   1.304 +
   1.305 +    if (!ValidateBlendFuncSrcEnum(srcRGB, "blendFuncSeparate: srcRGB") ||
   1.306 +        !ValidateBlendFuncSrcEnum(srcAlpha, "blendFuncSeparate: srcAlpha") ||
   1.307 +        !ValidateBlendFuncDstEnum(dstRGB, "blendFuncSeparate: dstRGB") ||
   1.308 +        !ValidateBlendFuncDstEnum(dstAlpha, "blendFuncSeparate: dstAlpha"))
   1.309 +        return;
   1.310 +
   1.311 +    // note that we only check compatibity for the RGB enums, no need to for the Alpha enums, see
   1.312 +    // "Section 6.8 forgetting to mention alpha factors?" thread on the public_webgl mailing list
   1.313 +    if (!ValidateBlendFuncEnumsCompatibility(srcRGB, dstRGB, "blendFuncSeparate: srcRGB and dstRGB"))
   1.314 +        return;
   1.315 +
   1.316 +    MakeContextCurrent();
   1.317 +    gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
   1.318 +}
   1.319 +
   1.320 +GLenum
   1.321 +WebGLContext::CheckFramebufferStatus(GLenum target)
   1.322 +{
   1.323 +    if (IsContextLost())
   1.324 +        return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
   1.325 +
   1.326 +    if (target != LOCAL_GL_FRAMEBUFFER) {
   1.327 +        ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
   1.328 +        return 0;
   1.329 +    }
   1.330 +
   1.331 +    if (!mBoundFramebuffer)
   1.332 +        return LOCAL_GL_FRAMEBUFFER_COMPLETE;
   1.333 +
   1.334 +    return mBoundFramebuffer->CheckFramebufferStatus();
   1.335 +}
   1.336 +
   1.337 +void
   1.338 +WebGLContext::CopyTexSubImage2D_base(GLenum target,
   1.339 +                                     GLint level,
   1.340 +                                     GLenum internalformat,
   1.341 +                                     GLint xoffset,
   1.342 +                                     GLint yoffset,
   1.343 +                                     GLint x,
   1.344 +                                     GLint y,
   1.345 +                                     GLsizei width,
   1.346 +                                     GLsizei height,
   1.347 +                                     bool sub)
   1.348 +{
   1.349 +    const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
   1.350 +    GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
   1.351 +    GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
   1.352 +
   1.353 +    const char* info = sub ? "copyTexSubImage2D" : "copyTexImage2D";
   1.354 +    WebGLTexImageFunc func = sub ? WebGLTexImageFunc::CopyTexSubImage : WebGLTexImageFunc::CopyTexImage;
   1.355 +
   1.356 +    // TODO: This changes with color_buffer_float. Reassess when the
   1.357 +    // patch lands.
   1.358 +    if (!ValidateTexImage(2, target, level, internalformat,
   1.359 +                          xoffset, yoffset, 0,
   1.360 +                          width, height, 0,
   1.361 +                          0, internalformat, LOCAL_GL_UNSIGNED_BYTE,
   1.362 +                          func))
   1.363 +    {
   1.364 +        return;
   1.365 +    }
   1.366 +
   1.367 +    MakeContextCurrent();
   1.368 +
   1.369 +    WebGLTexture *tex = activeBoundTextureForTarget(target);
   1.370 +
   1.371 +    if (!tex)
   1.372 +        return ErrorInvalidOperation("%s: no texture is bound to this target");
   1.373 +
   1.374 +    if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
   1.375 +        if (sub)
   1.376 +            gl->fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
   1.377 +        else
   1.378 +            gl->fCopyTexImage2D(target, level, internalformat, x, y, width, height, 0);
   1.379 +    } else {
   1.380 +
   1.381 +        // the rect doesn't fit in the framebuffer
   1.382 +
   1.383 +        /*** first, we initialize the texture as black ***/
   1.384 +
   1.385 +        // first, compute the size of the buffer we should allocate to initialize the texture as black
   1.386 +
   1.387 +        if (!ValidateTexInputData(LOCAL_GL_UNSIGNED_BYTE, -1, func))
   1.388 +            return;
   1.389 +
   1.390 +        uint32_t texelSize = GetBitsPerTexel(internalformat, LOCAL_GL_UNSIGNED_BYTE) / 8;
   1.391 +
   1.392 +        CheckedUint32 checked_neededByteLength =
   1.393 +            GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
   1.394 +
   1.395 +        if (!checked_neededByteLength.isValid())
   1.396 +            return ErrorInvalidOperation("%s: integer overflow computing the needed buffer size", info);
   1.397 +
   1.398 +        uint32_t bytesNeeded = checked_neededByteLength.value();
   1.399 +
   1.400 +        // now that the size is known, create the buffer
   1.401 +
   1.402 +        // We need some zero pages, because GL doesn't guarantee the
   1.403 +        // contents of a texture allocated with nullptr data.
   1.404 +        // Hopefully calloc will just mmap zero pages here.
   1.405 +        void* tempZeroData = calloc(1, bytesNeeded);
   1.406 +        if (!tempZeroData)
   1.407 +            return ErrorOutOfMemory("%s: could not allocate %d bytes (for zero fill)", info, bytesNeeded);
   1.408 +
   1.409 +        // now initialize the texture as black
   1.410 +
   1.411 +        if (sub)
   1.412 +            gl->fTexSubImage2D(target, level, 0, 0, width, height,
   1.413 +                               internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
   1.414 +        else
   1.415 +            gl->fTexImage2D(target, level, internalformat, width, height,
   1.416 +                            0, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
   1.417 +        free(tempZeroData);
   1.418 +
   1.419 +        // if we are completely outside of the framebuffer, we can exit now with our black texture
   1.420 +        if (   x >= framebufferWidth
   1.421 +            || x+width <= 0
   1.422 +            || y >= framebufferHeight
   1.423 +            || y+height <= 0)
   1.424 +        {
   1.425 +            // we are completely outside of range, can exit now with buffer filled with zeros
   1.426 +            return DummyFramebufferOperation(info);
   1.427 +        }
   1.428 +
   1.429 +        GLint   actual_x             = clamped(x, 0, framebufferWidth);
   1.430 +        GLint   actual_x_plus_width  = clamped(x + width, 0, framebufferWidth);
   1.431 +        GLsizei actual_width   = actual_x_plus_width  - actual_x;
   1.432 +        GLint   actual_xoffset = xoffset + actual_x - x;
   1.433 +
   1.434 +        GLint   actual_y             = clamped(y, 0, framebufferHeight);
   1.435 +        GLint   actual_y_plus_height = clamped(y + height, 0, framebufferHeight);
   1.436 +        GLsizei actual_height  = actual_y_plus_height - actual_y;
   1.437 +        GLint   actual_yoffset = yoffset + actual_y - y;
   1.438 +
   1.439 +        gl->fCopyTexSubImage2D(target, level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height);
   1.440 +    }
   1.441 +}
   1.442 +
   1.443 +void
   1.444 +WebGLContext::CopyTexImage2D(GLenum target,
   1.445 +                             GLint level,
   1.446 +                             GLenum internalformat,
   1.447 +                             GLint x,
   1.448 +                             GLint y,
   1.449 +                             GLsizei width,
   1.450 +                             GLsizei height,
   1.451 +                             GLint border)
   1.452 +{
   1.453 +    if (IsContextLost())
   1.454 +        return;
   1.455 +
   1.456 +    // copyTexImage2D only generates textures with type = UNSIGNED_BYTE
   1.457 +    const WebGLTexImageFunc func = WebGLTexImageFunc::CopyTexImage;
   1.458 +    const GLenum format = internalformat; // WebGL/ES Format
   1.459 +    const GLenum type = LOCAL_GL_UNSIGNED_BYTE; // WebGL/ES Format
   1.460 +
   1.461 +    if (!ValidateTexImage(2, target, level, format,
   1.462 +                          0, 0, 0,
   1.463 +                          width, height, 0,
   1.464 +                          border, format, type,
   1.465 +                          func))
   1.466 +    {
   1.467 +        return;
   1.468 +    }
   1.469 +
   1.470 +    if (mBoundFramebuffer) {
   1.471 +        if (!mBoundFramebuffer->CheckAndInitializeAttachments())
   1.472 +            return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
   1.473 +
   1.474 +        GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
   1.475 +        if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
   1.476 +            return ErrorInvalidOperation("copyTexImage2D: Read source attachment doesn't have the"
   1.477 +                                         " correct color/depth/stencil type.");
   1.478 +        }
   1.479 +    } else {
   1.480 +      ClearBackbufferIfNeeded();
   1.481 +    }
   1.482 +
   1.483 +    bool texFormatRequiresAlpha = format == LOCAL_GL_RGBA ||
   1.484 +                                  format == LOCAL_GL_ALPHA ||
   1.485 +                                  format == LOCAL_GL_LUMINANCE_ALPHA;
   1.486 +    bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
   1.487 +                                               : bool(gl->GetPixelFormat().alpha > 0);
   1.488 +    if (texFormatRequiresAlpha && !fboFormatHasAlpha)
   1.489 +        return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel "
   1.490 +                                     "but the framebuffer doesn't have one");
   1.491 +
   1.492 +    // check if the memory size of this texture may change with this call
   1.493 +    bool sizeMayChange = true;
   1.494 +    WebGLTexture* tex = activeBoundTextureForTarget(target);
   1.495 +    if (tex->HasImageInfoAt(target, level)) {
   1.496 +        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
   1.497 +
   1.498 +        sizeMayChange = width != imageInfo.Width() ||
   1.499 +                        height != imageInfo.Height() ||
   1.500 +                        format != imageInfo.WebGLFormat() ||
   1.501 +                        type != imageInfo.WebGLType();
   1.502 +    }
   1.503 +
   1.504 +    if (sizeMayChange)
   1.505 +        GetAndFlushUnderlyingGLErrors();
   1.506 +
   1.507 +    CopyTexSubImage2D_base(target, level, format, 0, 0, x, y, width, height, false);
   1.508 +
   1.509 +    if (sizeMayChange) {
   1.510 +        GLenum error = GetAndFlushUnderlyingGLErrors();
   1.511 +        if (error) {
   1.512 +            GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
   1.513 +            return;
   1.514 +        }
   1.515 +    }
   1.516 +
   1.517 +    tex->SetImageInfo(target, level, width, height, format, type,
   1.518 +                      WebGLImageDataStatus::InitializedImageData);
   1.519 +}
   1.520 +
   1.521 +void
   1.522 +WebGLContext::CopyTexSubImage2D(GLenum target,
   1.523 +                                GLint level,
   1.524 +                                GLint xoffset,
   1.525 +                                GLint yoffset,
   1.526 +                                GLint x,
   1.527 +                                GLint y,
   1.528 +                                GLsizei width,
   1.529 +                                GLsizei height)
   1.530 +{
   1.531 +    if (IsContextLost())
   1.532 +        return;
   1.533 +
   1.534 +    switch (target) {
   1.535 +        case LOCAL_GL_TEXTURE_2D:
   1.536 +        case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
   1.537 +        case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
   1.538 +        case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
   1.539 +        case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
   1.540 +        case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
   1.541 +        case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
   1.542 +            break;
   1.543 +        default:
   1.544 +            return ErrorInvalidEnumInfo("copyTexSubImage2D: target", target);
   1.545 +    }
   1.546 +
   1.547 +    if (level < 0)
   1.548 +        return ErrorInvalidValue("copyTexSubImage2D: level may not be negative");
   1.549 +
   1.550 +    GLsizei maxTextureSize = MaxTextureSizeForTarget(target);
   1.551 +    if (!(maxTextureSize >> level))
   1.552 +        return ErrorInvalidValue("copyTexSubImage2D: 2^level exceeds maximum texture size");
   1.553 +
   1.554 +    if (width < 0 || height < 0)
   1.555 +        return ErrorInvalidValue("copyTexSubImage2D: width and height may not be negative");
   1.556 +
   1.557 +    if (xoffset < 0 || yoffset < 0)
   1.558 +        return ErrorInvalidValue("copyTexSubImage2D: xoffset and yoffset may not be negative");
   1.559 +
   1.560 +    WebGLTexture *tex = activeBoundTextureForTarget(target);
   1.561 +    if (!tex)
   1.562 +        return ErrorInvalidOperation("copyTexSubImage2D: no texture bound to this target");
   1.563 +
   1.564 +    if (!tex->HasImageInfoAt(target, level))
   1.565 +        return ErrorInvalidOperation("copyTexSubImage2D: no texture image previously defined for this level and face");
   1.566 +
   1.567 +    const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level);
   1.568 +    GLsizei texWidth = imageInfo.Width();
   1.569 +    GLsizei texHeight = imageInfo.Height();
   1.570 +
   1.571 +    if (xoffset + width > texWidth || xoffset + width < 0)
   1.572 +      return ErrorInvalidValue("copyTexSubImage2D: xoffset+width is too large");
   1.573 +
   1.574 +    if (yoffset + height > texHeight || yoffset + height < 0)
   1.575 +      return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
   1.576 +
   1.577 +    GLenum webGLFormat = imageInfo.WebGLFormat();
   1.578 +    if (IsGLDepthFormat(webGLFormat) || IsGLDepthStencilFormat(webGLFormat))
   1.579 +        return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
   1.580 +
   1.581 +    if (mBoundFramebuffer) {
   1.582 +        if (!mBoundFramebuffer->CheckAndInitializeAttachments())
   1.583 +            return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
   1.584 +
   1.585 +        GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
   1.586 +        if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
   1.587 +            return ErrorInvalidOperation("copyTexSubImage2D: Read source attachment doesn't have the"
   1.588 +                                         " correct color/depth/stencil type.");
   1.589 +        }
   1.590 +    } else {
   1.591 +        ClearBackbufferIfNeeded();
   1.592 +    }
   1.593 +
   1.594 +    bool texFormatRequiresAlpha = FormatHasAlpha(webGLFormat);
   1.595 +    bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
   1.596 +                                               : bool(gl->GetPixelFormat().alpha > 0);
   1.597 +
   1.598 +    if (texFormatRequiresAlpha && !fboFormatHasAlpha)
   1.599 +        return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
   1.600 +                                     "but the framebuffer doesn't have one");
   1.601 +
   1.602 +    if (imageInfo.HasUninitializedImageData()) {
   1.603 +        tex->DoDeferredImageInitialization(target, level);
   1.604 +    }
   1.605 +
   1.606 +    return CopyTexSubImage2D_base(target, level, webGLFormat, xoffset, yoffset, x, y, width, height, true);
   1.607 +}
   1.608 +
   1.609 +
   1.610 +already_AddRefed<WebGLProgram>
   1.611 +WebGLContext::CreateProgram()
   1.612 +{
   1.613 +    if (IsContextLost())
   1.614 +        return nullptr;
   1.615 +    nsRefPtr<WebGLProgram> globj = new WebGLProgram(this);
   1.616 +    return globj.forget();
   1.617 +}
   1.618 +
   1.619 +already_AddRefed<WebGLShader>
   1.620 +WebGLContext::CreateShader(GLenum type)
   1.621 +{
   1.622 +    if (IsContextLost())
   1.623 +        return nullptr;
   1.624 +
   1.625 +    if (type != LOCAL_GL_VERTEX_SHADER &&
   1.626 +        type != LOCAL_GL_FRAGMENT_SHADER)
   1.627 +    {
   1.628 +        ErrorInvalidEnumInfo("createShader: type", type);
   1.629 +        return nullptr;
   1.630 +    }
   1.631 +
   1.632 +    nsRefPtr<WebGLShader> shader = new WebGLShader(this, type);
   1.633 +    return shader.forget();
   1.634 +}
   1.635 +
   1.636 +void
   1.637 +WebGLContext::CullFace(GLenum face)
   1.638 +{
   1.639 +    if (IsContextLost())
   1.640 +        return;
   1.641 +
   1.642 +    if (!ValidateFaceEnum(face, "cullFace"))
   1.643 +        return;
   1.644 +
   1.645 +    MakeContextCurrent();
   1.646 +    gl->fCullFace(face);
   1.647 +}
   1.648 +
   1.649 +void
   1.650 +WebGLContext::DeleteFramebuffer(WebGLFramebuffer* fbuf)
   1.651 +{
   1.652 +    if (IsContextLost())
   1.653 +        return;
   1.654 +
   1.655 +    if (!ValidateObjectAllowDeletedOrNull("deleteFramebuffer", fbuf))
   1.656 +        return;
   1.657 +
   1.658 +    if (!fbuf || fbuf->IsDeleted())
   1.659 +        return;
   1.660 +
   1.661 +    fbuf->RequestDelete();
   1.662 +
   1.663 +    if (mBoundFramebuffer == fbuf)
   1.664 +        BindFramebuffer(LOCAL_GL_FRAMEBUFFER,
   1.665 +                        static_cast<WebGLFramebuffer*>(nullptr));
   1.666 +}
   1.667 +
   1.668 +void
   1.669 +WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer *rbuf)
   1.670 +{
   1.671 +    if (IsContextLost())
   1.672 +        return;
   1.673 +
   1.674 +    if (!ValidateObjectAllowDeletedOrNull("deleteRenderbuffer", rbuf))
   1.675 +        return;
   1.676 +
   1.677 +    if (!rbuf || rbuf->IsDeleted())
   1.678 +        return;
   1.679 +
   1.680 +    if (mBoundFramebuffer)
   1.681 +        mBoundFramebuffer->DetachRenderbuffer(rbuf);
   1.682 +
   1.683 +    // Invalidate framebuffer status cache
   1.684 +    rbuf->NotifyFBsStatusChanged();
   1.685 +
   1.686 +    if (mBoundRenderbuffer == rbuf)
   1.687 +        BindRenderbuffer(LOCAL_GL_RENDERBUFFER,
   1.688 +                         static_cast<WebGLRenderbuffer*>(nullptr));
   1.689 +
   1.690 +    rbuf->RequestDelete();
   1.691 +}
   1.692 +
   1.693 +void
   1.694 +WebGLContext::DeleteTexture(WebGLTexture *tex)
   1.695 +{
   1.696 +    if (IsContextLost())
   1.697 +        return;
   1.698 +
   1.699 +    if (!ValidateObjectAllowDeletedOrNull("deleteTexture", tex))
   1.700 +        return;
   1.701 +
   1.702 +    if (!tex || tex->IsDeleted())
   1.703 +        return;
   1.704 +
   1.705 +    if (mBoundFramebuffer)
   1.706 +        mBoundFramebuffer->DetachTexture(tex);
   1.707 +
   1.708 +    // Invalidate framebuffer status cache
   1.709 +    tex->NotifyFBsStatusChanged();
   1.710 +
   1.711 +    GLuint activeTexture = mActiveTexture;
   1.712 +    for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
   1.713 +        if ((tex->Target() == LOCAL_GL_TEXTURE_2D && mBound2DTextures[i] == tex) ||
   1.714 +            (tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP && mBoundCubeMapTextures[i] == tex))
   1.715 +        {
   1.716 +            ActiveTexture(LOCAL_GL_TEXTURE0 + i);
   1.717 +            BindTexture(tex->Target(), static_cast<WebGLTexture*>(nullptr));
   1.718 +        }
   1.719 +    }
   1.720 +    ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture);
   1.721 +
   1.722 +    tex->RequestDelete();
   1.723 +}
   1.724 +
   1.725 +void
   1.726 +WebGLContext::DeleteProgram(WebGLProgram *prog)
   1.727 +{
   1.728 +    if (IsContextLost())
   1.729 +        return;
   1.730 +
   1.731 +    if (!ValidateObjectAllowDeletedOrNull("deleteProgram", prog))
   1.732 +        return;
   1.733 +
   1.734 +    if (!prog || prog->IsDeleted())
   1.735 +        return;
   1.736 +
   1.737 +    prog->RequestDelete();
   1.738 +}
   1.739 +
   1.740 +void
   1.741 +WebGLContext::DeleteShader(WebGLShader *shader)
   1.742 +{
   1.743 +    if (IsContextLost())
   1.744 +        return;
   1.745 +
   1.746 +    if (!ValidateObjectAllowDeletedOrNull("deleteShader", shader))
   1.747 +        return;
   1.748 +
   1.749 +    if (!shader || shader->IsDeleted())
   1.750 +        return;
   1.751 +
   1.752 +    shader->RequestDelete();
   1.753 +}
   1.754 +
   1.755 +void
   1.756 +WebGLContext::DetachShader(WebGLProgram *program, WebGLShader *shader)
   1.757 +{
   1.758 +    if (IsContextLost())
   1.759 +        return;
   1.760 +
   1.761 +    if (!ValidateObject("detachShader: program", program) ||
   1.762 +        // it's valid to attempt to detach a deleted shader, since it's
   1.763 +        // still a shader
   1.764 +        !ValidateObjectAllowDeleted("detashShader: shader", shader))
   1.765 +        return;
   1.766 +
   1.767 +    if (!program->DetachShader(shader))
   1.768 +        return ErrorInvalidOperation("detachShader: shader is not attached");
   1.769 +}
   1.770 +
   1.771 +void
   1.772 +WebGLContext::DepthFunc(GLenum func)
   1.773 +{
   1.774 +    if (IsContextLost())
   1.775 +        return;
   1.776 +
   1.777 +    if (!ValidateComparisonEnum(func, "depthFunc"))
   1.778 +        return;
   1.779 +
   1.780 +    MakeContextCurrent();
   1.781 +    gl->fDepthFunc(func);
   1.782 +}
   1.783 +
   1.784 +void
   1.785 +WebGLContext::DepthRange(GLfloat zNear, GLfloat zFar)
   1.786 +{
   1.787 +    if (IsContextLost())
   1.788 +        return;
   1.789 +
   1.790 +    if (zNear > zFar)
   1.791 +        return ErrorInvalidOperation("depthRange: the near value is greater than the far value!");
   1.792 +
   1.793 +    MakeContextCurrent();
   1.794 +    gl->fDepthRange(zNear, zFar);
   1.795 +}
   1.796 +
   1.797 +void
   1.798 +WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum rbtarget, WebGLRenderbuffer *wrb)
   1.799 +{
   1.800 +    if (IsContextLost())
   1.801 +        return;
   1.802 +
   1.803 +    if (!mBoundFramebuffer)
   1.804 +        return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
   1.805 +
   1.806 +    return mBoundFramebuffer->FramebufferRenderbuffer(target, attachment, rbtarget, wrb);
   1.807 +}
   1.808 +
   1.809 +void
   1.810 +WebGLContext::FramebufferTexture2D(GLenum target,
   1.811 +                                   GLenum attachment,
   1.812 +                                   GLenum textarget,
   1.813 +                                   WebGLTexture *tobj,
   1.814 +                                   GLint level)
   1.815 +{
   1.816 +    if (IsContextLost())
   1.817 +        return;
   1.818 +
   1.819 +    if (!mBoundFramebuffer)
   1.820 +        return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
   1.821 +
   1.822 +    return mBoundFramebuffer->FramebufferTexture2D(target, attachment, textarget, tobj, level);
   1.823 +}
   1.824 +
   1.825 +void
   1.826 +WebGLContext::FrontFace(GLenum mode)
   1.827 +{
   1.828 +    if (IsContextLost())
   1.829 +        return;
   1.830 +
   1.831 +    switch (mode) {
   1.832 +        case LOCAL_GL_CW:
   1.833 +        case LOCAL_GL_CCW:
   1.834 +            break;
   1.835 +        default:
   1.836 +            return ErrorInvalidEnumInfo("frontFace: mode", mode);
   1.837 +    }
   1.838 +
   1.839 +    MakeContextCurrent();
   1.840 +    gl->fFrontFace(mode);
   1.841 +}
   1.842 +
   1.843 +already_AddRefed<WebGLActiveInfo>
   1.844 +WebGLContext::GetActiveAttrib(WebGLProgram *prog, uint32_t index)
   1.845 +{
   1.846 +    if (IsContextLost())
   1.847 +        return nullptr;
   1.848 +
   1.849 +    if (!ValidateObject("getActiveAttrib: program", prog))
   1.850 +        return nullptr;
   1.851 +
   1.852 +    MakeContextCurrent();
   1.853 +
   1.854 +    GLint len = 0;
   1.855 +    GLuint progname = prog->GLName();;
   1.856 +    gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len);
   1.857 +    if (len == 0)
   1.858 +        return nullptr;
   1.859 +
   1.860 +    nsAutoArrayPtr<char> name(new char[len]);
   1.861 +    GLint attrsize = 0;
   1.862 +    GLuint attrtype = 0;
   1.863 +
   1.864 +    gl->fGetActiveAttrib(progname, index, len, &len, &attrsize, &attrtype, name);
   1.865 +    if (attrsize == 0 || attrtype == 0) {
   1.866 +        return nullptr;
   1.867 +    }
   1.868 +
   1.869 +    nsCString reverseMappedName;
   1.870 +    prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
   1.871 +
   1.872 +    nsRefPtr<WebGLActiveInfo> retActiveInfo =
   1.873 +        new WebGLActiveInfo(attrsize, attrtype, reverseMappedName);
   1.874 +    return retActiveInfo.forget();
   1.875 +}
   1.876 +
   1.877 +void
   1.878 +WebGLContext::GenerateMipmap(GLenum target)
   1.879 +{
   1.880 +    if (IsContextLost())
   1.881 +        return;
   1.882 +
   1.883 +    if (!ValidateTextureTargetEnum(target, "generateMipmap"))
   1.884 +        return;
   1.885 +
   1.886 +    WebGLTexture *tex = activeBoundTextureForTarget(target);
   1.887 +
   1.888 +    if (!tex)
   1.889 +        return ErrorInvalidOperation("generateMipmap: No texture is bound to this target.");
   1.890 +
   1.891 +    GLenum imageTarget = (target == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_2D
   1.892 +                                                         : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
   1.893 +    if (!tex->HasImageInfoAt(imageTarget, 0))
   1.894 +    {
   1.895 +        return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
   1.896 +    }
   1.897 +
   1.898 +    if (!tex->IsFirstImagePowerOfTwo())
   1.899 +        return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
   1.900 +
   1.901 +    GLenum webGLFormat = tex->ImageInfoAt(imageTarget, 0).WebGLFormat();
   1.902 +    if (IsTextureFormatCompressed(webGLFormat))
   1.903 +        return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
   1.904 +
   1.905 +    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
   1.906 +        (IsGLDepthFormat(webGLFormat) || IsGLDepthStencilFormat(webGLFormat)))
   1.907 +    {
   1.908 +        return ErrorInvalidOperation("generateMipmap: "
   1.909 +                                     "A texture that has a base internal format of "
   1.910 +                                     "DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
   1.911 +    }
   1.912 +
   1.913 +    if (!tex->AreAllLevel0ImageInfosEqual())
   1.914 +        return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");
   1.915 +
   1.916 +    tex->SetGeneratedMipmap();
   1.917 +
   1.918 +    MakeContextCurrent();
   1.919 +
   1.920 +    if (gl->WorkAroundDriverBugs()) {
   1.921 +        // bug 696495 - to work around failures in the texture-mips.html test on various drivers, we
   1.922 +        // set the minification filter before calling glGenerateMipmap. This should not carry a significant performance
   1.923 +        // overhead so we do it unconditionally.
   1.924 +        //
   1.925 +        // note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105.
   1.926 +        gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST_MIPMAP_NEAREST);
   1.927 +        gl->fGenerateMipmap(target);
   1.928 +        gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, tex->MinFilter());
   1.929 +    } else {
   1.930 +        gl->fGenerateMipmap(target);
   1.931 +    }
   1.932 +}
   1.933 +
   1.934 +already_AddRefed<WebGLActiveInfo>
   1.935 +WebGLContext::GetActiveUniform(WebGLProgram *prog, uint32_t index)
   1.936 +{
   1.937 +    if (IsContextLost())
   1.938 +        return nullptr;
   1.939 +
   1.940 +    if (!ValidateObject("getActiveUniform: program", prog))
   1.941 +        return nullptr;
   1.942 +
   1.943 +    MakeContextCurrent();
   1.944 +
   1.945 +    GLint len = 0;
   1.946 +    GLuint progname = prog->GLName();
   1.947 +    gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &len);
   1.948 +    if (len == 0)
   1.949 +        return nullptr;
   1.950 +
   1.951 +    nsAutoArrayPtr<char> name(new char[len]);
   1.952 +
   1.953 +    GLint usize = 0;
   1.954 +    GLuint utype = 0;
   1.955 +
   1.956 +    gl->fGetActiveUniform(progname, index, len, &len, &usize, &utype, name);
   1.957 +    if (len == 0 || usize == 0 || utype == 0) {
   1.958 +        return nullptr;
   1.959 +    }
   1.960 +
   1.961 +    nsCString reverseMappedName;
   1.962 +    prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
   1.963 +
   1.964 +    // OpenGL ES 2.0 specifies that if foo is a uniform array, GetActiveUniform returns its name as "foo[0]".
   1.965 +    // See section 2.10 page 35 in the OpenGL ES 2.0.24 specification:
   1.966 +    //
   1.967 +    // > If the active uniform is an array, the uniform name returned in name will always
   1.968 +    // > be the name of the uniform array appended with "[0]".
   1.969 +    //
   1.970 +    // There is no such requirement in the OpenGL (non-ES) spec and indeed we have OpenGL implementations returning
   1.971 +    // "foo" instead of "foo[0]". So, when implementing WebGL on top of desktop OpenGL, we must check if the
   1.972 +    // returned name ends in [0], and if it doesn't, append that.
   1.973 +    //
   1.974 +    // In principle we don't need to do that on OpenGL ES, but this is such a tricky difference between the ES and non-ES
   1.975 +    // specs that it seems probable that some ES implementers will overlook it. Since the work-around is quite cheap,
   1.976 +    // we do it unconditionally.
   1.977 +    if (usize > 1 && reverseMappedName.CharAt(reverseMappedName.Length()-1) != ']')
   1.978 +        reverseMappedName.AppendLiteral("[0]");
   1.979 +
   1.980 +    nsRefPtr<WebGLActiveInfo> retActiveInfo =
   1.981 +        new WebGLActiveInfo(usize, utype, reverseMappedName);
   1.982 +    return retActiveInfo.forget();
   1.983 +}
   1.984 +
   1.985 +void
   1.986 +WebGLContext::GetAttachedShaders(WebGLProgram *prog,
   1.987 +                                 Nullable< nsTArray<WebGLShader*> > &retval)
   1.988 +{
   1.989 +    retval.SetNull();
   1.990 +    if (IsContextLost())
   1.991 +        return;
   1.992 +
   1.993 +    if (!ValidateObjectAllowNull("getAttachedShaders", prog))
   1.994 +        return;
   1.995 +
   1.996 +    MakeContextCurrent();
   1.997 +
   1.998 +    if (!prog) {
   1.999 +        retval.SetNull();
  1.1000 +        ErrorInvalidValue("getAttachedShaders: invalid program");
  1.1001 +    } else if (prog->AttachedShaders().Length() == 0) {
  1.1002 +        retval.SetValue().TruncateLength(0);
  1.1003 +    } else {
  1.1004 +        retval.SetValue().AppendElements(prog->AttachedShaders());
  1.1005 +    }
  1.1006 +}
  1.1007 +
  1.1008 +GLint
  1.1009 +WebGLContext::GetAttribLocation(WebGLProgram *prog, const nsAString& name)
  1.1010 +{
  1.1011 +    if (IsContextLost())
  1.1012 +        return -1;
  1.1013 +
  1.1014 +    if (!ValidateObject("getAttribLocation: program", prog))
  1.1015 +        return -1;
  1.1016 +
  1.1017 +    if (!ValidateGLSLVariableName(name, "getAttribLocation"))
  1.1018 +        return -1;
  1.1019 +
  1.1020 +    NS_LossyConvertUTF16toASCII cname(name);
  1.1021 +    nsCString mappedName;
  1.1022 +    prog->MapIdentifier(cname, &mappedName);
  1.1023 +
  1.1024 +    GLuint progname = prog->GLName();
  1.1025 +
  1.1026 +    MakeContextCurrent();
  1.1027 +    return gl->fGetAttribLocation(progname, mappedName.get());
  1.1028 +}
  1.1029 +
  1.1030 +JS::Value
  1.1031 +WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
  1.1032 +{
  1.1033 +    if (IsContextLost())
  1.1034 +        return JS::NullValue();
  1.1035 +
  1.1036 +    if (target != LOCAL_GL_ARRAY_BUFFER && target != LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
  1.1037 +        ErrorInvalidEnumInfo("getBufferParameter: target", target);
  1.1038 +        return JS::NullValue();
  1.1039 +    }
  1.1040 +
  1.1041 +    MakeContextCurrent();
  1.1042 +
  1.1043 +    switch (pname) {
  1.1044 +        case LOCAL_GL_BUFFER_SIZE:
  1.1045 +        case LOCAL_GL_BUFFER_USAGE:
  1.1046 +        {
  1.1047 +            GLint i = 0;
  1.1048 +            gl->fGetBufferParameteriv(target, pname, &i);
  1.1049 +            if (pname == LOCAL_GL_BUFFER_SIZE) {
  1.1050 +                return JS::Int32Value(i);
  1.1051 +            }
  1.1052 +
  1.1053 +            MOZ_ASSERT(pname == LOCAL_GL_BUFFER_USAGE);
  1.1054 +            return JS::NumberValue(uint32_t(i));
  1.1055 +        }
  1.1056 +            break;
  1.1057 +
  1.1058 +        default:
  1.1059 +            ErrorInvalidEnumInfo("getBufferParameter: parameter", pname);
  1.1060 +    }
  1.1061 +
  1.1062 +    return JS::NullValue();
  1.1063 +}
  1.1064 +
  1.1065 +JS::Value
  1.1066 +WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx,
  1.1067 +                                                GLenum target,
  1.1068 +                                                GLenum attachment,
  1.1069 +                                                GLenum pname,
  1.1070 +                                                ErrorResult& rv)
  1.1071 +{
  1.1072 +    if (IsContextLost())
  1.1073 +        return JS::NullValue();
  1.1074 +
  1.1075 +    if (target != LOCAL_GL_FRAMEBUFFER) {
  1.1076 +        ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: target", target);
  1.1077 +        return JS::NullValue();
  1.1078 +    }
  1.1079 +
  1.1080 +    if (!mBoundFramebuffer) {
  1.1081 +        ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query framebuffer 0");
  1.1082 +        return JS::NullValue();
  1.1083 +    }
  1.1084 +
  1.1085 +    if (attachment != LOCAL_GL_DEPTH_ATTACHMENT &&
  1.1086 +        attachment != LOCAL_GL_STENCIL_ATTACHMENT &&
  1.1087 +        attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
  1.1088 +    {
  1.1089 +        if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
  1.1090 +        {
  1.1091 +            if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
  1.1092 +                attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mGLMaxColorAttachments))
  1.1093 +            {
  1.1094 +                ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: attachment", attachment);
  1.1095 +                return JS::NullValue();
  1.1096 +            }
  1.1097 +
  1.1098 +            mBoundFramebuffer->EnsureColorAttachments(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
  1.1099 +        }
  1.1100 +        else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0)
  1.1101 +        {
  1.1102 +            ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: attachment", attachment);
  1.1103 +            return JS::NullValue();
  1.1104 +        }
  1.1105 +    }
  1.1106 +
  1.1107 +    MakeContextCurrent();
  1.1108 +
  1.1109 +    const WebGLFramebuffer::Attachment& fba = mBoundFramebuffer->GetAttachment(attachment);
  1.1110 +
  1.1111 +    if (fba.Renderbuffer()) {
  1.1112 +        switch (pname) {
  1.1113 +            case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
  1.1114 +                if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
  1.1115 +                    const GLenum internalFormat = fba.Renderbuffer()->InternalFormat();
  1.1116 +                    return (internalFormat == LOCAL_GL_SRGB_EXT ||
  1.1117 +                            internalFormat == LOCAL_GL_SRGB_ALPHA_EXT ||
  1.1118 +                            internalFormat == LOCAL_GL_SRGB8_ALPHA8_EXT) ?
  1.1119 +                        JS::NumberValue(uint32_t(LOCAL_GL_SRGB_EXT)) :
  1.1120 +                        JS::NumberValue(uint32_t(LOCAL_GL_LINEAR));
  1.1121 +                }
  1.1122 +                break;
  1.1123 +
  1.1124 +            case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
  1.1125 +                return JS::NumberValue(uint32_t(LOCAL_GL_RENDERBUFFER));
  1.1126 +
  1.1127 +            case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
  1.1128 +                return WebGLObjectAsJSValue(cx, fba.Renderbuffer(), rv);
  1.1129 +
  1.1130 +            case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: {
  1.1131 +                if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) &&
  1.1132 +                    !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
  1.1133 +                {
  1.1134 +                    break;
  1.1135 +                }
  1.1136 +
  1.1137 +                if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
  1.1138 +                    ErrorInvalidOperation("getFramebufferAttachmentParameter: Cannot get component"
  1.1139 +                                          " type of a depth-stencil attachment.");
  1.1140 +                    return JS::NullValue();
  1.1141 +                }
  1.1142 +
  1.1143 +                if (!fba.IsComplete())
  1.1144 +                    return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
  1.1145 +
  1.1146 +                uint32_t ret = LOCAL_GL_NONE;
  1.1147 +                switch (fba.Renderbuffer()->InternalFormat()) {
  1.1148 +                case LOCAL_GL_RGBA4:
  1.1149 +                case LOCAL_GL_RGB5_A1:
  1.1150 +                case LOCAL_GL_RGB565:
  1.1151 +                case LOCAL_GL_SRGB8_ALPHA8:
  1.1152 +                    ret = LOCAL_GL_UNSIGNED_NORMALIZED;
  1.1153 +                    break;
  1.1154 +                case LOCAL_GL_RGB16F:
  1.1155 +                case LOCAL_GL_RGBA16F:
  1.1156 +                case LOCAL_GL_RGB32F:
  1.1157 +                case LOCAL_GL_RGBA32F:
  1.1158 +                    ret = LOCAL_GL_FLOAT;
  1.1159 +                    break;
  1.1160 +                case LOCAL_GL_DEPTH_COMPONENT16:
  1.1161 +                case LOCAL_GL_STENCIL_INDEX8:
  1.1162 +                    ret = LOCAL_GL_UNSIGNED_INT;
  1.1163 +                    break;
  1.1164 +                default:
  1.1165 +                    MOZ_ASSERT(false, "Unhandled RB component type.");
  1.1166 +                    break;
  1.1167 +                }
  1.1168 +                return JS::NumberValue(uint32_t(ret));
  1.1169 +            }
  1.1170 +        }
  1.1171 +
  1.1172 +        ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
  1.1173 +        return JS::NullValue();
  1.1174 +    } else if (fba.Texture()) {
  1.1175 +        switch (pname) {
  1.1176 +             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
  1.1177 +                if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
  1.1178 +                    const GLenum webGLFormat =
  1.1179 +                        fba.Texture()->ImageInfoBase().WebGLFormat();
  1.1180 +                    return (webGLFormat == LOCAL_GL_SRGB ||
  1.1181 +                            webGLFormat == LOCAL_GL_SRGB_ALPHA) ?
  1.1182 +                        JS::NumberValue(uint32_t(LOCAL_GL_SRGB)) :
  1.1183 +                        JS::NumberValue(uint32_t(LOCAL_GL_LINEAR));
  1.1184 +                }
  1.1185 +                break;
  1.1186 +
  1.1187 +            case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
  1.1188 +                return JS::NumberValue(uint32_t(LOCAL_GL_TEXTURE));
  1.1189 +
  1.1190 +            case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
  1.1191 +                return WebGLObjectAsJSValue(cx, fba.Texture(), rv);
  1.1192 +
  1.1193 +            case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
  1.1194 +                return JS::Int32Value(fba.TexImageLevel());
  1.1195 +
  1.1196 +            case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: {
  1.1197 +                GLenum face = fba.TexImageTarget();
  1.1198 +                if (face == LOCAL_GL_TEXTURE_2D)
  1.1199 +                    face = 0;
  1.1200 +                return JS::Int32Value(face);
  1.1201 +            }
  1.1202 +
  1.1203 +            case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: {
  1.1204 +                if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) &&
  1.1205 +                    !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
  1.1206 +                {
  1.1207 +                    break;
  1.1208 +                }
  1.1209 +
  1.1210 +                if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
  1.1211 +                    ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot component"
  1.1212 +                                          " type of depth-stencil attachments.");
  1.1213 +                    return JS::NullValue();
  1.1214 +                }
  1.1215 +
  1.1216 +                if (!fba.IsComplete())
  1.1217 +                    return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
  1.1218 +
  1.1219 +                uint32_t ret = LOCAL_GL_NONE;
  1.1220 +                GLenum type = fba.Texture()->ImageInfoAt(fba.TexImageTarget(),
  1.1221 +                                                         fba.TexImageLevel()).WebGLType();
  1.1222 +                switch (type) {
  1.1223 +                case LOCAL_GL_UNSIGNED_BYTE:
  1.1224 +                case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
  1.1225 +                case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
  1.1226 +                case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
  1.1227 +                    ret = LOCAL_GL_UNSIGNED_NORMALIZED;
  1.1228 +                    break;
  1.1229 +                case LOCAL_GL_FLOAT:
  1.1230 +                case LOCAL_GL_HALF_FLOAT_OES:
  1.1231 +                    ret = LOCAL_GL_FLOAT;
  1.1232 +                    break;
  1.1233 +                case LOCAL_GL_UNSIGNED_SHORT:
  1.1234 +                case LOCAL_GL_UNSIGNED_INT:
  1.1235 +                    ret = LOCAL_GL_UNSIGNED_INT;
  1.1236 +                    break;
  1.1237 +                default:
  1.1238 +                    MOZ_ASSERT(false, "Unhandled RB component type.");
  1.1239 +                    break;
  1.1240 +                }
  1.1241 +                return JS::NumberValue(uint32_t(ret));
  1.1242 +            }
  1.1243 +        }
  1.1244 +
  1.1245 +        ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
  1.1246 +        return JS::NullValue();
  1.1247 +    } else {
  1.1248 +        switch (pname) {
  1.1249 +            case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
  1.1250 +                return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
  1.1251 +
  1.1252 +            default:
  1.1253 +                ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
  1.1254 +                return JS::NullValue();
  1.1255 +        }
  1.1256 +    }
  1.1257 +
  1.1258 +    return JS::NullValue();
  1.1259 +}
  1.1260 +
  1.1261 +JS::Value
  1.1262 +WebGLContext::GetRenderbufferParameter(GLenum target, GLenum pname)
  1.1263 +{
  1.1264 +    if (IsContextLost())
  1.1265 +        return JS::NullValue();
  1.1266 +
  1.1267 +    if (target != LOCAL_GL_RENDERBUFFER) {
  1.1268 +        ErrorInvalidEnumInfo("getRenderbufferParameter: target", target);
  1.1269 +        return JS::NullValue();
  1.1270 +    }
  1.1271 +
  1.1272 +    if (!mBoundRenderbuffer) {
  1.1273 +        ErrorInvalidOperation("getRenderbufferParameter: no render buffer is bound");
  1.1274 +        return JS::NullValue();
  1.1275 +    }
  1.1276 +
  1.1277 +    MakeContextCurrent();
  1.1278 +
  1.1279 +    switch (pname) {
  1.1280 +        case LOCAL_GL_RENDERBUFFER_WIDTH:
  1.1281 +        case LOCAL_GL_RENDERBUFFER_HEIGHT:
  1.1282 +        case LOCAL_GL_RENDERBUFFER_RED_SIZE:
  1.1283 +        case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
  1.1284 +        case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
  1.1285 +        case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
  1.1286 +        case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
  1.1287 +        case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
  1.1288 +        {
  1.1289 +            // RB emulation means we have to ask the RB itself.
  1.1290 +            GLint i = mBoundRenderbuffer->GetRenderbufferParameter(target, pname);
  1.1291 +            return JS::Int32Value(i);
  1.1292 +        }
  1.1293 +        case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
  1.1294 +        {
  1.1295 +            return JS::NumberValue(mBoundRenderbuffer->InternalFormat());
  1.1296 +        }
  1.1297 +        default:
  1.1298 +            ErrorInvalidEnumInfo("getRenderbufferParameter: parameter", pname);
  1.1299 +    }
  1.1300 +
  1.1301 +    return JS::NullValue();
  1.1302 +}
  1.1303 +
  1.1304 +already_AddRefed<WebGLTexture>
  1.1305 +WebGLContext::CreateTexture()
  1.1306 +{
  1.1307 +    if (IsContextLost())
  1.1308 +        return nullptr;
  1.1309 +    nsRefPtr<WebGLTexture> globj = new WebGLTexture(this);
  1.1310 +    return globj.forget();
  1.1311 +}
  1.1312 +
  1.1313 +static GLenum
  1.1314 +GetAndClearError(GLenum* errorVar)
  1.1315 +{
  1.1316 +    MOZ_ASSERT(errorVar);
  1.1317 +    GLenum ret = *errorVar;
  1.1318 +    *errorVar = LOCAL_GL_NO_ERROR;
  1.1319 +    return ret;
  1.1320 +}
  1.1321 +
  1.1322 +GLenum
  1.1323 +WebGLContext::GetError()
  1.1324 +{
  1.1325 +    /* WebGL 1.0: Section 5.14.3: Setting and getting state:
  1.1326 +     *   If the context's webgl context lost flag is set, returns
  1.1327 +     *   CONTEXT_LOST_WEBGL the first time this method is called.
  1.1328 +     *   Afterward, returns NO_ERROR until the context has been
  1.1329 +     *   restored.
  1.1330 +     *
  1.1331 +     * WEBGL_lose_context:
  1.1332 +     *   [When this extension is enabled: ] loseContext and
  1.1333 +     *   restoreContext are allowed to generate INVALID_OPERATION errors
  1.1334 +     *   even when the context is lost.
  1.1335 +     */
  1.1336 +
  1.1337 +    if (IsContextLost()) {
  1.1338 +        if (mEmitContextLostErrorOnce) {
  1.1339 +            mEmitContextLostErrorOnce = false;
  1.1340 +            return LOCAL_GL_CONTEXT_LOST;
  1.1341 +        }
  1.1342 +        // Don't return yet, since WEBGL_lose_contexts contradicts the
  1.1343 +        // original spec, and allows error generation while lost.
  1.1344 +    }
  1.1345 +
  1.1346 +    GLenum err = GetAndClearError(&mWebGLError);
  1.1347 +    if (err != LOCAL_GL_NO_ERROR)
  1.1348 +        return err;
  1.1349 +
  1.1350 +    if (IsContextLost())
  1.1351 +        return LOCAL_GL_NO_ERROR;
  1.1352 +
  1.1353 +    // Either no WebGL-side error, or it's already been cleared.
  1.1354 +    // UnderlyingGL-side errors, now.
  1.1355 +
  1.1356 +    MakeContextCurrent();
  1.1357 +    GetAndFlushUnderlyingGLErrors();
  1.1358 +
  1.1359 +    err = GetAndClearError(&mUnderlyingGLError);
  1.1360 +    return err;
  1.1361 +}
  1.1362 +
  1.1363 +JS::Value
  1.1364 +WebGLContext::GetProgramParameter(WebGLProgram *prog, GLenum pname)
  1.1365 +{
  1.1366 +    if (IsContextLost())
  1.1367 +        return JS::NullValue();
  1.1368 +
  1.1369 +    if (!ValidateObjectAllowDeleted("getProgramParameter: program", prog))
  1.1370 +        return JS::NullValue();
  1.1371 +
  1.1372 +    GLuint progname = prog->GLName();
  1.1373 +
  1.1374 +    MakeContextCurrent();
  1.1375 +
  1.1376 +    switch (pname) {
  1.1377 +        case LOCAL_GL_ATTACHED_SHADERS:
  1.1378 +        case LOCAL_GL_ACTIVE_UNIFORMS:
  1.1379 +        case LOCAL_GL_ACTIVE_ATTRIBUTES:
  1.1380 +        {
  1.1381 +            GLint i = 0;
  1.1382 +            gl->fGetProgramiv(progname, pname, &i);
  1.1383 +            return JS::Int32Value(i);
  1.1384 +        }
  1.1385 +        case LOCAL_GL_DELETE_STATUS:
  1.1386 +            return JS::BooleanValue(prog->IsDeleteRequested());
  1.1387 +        case LOCAL_GL_LINK_STATUS:
  1.1388 +        {
  1.1389 +            return JS::BooleanValue(prog->LinkStatus());
  1.1390 +        }
  1.1391 +        case LOCAL_GL_VALIDATE_STATUS:
  1.1392 +        {
  1.1393 +            GLint i = 0;
  1.1394 +#ifdef XP_MACOSX
  1.1395 +            // See comment in ValidateProgram below.
  1.1396 +            if (gl->WorkAroundDriverBugs())
  1.1397 +                i = 1;
  1.1398 +            else
  1.1399 +                gl->fGetProgramiv(progname, pname, &i);
  1.1400 +#else
  1.1401 +            gl->fGetProgramiv(progname, pname, &i);
  1.1402 +#endif
  1.1403 +            return JS::BooleanValue(bool(i));
  1.1404 +        }
  1.1405 +            break;
  1.1406 +
  1.1407 +        default:
  1.1408 +            ErrorInvalidEnumInfo("getProgramParameter: parameter", pname);
  1.1409 +    }
  1.1410 +
  1.1411 +    return JS::NullValue();
  1.1412 +}
  1.1413 +
  1.1414 +void
  1.1415 +WebGLContext::GetProgramInfoLog(WebGLProgram *prog, nsAString& retval)
  1.1416 +{
  1.1417 +    nsAutoCString s;
  1.1418 +    GetProgramInfoLog(prog, s);
  1.1419 +    if (s.IsVoid())
  1.1420 +        retval.SetIsVoid(true);
  1.1421 +    else
  1.1422 +        CopyASCIItoUTF16(s, retval);
  1.1423 +}
  1.1424 +
  1.1425 +void
  1.1426 +WebGLContext::GetProgramInfoLog(WebGLProgram *prog, nsACString& retval)
  1.1427 +{
  1.1428 +    if (IsContextLost())
  1.1429 +    {
  1.1430 +        retval.SetIsVoid(true);
  1.1431 +        return;
  1.1432 +    }
  1.1433 +
  1.1434 +    if (!ValidateObject("getProgramInfoLog: program", prog)) {
  1.1435 +        retval.Truncate();
  1.1436 +        return;
  1.1437 +    }
  1.1438 +
  1.1439 +    GLuint progname = prog->GLName();
  1.1440 +
  1.1441 +    MakeContextCurrent();
  1.1442 +
  1.1443 +    GLint k = -1;
  1.1444 +    gl->fGetProgramiv(progname, LOCAL_GL_INFO_LOG_LENGTH, &k);
  1.1445 +    if (k == -1) {
  1.1446 +        // If GetProgramiv doesn't modify |k|,
  1.1447 +        // it's because there was a GL error.
  1.1448 +        // GetProgramInfoLog should return null on error. (Bug 746740)
  1.1449 +        retval.SetIsVoid(true);
  1.1450 +        return;
  1.1451 +    }
  1.1452 +
  1.1453 +    if (k == 0) {
  1.1454 +        retval.Truncate();
  1.1455 +        return;
  1.1456 +    }
  1.1457 +
  1.1458 +    retval.SetCapacity(k);
  1.1459 +    gl->fGetProgramInfoLog(progname, k, &k, (char*) retval.BeginWriting());
  1.1460 +    retval.SetLength(k);
  1.1461 +}
  1.1462 +
  1.1463 +// here we have to support all pnames with both int and float params.
  1.1464 +// See this discussion:
  1.1465 +//  https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
  1.1466 +void WebGLContext::TexParameter_base(GLenum target, GLenum pname,
  1.1467 +                                     GLint *intParamPtr,
  1.1468 +                                     GLfloat *floatParamPtr)
  1.1469 +{
  1.1470 +    MOZ_ASSERT(intParamPtr || floatParamPtr);
  1.1471 +
  1.1472 +    if (IsContextLost())
  1.1473 +        return;
  1.1474 +
  1.1475 +    GLint intParam = intParamPtr ? *intParamPtr : GLint(*floatParamPtr);
  1.1476 +    GLfloat floatParam = floatParamPtr ? *floatParamPtr : GLfloat(*intParamPtr);
  1.1477 +
  1.1478 +    if (!ValidateTextureTargetEnum(target, "texParameter: target"))
  1.1479 +        return;
  1.1480 +
  1.1481 +    WebGLTexture *tex = activeBoundTextureForTarget(target);
  1.1482 +    if (!tex)
  1.1483 +        return ErrorInvalidOperation("texParameter: no texture is bound to this target");
  1.1484 +
  1.1485 +    bool pnameAndParamAreIncompatible = false;
  1.1486 +    bool paramValueInvalid = false;
  1.1487 +
  1.1488 +    switch (pname) {
  1.1489 +        case LOCAL_GL_TEXTURE_MIN_FILTER:
  1.1490 +            switch (intParam) {
  1.1491 +                case LOCAL_GL_NEAREST:
  1.1492 +                case LOCAL_GL_LINEAR:
  1.1493 +                case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
  1.1494 +                case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
  1.1495 +                case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
  1.1496 +                case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
  1.1497 +                    tex->SetMinFilter(intParam);
  1.1498 +                    break;
  1.1499 +                default:
  1.1500 +                    pnameAndParamAreIncompatible = true;
  1.1501 +            }
  1.1502 +            break;
  1.1503 +        case LOCAL_GL_TEXTURE_MAG_FILTER:
  1.1504 +            switch (intParam) {
  1.1505 +                case LOCAL_GL_NEAREST:
  1.1506 +                case LOCAL_GL_LINEAR:
  1.1507 +                    tex->SetMagFilter(intParam);
  1.1508 +                    break;
  1.1509 +                default:
  1.1510 +                    pnameAndParamAreIncompatible = true;
  1.1511 +            }
  1.1512 +            break;
  1.1513 +        case LOCAL_GL_TEXTURE_WRAP_S:
  1.1514 +            switch (intParam) {
  1.1515 +                case LOCAL_GL_CLAMP_TO_EDGE:
  1.1516 +                case LOCAL_GL_MIRRORED_REPEAT:
  1.1517 +                case LOCAL_GL_REPEAT:
  1.1518 +                    tex->SetWrapS(intParam);
  1.1519 +                    break;
  1.1520 +                default:
  1.1521 +                    pnameAndParamAreIncompatible = true;
  1.1522 +            }
  1.1523 +            break;
  1.1524 +        case LOCAL_GL_TEXTURE_WRAP_T:
  1.1525 +            switch (intParam) {
  1.1526 +                case LOCAL_GL_CLAMP_TO_EDGE:
  1.1527 +                case LOCAL_GL_MIRRORED_REPEAT:
  1.1528 +                case LOCAL_GL_REPEAT:
  1.1529 +                    tex->SetWrapT(intParam);
  1.1530 +                    break;
  1.1531 +                default:
  1.1532 +                    pnameAndParamAreIncompatible = true;
  1.1533 +            }
  1.1534 +            break;
  1.1535 +        case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
  1.1536 +            if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
  1.1537 +                if (floatParamPtr && floatParam < 1.f)
  1.1538 +                    paramValueInvalid = true;
  1.1539 +                else if (intParamPtr && intParam < 1)
  1.1540 +                    paramValueInvalid = true;
  1.1541 +            }
  1.1542 +            else
  1.1543 +                pnameAndParamAreIncompatible = true;
  1.1544 +            break;
  1.1545 +        default:
  1.1546 +            return ErrorInvalidEnumInfo("texParameter: pname", pname);
  1.1547 +    }
  1.1548 +
  1.1549 +    if (pnameAndParamAreIncompatible) {
  1.1550 +        if (intParamPtr)
  1.1551 +            return ErrorInvalidEnum("texParameteri: pname %x and param %x (decimal %d) are mutually incompatible",
  1.1552 +                                    pname, intParam, intParam);
  1.1553 +        else
  1.1554 +            return ErrorInvalidEnum("texParameterf: pname %x and param %g are mutually incompatible",
  1.1555 +                                    pname, floatParam);
  1.1556 +    } else if (paramValueInvalid) {
  1.1557 +        if (intParamPtr)
  1.1558 +            return ErrorInvalidValue("texParameteri: pname %x and param %x (decimal %d) is invalid",
  1.1559 +                                    pname, intParam, intParam);
  1.1560 +        else
  1.1561 +            return ErrorInvalidValue("texParameterf: pname %x and param %g is invalid",
  1.1562 +                                    pname, floatParam);
  1.1563 +    }
  1.1564 +
  1.1565 +    MakeContextCurrent();
  1.1566 +    if (intParamPtr)
  1.1567 +        gl->fTexParameteri(target, pname, intParam);
  1.1568 +    else
  1.1569 +        gl->fTexParameterf(target, pname, floatParam);
  1.1570 +}
  1.1571 +
  1.1572 +JS::Value
  1.1573 +WebGLContext::GetTexParameter(GLenum target, GLenum pname)
  1.1574 +{
  1.1575 +    if (IsContextLost())
  1.1576 +        return JS::NullValue();
  1.1577 +
  1.1578 +    MakeContextCurrent();
  1.1579 +
  1.1580 +    if (!ValidateTextureTargetEnum(target, "getTexParameter: target"))
  1.1581 +        return JS::NullValue();
  1.1582 +
  1.1583 +    if (!activeBoundTextureForTarget(target)) {
  1.1584 +        ErrorInvalidOperation("getTexParameter: no texture bound");
  1.1585 +        return JS::NullValue();
  1.1586 +    }
  1.1587 +
  1.1588 +    switch (pname) {
  1.1589 +        case LOCAL_GL_TEXTURE_MIN_FILTER:
  1.1590 +        case LOCAL_GL_TEXTURE_MAG_FILTER:
  1.1591 +        case LOCAL_GL_TEXTURE_WRAP_S:
  1.1592 +        case LOCAL_GL_TEXTURE_WRAP_T:
  1.1593 +        {
  1.1594 +            GLint i = 0;
  1.1595 +            gl->fGetTexParameteriv(target, pname, &i);
  1.1596 +            return JS::NumberValue(uint32_t(i));
  1.1597 +        }
  1.1598 +        case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
  1.1599 +            if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
  1.1600 +                GLfloat f = 0.f;
  1.1601 +                gl->fGetTexParameterfv(target, pname, &f);
  1.1602 +                return JS::DoubleValue(f);
  1.1603 +            }
  1.1604 +
  1.1605 +            ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
  1.1606 +            break;
  1.1607 +
  1.1608 +        default:
  1.1609 +            ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
  1.1610 +    }
  1.1611 +
  1.1612 +    return JS::NullValue();
  1.1613 +}
  1.1614 +
  1.1615 +JS::Value
  1.1616 +WebGLContext::GetUniform(JSContext* cx, WebGLProgram *prog,
  1.1617 +                         WebGLUniformLocation *location)
  1.1618 +{
  1.1619 +    if (IsContextLost())
  1.1620 +        return JS::NullValue();
  1.1621 +
  1.1622 +    if (!ValidateObject("getUniform: program", prog))
  1.1623 +        return JS::NullValue();
  1.1624 +
  1.1625 +    if (!ValidateObject("getUniform: location", location))
  1.1626 +        return JS::NullValue();
  1.1627 +
  1.1628 +    if (location->Program() != prog) {
  1.1629 +        ErrorInvalidValue("getUniform: this uniform location corresponds to another program");
  1.1630 +        return JS::NullValue();
  1.1631 +    }
  1.1632 +
  1.1633 +    if (location->ProgramGeneration() != prog->Generation()) {
  1.1634 +        ErrorInvalidOperation("getUniform: this uniform location is obsolete since the program has been relinked");
  1.1635 +        return JS::NullValue();
  1.1636 +    }
  1.1637 +
  1.1638 +    GLuint progname = prog->GLName();
  1.1639 +
  1.1640 +    MakeContextCurrent();
  1.1641 +
  1.1642 +    GLint uniforms = 0;
  1.1643 +    GLint uniformNameMaxLength = 0;
  1.1644 +    gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORMS, &uniforms);
  1.1645 +    gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformNameMaxLength);
  1.1646 +
  1.1647 +    // we now need the type info to switch between fGetUniformfv and fGetUniformiv
  1.1648 +    // the only way to get that is to iterate through all active uniforms by index until
  1.1649 +    // one matches the given uniform location.
  1.1650 +    GLenum uniformType = 0;
  1.1651 +    nsAutoArrayPtr<GLchar> uniformName(new GLchar[uniformNameMaxLength]);
  1.1652 +    // this buffer has 16 more bytes to be able to store [index] at the end.
  1.1653 +    nsAutoArrayPtr<GLchar> uniformNameBracketIndex(new GLchar[uniformNameMaxLength + 16]);
  1.1654 +
  1.1655 +    GLint index;
  1.1656 +    for (index = 0; index < uniforms; ++index) {
  1.1657 +        GLsizei length;
  1.1658 +        GLint size;
  1.1659 +        gl->fGetActiveUniform(progname, index, uniformNameMaxLength, &length,
  1.1660 +                              &size, &uniformType, uniformName);
  1.1661 +        if (gl->fGetUniformLocation(progname, uniformName) == location->Location())
  1.1662 +            break;
  1.1663 +
  1.1664 +        // now we handle the case of array uniforms. In that case, fGetActiveUniform returned as 'size'
  1.1665 +        // the biggest index used plus one, so we need to loop over that. The 0 index has already been handled above,
  1.1666 +        // so we can start at one. For each index, we construct the string uniformName + "[" + index + "]".
  1.1667 +        if (size > 1) {
  1.1668 +            bool found_it = false;
  1.1669 +            if (uniformName[length - 1] == ']') { // if uniformName ends in [0]
  1.1670 +                // remove the [0] at the end
  1.1671 +                length -= 3;
  1.1672 +                uniformName[length] = 0;
  1.1673 +            }
  1.1674 +            for (GLint arrayIndex = 1; arrayIndex < size; arrayIndex++) {
  1.1675 +                sprintf(uniformNameBracketIndex.get(), "%s[%d]", uniformName.get(), arrayIndex);
  1.1676 +                if (gl->fGetUniformLocation(progname, uniformNameBracketIndex) == location->Location()) {
  1.1677 +                    found_it = true;
  1.1678 +                    break;
  1.1679 +                }
  1.1680 +            }
  1.1681 +            if (found_it) break;
  1.1682 +        }
  1.1683 +    }
  1.1684 +
  1.1685 +    if (index == uniforms) {
  1.1686 +        GenerateWarning("getUniform: internal error: hit an OpenGL driver bug");
  1.1687 +        return JS::NullValue();
  1.1688 +    }
  1.1689 +
  1.1690 +    GLenum baseType;
  1.1691 +    GLint unitSize;
  1.1692 +    if (!BaseTypeAndSizeFromUniformType(uniformType, &baseType, &unitSize)) {
  1.1693 +        GenerateWarning("getUniform: internal error: unknown uniform type 0x%x", uniformType);
  1.1694 +        return JS::NullValue();
  1.1695 +    }
  1.1696 +
  1.1697 +    // this should never happen
  1.1698 +    if (unitSize > 16) {
  1.1699 +        GenerateWarning("getUniform: internal error: unexpected uniform unit size %d", unitSize);
  1.1700 +        return JS::NullValue();
  1.1701 +    }
  1.1702 +
  1.1703 +    if (baseType == LOCAL_GL_FLOAT) {
  1.1704 +        GLfloat fv[16] = { GLfloat(0) };
  1.1705 +        gl->fGetUniformfv(progname, location->Location(), fv);
  1.1706 +        if (unitSize == 1) {
  1.1707 +            return JS::DoubleValue(fv[0]);
  1.1708 +        } else {
  1.1709 +            JSObject* obj = Float32Array::Create(cx, this, unitSize, fv);
  1.1710 +            if (!obj) {
  1.1711 +                ErrorOutOfMemory("getUniform: out of memory");
  1.1712 +                return JS::NullValue();
  1.1713 +            }
  1.1714 +            return JS::ObjectOrNullValue(obj);
  1.1715 +        }
  1.1716 +    } else if (baseType == LOCAL_GL_INT) {
  1.1717 +        GLint iv[16] = { 0 };
  1.1718 +        gl->fGetUniformiv(progname, location->Location(), iv);
  1.1719 +        if (unitSize == 1) {
  1.1720 +            return JS::Int32Value(iv[0]);
  1.1721 +        } else {
  1.1722 +            JSObject* obj = Int32Array::Create(cx, this, unitSize, iv);
  1.1723 +            if (!obj) {
  1.1724 +                ErrorOutOfMemory("getUniform: out of memory");
  1.1725 +                return JS::NullValue();
  1.1726 +            }
  1.1727 +            return JS::ObjectOrNullValue(obj);
  1.1728 +        }
  1.1729 +    } else if (baseType == LOCAL_GL_BOOL) {
  1.1730 +        GLint iv[16] = { 0 };
  1.1731 +        gl->fGetUniformiv(progname, location->Location(), iv);
  1.1732 +        if (unitSize == 1) {
  1.1733 +            return JS::BooleanValue(iv[0] ? true : false);
  1.1734 +        } else {
  1.1735 +            bool uv[16];
  1.1736 +            for (int k = 0; k < unitSize; k++)
  1.1737 +                uv[k] = iv[k];
  1.1738 +            JS::Rooted<JS::Value> val(cx);
  1.1739 +            // Be careful: we don't want to convert all of |uv|!
  1.1740 +            if (!ToJSValue(cx, uv, unitSize, &val)) {
  1.1741 +                ErrorOutOfMemory("getUniform: out of memory");
  1.1742 +                return JS::NullValue();
  1.1743 +            }
  1.1744 +            return val;
  1.1745 +        }
  1.1746 +    }
  1.1747 +
  1.1748 +    // Else preserving behavior, but I'm not sure this is correct per spec
  1.1749 +    return JS::UndefinedValue();
  1.1750 +}
  1.1751 +
  1.1752 +already_AddRefed<WebGLUniformLocation>
  1.1753 +WebGLContext::GetUniformLocation(WebGLProgram *prog, const nsAString& name)
  1.1754 +{
  1.1755 +    if (IsContextLost())
  1.1756 +        return nullptr;
  1.1757 +
  1.1758 +    if (!ValidateObject("getUniformLocation: program", prog))
  1.1759 +        return nullptr;
  1.1760 +
  1.1761 +    if (!ValidateGLSLVariableName(name, "getUniformLocation"))
  1.1762 +        return nullptr;
  1.1763 +
  1.1764 +    NS_LossyConvertUTF16toASCII cname(name);
  1.1765 +    nsCString mappedName;
  1.1766 +    prog->MapIdentifier(cname, &mappedName);
  1.1767 +
  1.1768 +    GLuint progname = prog->GLName();
  1.1769 +    MakeContextCurrent();
  1.1770 +    GLint intlocation = gl->fGetUniformLocation(progname, mappedName.get());
  1.1771 +
  1.1772 +    nsRefPtr<WebGLUniformLocation> loc;
  1.1773 +    if (intlocation >= 0) {
  1.1774 +        WebGLUniformInfo info = prog->GetUniformInfoForMappedIdentifier(mappedName);
  1.1775 +        loc = new WebGLUniformLocation(this,
  1.1776 +                                       prog,
  1.1777 +                                       intlocation,
  1.1778 +                                       info);
  1.1779 +    }
  1.1780 +    return loc.forget();
  1.1781 +}
  1.1782 +
  1.1783 +void
  1.1784 +WebGLContext::Hint(GLenum target, GLenum mode)
  1.1785 +{
  1.1786 +    if (IsContextLost())
  1.1787 +        return;
  1.1788 +
  1.1789 +    bool isValid = false;
  1.1790 +
  1.1791 +    switch (target) {
  1.1792 +        case LOCAL_GL_GENERATE_MIPMAP_HINT:
  1.1793 +            isValid = true;
  1.1794 +            break;
  1.1795 +        case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
  1.1796 +            if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
  1.1797 +                isValid = true;
  1.1798 +            break;
  1.1799 +    }
  1.1800 +
  1.1801 +    if (!isValid)
  1.1802 +        return ErrorInvalidEnum("hint: invalid hint");
  1.1803 +
  1.1804 +    MakeContextCurrent();
  1.1805 +    gl->fHint(target, mode);
  1.1806 +}
  1.1807 +
  1.1808 +bool
  1.1809 +WebGLContext::IsFramebuffer(WebGLFramebuffer *fb)
  1.1810 +{
  1.1811 +    if (IsContextLost())
  1.1812 +        return false;
  1.1813 +
  1.1814 +    return ValidateObjectAllowDeleted("isFramebuffer", fb) &&
  1.1815 +        !fb->IsDeleted() &&
  1.1816 +        fb->HasEverBeenBound();
  1.1817 +}
  1.1818 +
  1.1819 +bool
  1.1820 +WebGLContext::IsProgram(WebGLProgram *prog)
  1.1821 +{
  1.1822 +    if (IsContextLost())
  1.1823 +        return false;
  1.1824 +
  1.1825 +    return ValidateObjectAllowDeleted("isProgram", prog) && !prog->IsDeleted();
  1.1826 +}
  1.1827 +
  1.1828 +bool
  1.1829 +WebGLContext::IsRenderbuffer(WebGLRenderbuffer *rb)
  1.1830 +{
  1.1831 +    if (IsContextLost())
  1.1832 +        return false;
  1.1833 +
  1.1834 +    return ValidateObjectAllowDeleted("isRenderBuffer", rb) &&
  1.1835 +        !rb->IsDeleted() &&
  1.1836 +        rb->HasEverBeenBound();
  1.1837 +}
  1.1838 +
  1.1839 +bool
  1.1840 +WebGLContext::IsShader(WebGLShader *shader)
  1.1841 +{
  1.1842 +    if (IsContextLost())
  1.1843 +        return false;
  1.1844 +
  1.1845 +    return ValidateObjectAllowDeleted("isShader", shader) &&
  1.1846 +        !shader->IsDeleted();
  1.1847 +}
  1.1848 +
  1.1849 +bool
  1.1850 +WebGLContext::IsTexture(WebGLTexture *tex)
  1.1851 +{
  1.1852 +    if (IsContextLost())
  1.1853 +        return false;
  1.1854 +
  1.1855 +    return ValidateObjectAllowDeleted("isTexture", tex) &&
  1.1856 +        !tex->IsDeleted() &&
  1.1857 +        tex->HasEverBeenBound();
  1.1858 +}
  1.1859 +
  1.1860 +// Try to bind an attribute that is an array to location 0:
  1.1861 +bool WebGLContext::BindArrayAttribToLocation0(WebGLProgram *program)
  1.1862 +{
  1.1863 +    if (mBoundVertexArray->IsAttribArrayEnabled(0)) {
  1.1864 +        return false;
  1.1865 +    }
  1.1866 +
  1.1867 +    GLint leastArrayLocation = -1;
  1.1868 +
  1.1869 +    std::map<GLint, nsCString>::iterator itr;
  1.1870 +    for (itr = program->mActiveAttribMap.begin();
  1.1871 +         itr != program->mActiveAttribMap.end();
  1.1872 +         itr++) {
  1.1873 +        int32_t index = itr->first;
  1.1874 +        if (mBoundVertexArray->IsAttribArrayEnabled(index) &&
  1.1875 +            index < leastArrayLocation)
  1.1876 +        {
  1.1877 +            leastArrayLocation = index;
  1.1878 +        }
  1.1879 +    }
  1.1880 +
  1.1881 +    if (leastArrayLocation > 0) {
  1.1882 +        nsCString& attrName = program->mActiveAttribMap.find(leastArrayLocation)->second;
  1.1883 +        const char* attrNameCStr = attrName.get();
  1.1884 +        gl->fBindAttribLocation(program->GLName(), 0, attrNameCStr);
  1.1885 +        return true;
  1.1886 +    }
  1.1887 +    return false;
  1.1888 +}
  1.1889 +
  1.1890 +void
  1.1891 +WebGLContext::LinkProgram(WebGLProgram *program)
  1.1892 +{
  1.1893 +    if (IsContextLost())
  1.1894 +        return;
  1.1895 +
  1.1896 +    if (!ValidateObject("linkProgram", program))
  1.1897 +        return;
  1.1898 +
  1.1899 +    InvalidateBufferFetching(); // we do it early in this function
  1.1900 +    // as some of the validation below changes program state
  1.1901 +
  1.1902 +    GLuint progname = program->GLName();
  1.1903 +
  1.1904 +    if (!program->NextGeneration()) {
  1.1905 +        // XXX throw?
  1.1906 +        return;
  1.1907 +    }
  1.1908 +
  1.1909 +    if (!program->HasBothShaderTypesAttached()) {
  1.1910 +        GenerateWarning("linkProgram: this program doesn't have both a vertex shader"
  1.1911 +                        " and a fragment shader");
  1.1912 +        program->SetLinkStatus(false);
  1.1913 +        return;
  1.1914 +    }
  1.1915 +
  1.1916 +    // bug 777028
  1.1917 +    // Mesa can't handle more than 16 samplers per program, counting each array entry.
  1.1918 +    if (gl->WorkAroundDriverBugs() &&
  1.1919 +        mIsMesa &&
  1.1920 +        program->UpperBoundNumSamplerUniforms() > 16)
  1.1921 +    {
  1.1922 +        GenerateWarning("Programs with more than 16 samplers are disallowed on Mesa drivers " "to avoid a Mesa crasher.");
  1.1923 +        program->SetLinkStatus(false);
  1.1924 +        return;
  1.1925 +    }
  1.1926 +
  1.1927 +    bool updateInfoSucceeded = false;
  1.1928 +    GLint ok = 0;
  1.1929 +    if (gl->WorkAroundDriverBugs() &&
  1.1930 +        program->HasBadShaderAttached())
  1.1931 +    {
  1.1932 +        // it's a common driver bug, caught by program-test.html, that linkProgram doesn't
  1.1933 +        // correctly preserve the state of an in-use program that has been attached a bad shader
  1.1934 +        // see bug 777883
  1.1935 +        ok = false;
  1.1936 +    } else {
  1.1937 +        MakeContextCurrent();
  1.1938 +        gl->fLinkProgram(progname);
  1.1939 +        gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok);
  1.1940 +
  1.1941 +        if (ok) {
  1.1942 +            updateInfoSucceeded = program->UpdateInfo();
  1.1943 +            program->SetLinkStatus(updateInfoSucceeded);
  1.1944 +
  1.1945 +            if (BindArrayAttribToLocation0(program)) {
  1.1946 +                GenerateWarning("linkProgram: relinking program to make attrib0 an "
  1.1947 +                                "array.");
  1.1948 +                gl->fLinkProgram(progname);
  1.1949 +                gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok);
  1.1950 +                if (ok) {
  1.1951 +                    updateInfoSucceeded = program->UpdateInfo();
  1.1952 +                    program->SetLinkStatus(updateInfoSucceeded);
  1.1953 +                }
  1.1954 +            }
  1.1955 +        }
  1.1956 +    }
  1.1957 +
  1.1958 +    if (ok) {
  1.1959 +        // Bug 750527
  1.1960 +        if (gl->WorkAroundDriverBugs() &&
  1.1961 +            updateInfoSucceeded &&
  1.1962 +            gl->Vendor() == gl::GLVendor::NVIDIA)
  1.1963 +        {
  1.1964 +            if (program == mCurrentProgram)
  1.1965 +                gl->fUseProgram(progname);
  1.1966 +        }
  1.1967 +    } else {
  1.1968 +        program->SetLinkStatus(false);
  1.1969 +
  1.1970 +        if (ShouldGenerateWarnings()) {
  1.1971 +
  1.1972 +            // report shader/program infoLogs as warnings.
  1.1973 +            // note that shader compilation errors can be deferred to linkProgram,
  1.1974 +            // which is why we can't do anything in compileShader. In practice we could
  1.1975 +            // report in compileShader the translation errors generated by ANGLE,
  1.1976 +            // but it seems saner to keep a single way of obtaining shader infologs.
  1.1977 +
  1.1978 +            nsAutoCString log;
  1.1979 +
  1.1980 +            bool alreadyReportedShaderInfoLog = false;
  1.1981 +
  1.1982 +            for (size_t i = 0; i < program->AttachedShaders().Length(); i++) {
  1.1983 +
  1.1984 +                WebGLShader* shader = program->AttachedShaders()[i];
  1.1985 +
  1.1986 +                if (shader->CompileStatus())
  1.1987 +                    continue;
  1.1988 +
  1.1989 +                const char *shaderTypeName = nullptr;
  1.1990 +                if (shader->ShaderType() == LOCAL_GL_VERTEX_SHADER) {
  1.1991 +                    shaderTypeName = "vertex";
  1.1992 +                } else if (shader->ShaderType() == LOCAL_GL_FRAGMENT_SHADER) {
  1.1993 +                    shaderTypeName = "fragment";
  1.1994 +                } else {
  1.1995 +                    // should have been validated earlier
  1.1996 +                    MOZ_ASSERT(false);
  1.1997 +                    shaderTypeName = "<unknown>";
  1.1998 +                }
  1.1999 +
  1.2000 +                GetShaderInfoLog(shader, log);
  1.2001 +
  1.2002 +                GenerateWarning("linkProgram: a %s shader used in this program failed to "
  1.2003 +                                "compile, with this log:\n%s\n",
  1.2004 +                                shaderTypeName,
  1.2005 +                                log.get());
  1.2006 +                alreadyReportedShaderInfoLog = true;
  1.2007 +            }
  1.2008 +
  1.2009 +            if (!alreadyReportedShaderInfoLog) {
  1.2010 +                GetProgramInfoLog(program, log);
  1.2011 +                if (!log.IsEmpty()) {
  1.2012 +                    GenerateWarning("linkProgram failed, with this log:\n%s\n",
  1.2013 +                                    log.get());
  1.2014 +                }
  1.2015 +            }
  1.2016 +        }
  1.2017 +    }
  1.2018 +}
  1.2019 +
  1.2020 +void
  1.2021 +WebGLContext::PixelStorei(GLenum pname, GLint param)
  1.2022 +{
  1.2023 +    if (IsContextLost())
  1.2024 +        return;
  1.2025 +
  1.2026 +    switch (pname) {
  1.2027 +        case UNPACK_FLIP_Y_WEBGL:
  1.2028 +            mPixelStoreFlipY = (param != 0);
  1.2029 +            break;
  1.2030 +        case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
  1.2031 +            mPixelStorePremultiplyAlpha = (param != 0);
  1.2032 +            break;
  1.2033 +        case UNPACK_COLORSPACE_CONVERSION_WEBGL:
  1.2034 +            if (param == LOCAL_GL_NONE || param == BROWSER_DEFAULT_WEBGL)
  1.2035 +                mPixelStoreColorspaceConversion = param;
  1.2036 +            else
  1.2037 +                return ErrorInvalidEnumInfo("pixelStorei: colorspace conversion parameter", param);
  1.2038 +            break;
  1.2039 +        case LOCAL_GL_PACK_ALIGNMENT:
  1.2040 +        case LOCAL_GL_UNPACK_ALIGNMENT:
  1.2041 +            if (param != 1 &&
  1.2042 +                param != 2 &&
  1.2043 +                param != 4 &&
  1.2044 +                param != 8)
  1.2045 +                return ErrorInvalidValue("pixelStorei: invalid pack/unpack alignment value");
  1.2046 +            if (pname == LOCAL_GL_PACK_ALIGNMENT)
  1.2047 +                mPixelStorePackAlignment = param;
  1.2048 +            else if (pname == LOCAL_GL_UNPACK_ALIGNMENT)
  1.2049 +                mPixelStoreUnpackAlignment = param;
  1.2050 +            MakeContextCurrent();
  1.2051 +            gl->fPixelStorei(pname, param);
  1.2052 +            break;
  1.2053 +        default:
  1.2054 +            return ErrorInvalidEnumInfo("pixelStorei: parameter", pname);
  1.2055 +    }
  1.2056 +}
  1.2057 +
  1.2058 +void
  1.2059 +WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
  1.2060 +                         GLsizei height, GLenum format,
  1.2061 +                         GLenum type, const Nullable<ArrayBufferView> &pixels,
  1.2062 +                         ErrorResult& rv)
  1.2063 +{
  1.2064 +    if (IsContextLost())
  1.2065 +        return;
  1.2066 +
  1.2067 +    if (mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome()) {
  1.2068 +        GenerateWarning("readPixels: Not allowed");
  1.2069 +        return rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.2070 +    }
  1.2071 +
  1.2072 +    if (width < 0 || height < 0)
  1.2073 +        return ErrorInvalidValue("readPixels: negative size passed");
  1.2074 +
  1.2075 +    if (pixels.IsNull())
  1.2076 +        return ErrorInvalidValue("readPixels: null destination buffer");
  1.2077 +
  1.2078 +    const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
  1.2079 +    GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
  1.2080 +    GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
  1.2081 +
  1.2082 +    uint32_t channels = 0;
  1.2083 +
  1.2084 +    // Check the format param
  1.2085 +    switch (format) {
  1.2086 +        case LOCAL_GL_ALPHA:
  1.2087 +            channels = 1;
  1.2088 +            break;
  1.2089 +        case LOCAL_GL_RGB:
  1.2090 +            channels = 3;
  1.2091 +            break;
  1.2092 +        case LOCAL_GL_RGBA:
  1.2093 +            channels = 4;
  1.2094 +            break;
  1.2095 +        default:
  1.2096 +            return ErrorInvalidEnum("readPixels: Bad format");
  1.2097 +    }
  1.2098 +
  1.2099 +    uint32_t bytesPerPixel = 0;
  1.2100 +    int requiredDataType = 0;
  1.2101 +
  1.2102 +    // Check the type param
  1.2103 +    bool isReadTypeValid = false;
  1.2104 +    bool isReadTypeFloat = false;
  1.2105 +    switch (type) {
  1.2106 +        case LOCAL_GL_UNSIGNED_BYTE:
  1.2107 +            isReadTypeValid = true;
  1.2108 +            bytesPerPixel = 1*channels;
  1.2109 +            requiredDataType = js::ArrayBufferView::TYPE_UINT8;
  1.2110 +            break;
  1.2111 +        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
  1.2112 +        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
  1.2113 +        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
  1.2114 +            isReadTypeValid = true;
  1.2115 +            bytesPerPixel = 2;
  1.2116 +            requiredDataType = js::ArrayBufferView::TYPE_UINT16;
  1.2117 +            break;
  1.2118 +        case LOCAL_GL_FLOAT:
  1.2119 +            if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float) ||
  1.2120 +                IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float))
  1.2121 +            {
  1.2122 +                isReadTypeValid = true;
  1.2123 +                isReadTypeFloat = true;
  1.2124 +                bytesPerPixel = 4*channels;
  1.2125 +                requiredDataType = js::ArrayBufferView::TYPE_FLOAT32;
  1.2126 +            }
  1.2127 +            break;
  1.2128 +    }
  1.2129 +    if (!isReadTypeValid)
  1.2130 +        return ErrorInvalidEnum("readPixels: Bad type", type);
  1.2131 +
  1.2132 +    const ArrayBufferView& pixbuf = pixels.Value();
  1.2133 +    int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
  1.2134 +
  1.2135 +    // Check the pixels param type
  1.2136 +    if (dataType != requiredDataType)
  1.2137 +        return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
  1.2138 +
  1.2139 +    // Check the pixels param size
  1.2140 +    CheckedUint32 checked_neededByteLength =
  1.2141 +        GetImageSize(height, width, bytesPerPixel, mPixelStorePackAlignment);
  1.2142 +
  1.2143 +    CheckedUint32 checked_plainRowSize = CheckedUint32(width) * bytesPerPixel;
  1.2144 +
  1.2145 +    CheckedUint32 checked_alignedRowSize =
  1.2146 +        RoundedToNextMultipleOf(checked_plainRowSize, mPixelStorePackAlignment);
  1.2147 +
  1.2148 +    if (!checked_neededByteLength.isValid())
  1.2149 +        return ErrorInvalidOperation("readPixels: integer overflow computing the needed buffer size");
  1.2150 +
  1.2151 +    // Compute length and data.  Don't reenter after this point, lest the
  1.2152 +    // precomputed go out of sync with the instant length/data.
  1.2153 +    pixbuf.ComputeLengthAndData();
  1.2154 +
  1.2155 +    uint32_t dataByteLen = pixbuf.Length();
  1.2156 +    if (checked_neededByteLength.value() > dataByteLen)
  1.2157 +        return ErrorInvalidOperation("readPixels: buffer too small");
  1.2158 +
  1.2159 +    void* data = pixbuf.Data();
  1.2160 +    if (!data) {
  1.2161 +        ErrorOutOfMemory("readPixels: buffer storage is null. Did we run out of memory?");
  1.2162 +        return rv.Throw(NS_ERROR_OUT_OF_MEMORY);
  1.2163 +    }
  1.2164 +
  1.2165 +    bool isSourceTypeFloat = false;
  1.2166 +    if (mBoundFramebuffer &&
  1.2167 +        mBoundFramebuffer->ColorAttachmentCount() &&
  1.2168 +        mBoundFramebuffer->ColorAttachment(0).IsDefined())
  1.2169 +    {
  1.2170 +        isSourceTypeFloat = mBoundFramebuffer->ColorAttachment(0).IsReadableFloat();
  1.2171 +    }
  1.2172 +
  1.2173 +    if (isReadTypeFloat != isSourceTypeFloat)
  1.2174 +        return ErrorInvalidOperation("readPixels: Invalid type floatness");
  1.2175 +
  1.2176 +    // Check the format and type params to assure they are an acceptable pair (as per spec)
  1.2177 +    switch (format) {
  1.2178 +        case LOCAL_GL_RGBA: {
  1.2179 +            switch (type) {
  1.2180 +                case LOCAL_GL_UNSIGNED_BYTE:
  1.2181 +                    break;
  1.2182 +                case LOCAL_GL_FLOAT:
  1.2183 +                    break;
  1.2184 +                default:
  1.2185 +                    return ErrorInvalidOperation("readPixels: Invalid format/type pair");
  1.2186 +            }
  1.2187 +            break;
  1.2188 +        }
  1.2189 +        default:
  1.2190 +            return ErrorInvalidOperation("readPixels: Invalid format/type pair");
  1.2191 +    }
  1.2192 +
  1.2193 +    MakeContextCurrent();
  1.2194 +
  1.2195 +    if (mBoundFramebuffer) {
  1.2196 +        // prevent readback of arbitrary video memory through uninitialized renderbuffers!
  1.2197 +        if (!mBoundFramebuffer->CheckAndInitializeAttachments())
  1.2198 +            return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
  1.2199 +
  1.2200 +        GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
  1.2201 +        if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
  1.2202 +            return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
  1.2203 +                                         " correct color/depth/stencil type.");
  1.2204 +        }
  1.2205 +    } else {
  1.2206 +      ClearBackbufferIfNeeded();
  1.2207 +    }
  1.2208 +    // Now that the errors are out of the way, on to actually reading
  1.2209 +
  1.2210 +    // If we won't be reading any pixels anyways, just skip the actual reading
  1.2211 +    if (width == 0 || height == 0)
  1.2212 +        return DummyFramebufferOperation("readPixels");
  1.2213 +
  1.2214 +    if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
  1.2215 +        // the easy case: we're not reading out-of-range pixels
  1.2216 +        gl->fReadPixels(x, y, width, height, format, type, data);
  1.2217 +    } else {
  1.2218 +        // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
  1.2219 +        // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
  1.2220 +        // to do that for us, because passing out of range parameters to a buggy OpenGL implementation
  1.2221 +        // could conceivably allow to read memory we shouldn't be allowed to read. So we manually initialize
  1.2222 +        // the buffer to zero and compute the parameters to pass to OpenGL. We have to use an intermediate buffer
  1.2223 +        // to accomodate the potentially different strides (widths).
  1.2224 +
  1.2225 +        // Zero the whole pixel dest area in the destination buffer.
  1.2226 +        memset(data, 0, checked_neededByteLength.value());
  1.2227 +
  1.2228 +        if (   x >= framebufferWidth
  1.2229 +            || x+width <= 0
  1.2230 +            || y >= framebufferHeight
  1.2231 +            || y+height <= 0)
  1.2232 +        {
  1.2233 +            // we are completely outside of range, can exit now with buffer filled with zeros
  1.2234 +            return DummyFramebufferOperation("readPixels");
  1.2235 +        }
  1.2236 +
  1.2237 +        // compute the parameters of the subrect we're actually going to call glReadPixels on
  1.2238 +        GLint   subrect_x      = std::max(x, 0);
  1.2239 +        GLint   subrect_end_x  = std::min(x+width, framebufferWidth);
  1.2240 +        GLsizei subrect_width  = subrect_end_x - subrect_x;
  1.2241 +
  1.2242 +        GLint   subrect_y      = std::max(y, 0);
  1.2243 +        GLint   subrect_end_y  = std::min(y+height, framebufferHeight);
  1.2244 +        GLsizei subrect_height = subrect_end_y - subrect_y;
  1.2245 +
  1.2246 +        if (subrect_width < 0 || subrect_height < 0 ||
  1.2247 +            subrect_width > width || subrect_height > height)
  1.2248 +            return ErrorInvalidOperation("readPixels: integer overflow computing clipped rect size");
  1.2249 +
  1.2250 +        // now we know that subrect_width is in the [0..width] interval, and same for heights.
  1.2251 +
  1.2252 +        // now, same computation as above to find the size of the intermediate buffer to allocate for the subrect
  1.2253 +        // no need to check again for integer overflow here, since we already know the sizes aren't greater than before
  1.2254 +        uint32_t subrect_plainRowSize = subrect_width * bytesPerPixel;
  1.2255 +    // There are checks above to ensure that this doesn't overflow.
  1.2256 +        uint32_t subrect_alignedRowSize =
  1.2257 +            RoundedToNextMultipleOf(subrect_plainRowSize, mPixelStorePackAlignment).value();
  1.2258 +        uint32_t subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize;
  1.2259 +
  1.2260 +        // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
  1.2261 +        GLubyte *subrect_data = new GLubyte[subrect_byteLength];
  1.2262 +        gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height, format, type, subrect_data);
  1.2263 +
  1.2264 +        // notice that this for loop terminates because we already checked that subrect_height is at most height
  1.2265 +        for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
  1.2266 +            GLint subrect_x_in_dest_buffer = subrect_x - x;
  1.2267 +            GLint subrect_y_in_dest_buffer = subrect_y - y;
  1.2268 +            memcpy(static_cast<GLubyte*>(data)
  1.2269 +                     + checked_alignedRowSize.value() * (subrect_y_in_dest_buffer + y_inside_subrect)
  1.2270 +                     + bytesPerPixel * subrect_x_in_dest_buffer, // destination
  1.2271 +                   subrect_data + subrect_alignedRowSize * y_inside_subrect, // source
  1.2272 +                   subrect_plainRowSize); // size
  1.2273 +        }
  1.2274 +        delete [] subrect_data;
  1.2275 +    }
  1.2276 +
  1.2277 +    // if we're reading alpha, we may need to do fixup.  Note that we don't allow
  1.2278 +    // GL_ALPHA to readpixels currently, but we had the code written for it already.
  1.2279 +    if (format == LOCAL_GL_ALPHA ||
  1.2280 +        format == LOCAL_GL_RGBA)
  1.2281 +    {
  1.2282 +        bool needAlphaFixup;
  1.2283 +        if (mBoundFramebuffer) {
  1.2284 +            needAlphaFixup = !mBoundFramebuffer->ColorAttachment(0).HasAlpha();
  1.2285 +        } else {
  1.2286 +            needAlphaFixup = gl->GetPixelFormat().alpha == 0;
  1.2287 +        }
  1.2288 +
  1.2289 +        if (needAlphaFixup) {
  1.2290 +            if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) {
  1.2291 +                // this is easy; it's an 0xff memset per row
  1.2292 +                uint8_t *row = static_cast<uint8_t*>(data);
  1.2293 +                for (GLint j = 0; j < height; ++j) {
  1.2294 +                    memset(row, 0xff, checked_plainRowSize.value());
  1.2295 +                    row += checked_alignedRowSize.value();
  1.2296 +                }
  1.2297 +            } else if (format == LOCAL_GL_RGBA && type == LOCAL_GL_UNSIGNED_BYTE) {
  1.2298 +                // this is harder, we need to just set the alpha byte here
  1.2299 +                uint8_t *row = static_cast<uint8_t*>(data);
  1.2300 +                for (GLint j = 0; j < height; ++j) {
  1.2301 +                    uint8_t *rowp = row;
  1.2302 +#if MOZ_LITTLE_ENDIAN
  1.2303 +                    // offset to get the alpha byte; we're always going to
  1.2304 +                    // move by 4 bytes
  1.2305 +                    rowp += 3;
  1.2306 +#endif
  1.2307 +                    uint8_t *endrowp = rowp + 4 * width;
  1.2308 +                    while (rowp != endrowp) {
  1.2309 +                        *rowp = 0xff;
  1.2310 +                        rowp += 4;
  1.2311 +                    }
  1.2312 +
  1.2313 +                    row += checked_alignedRowSize.value();
  1.2314 +                }
  1.2315 +            } else if (format == LOCAL_GL_RGBA && type == LOCAL_GL_FLOAT) {
  1.2316 +                float* row = static_cast<float*>(data);
  1.2317 +
  1.2318 +                for (GLint j = 0; j < height; ++j) {
  1.2319 +                    float* pAlpha = row + 3;
  1.2320 +                    float* pAlphaEnd = pAlpha + 4*width;
  1.2321 +
  1.2322 +                    while (pAlpha != pAlphaEnd) {
  1.2323 +                        *pAlpha = 1.0f;
  1.2324 +                        pAlpha += 4;
  1.2325 +                    }
  1.2326 +
  1.2327 +                    row += checked_alignedRowSize.value();
  1.2328 +                }
  1.2329 +            } else {
  1.2330 +                NS_WARNING("Unhandled case, how'd we get here?");
  1.2331 +                return rv.Throw(NS_ERROR_FAILURE);
  1.2332 +            }
  1.2333 +        }
  1.2334 +    }
  1.2335 +}
  1.2336 +
  1.2337 +void
  1.2338 +WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
  1.2339 +{
  1.2340 +    if (IsContextLost())
  1.2341 +        return;
  1.2342 +
  1.2343 +    if (!mBoundRenderbuffer)
  1.2344 +        return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
  1.2345 +
  1.2346 +    if (target != LOCAL_GL_RENDERBUFFER)
  1.2347 +        return ErrorInvalidEnumInfo("renderbufferStorage: target", target);
  1.2348 +
  1.2349 +    if (width < 0 || height < 0)
  1.2350 +        return ErrorInvalidValue("renderbufferStorage: width and height must be >= 0");
  1.2351 +
  1.2352 +    if (width > mGLMaxRenderbufferSize || height > mGLMaxRenderbufferSize)
  1.2353 +        return ErrorInvalidValue("renderbufferStorage: width or height exceeds maximum renderbuffer size");
  1.2354 +
  1.2355 +    // certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
  1.2356 +    GLenum internalformatForGL = internalformat;
  1.2357 +
  1.2358 +    switch (internalformat) {
  1.2359 +    case LOCAL_GL_RGBA4:
  1.2360 +    case LOCAL_GL_RGB5_A1:
  1.2361 +        // 16-bit RGBA formats are not supported on desktop GL
  1.2362 +        if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGBA8;
  1.2363 +        break;
  1.2364 +    case LOCAL_GL_RGB565:
  1.2365 +        // the RGB565 format is not supported on desktop GL
  1.2366 +        if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGB8;
  1.2367 +        break;
  1.2368 +    case LOCAL_GL_DEPTH_COMPONENT16:
  1.2369 +        if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
  1.2370 +            internalformatForGL = LOCAL_GL_DEPTH_COMPONENT24;
  1.2371 +        else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil))
  1.2372 +            internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
  1.2373 +        break;
  1.2374 +    case LOCAL_GL_STENCIL_INDEX8:
  1.2375 +        break;
  1.2376 +    case LOCAL_GL_DEPTH_STENCIL:
  1.2377 +        // We emulate this in WebGLRenderbuffer if we don't have the requisite extension.
  1.2378 +        internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
  1.2379 +        break;
  1.2380 +    case LOCAL_GL_SRGB8_ALPHA8_EXT:
  1.2381 +        break;
  1.2382 +    case LOCAL_GL_RGB16F:
  1.2383 +    case LOCAL_GL_RGBA16F: {
  1.2384 +        bool hasExtensions = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float) &&
  1.2385 +                             IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float);
  1.2386 +        if (!hasExtensions)
  1.2387 +            return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", target);
  1.2388 +        break;
  1.2389 +    }
  1.2390 +    case LOCAL_GL_RGB32F:
  1.2391 +    case LOCAL_GL_RGBA32F: {
  1.2392 +        bool hasExtensions = IsExtensionEnabled(WebGLExtensionID::OES_texture_float) &&
  1.2393 +                             IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float);
  1.2394 +        if (!hasExtensions)
  1.2395 +            return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", target);
  1.2396 +        break;
  1.2397 +    }
  1.2398 +    default:
  1.2399 +        return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
  1.2400 +    }
  1.2401 +
  1.2402 +    MakeContextCurrent();
  1.2403 +
  1.2404 +    bool sizeChanges = width != mBoundRenderbuffer->Width() ||
  1.2405 +                       height != mBoundRenderbuffer->Height() ||
  1.2406 +                       internalformat != mBoundRenderbuffer->InternalFormat();
  1.2407 +    if (sizeChanges) {
  1.2408 +        // Invalidate framebuffer status cache
  1.2409 +        mBoundRenderbuffer->NotifyFBsStatusChanged();
  1.2410 +        GetAndFlushUnderlyingGLErrors();
  1.2411 +        mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
  1.2412 +        GLenum error = GetAndFlushUnderlyingGLErrors();
  1.2413 +        if (error) {
  1.2414 +            GenerateWarning("renderbufferStorage generated error %s", ErrorName(error));
  1.2415 +            return;
  1.2416 +        }
  1.2417 +    } else {
  1.2418 +        mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
  1.2419 +    }
  1.2420 +
  1.2421 +    mBoundRenderbuffer->SetInternalFormat(internalformat);
  1.2422 +    mBoundRenderbuffer->SetInternalFormatForGL(internalformatForGL);
  1.2423 +    mBoundRenderbuffer->setDimensions(width, height);
  1.2424 +    mBoundRenderbuffer->SetImageDataStatus(WebGLImageDataStatus::UninitializedImageData);
  1.2425 +}
  1.2426 +
  1.2427 +void
  1.2428 +WebGLContext::Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
  1.2429 +{
  1.2430 +    if (IsContextLost())
  1.2431 +        return;
  1.2432 +
  1.2433 +    if (width < 0 || height < 0)
  1.2434 +        return ErrorInvalidValue("scissor: negative size");
  1.2435 +
  1.2436 +    MakeContextCurrent();
  1.2437 +    gl->fScissor(x, y, width, height);
  1.2438 +}
  1.2439 +
  1.2440 +void
  1.2441 +WebGLContext::StencilFunc(GLenum func, GLint ref, GLuint mask)
  1.2442 +{
  1.2443 +    if (IsContextLost())
  1.2444 +        return;
  1.2445 +
  1.2446 +    if (!ValidateComparisonEnum(func, "stencilFunc: func"))
  1.2447 +        return;
  1.2448 +
  1.2449 +    mStencilRefFront = ref;
  1.2450 +    mStencilRefBack = ref;
  1.2451 +    mStencilValueMaskFront = mask;
  1.2452 +    mStencilValueMaskBack = mask;
  1.2453 +
  1.2454 +    MakeContextCurrent();
  1.2455 +    gl->fStencilFunc(func, ref, mask);
  1.2456 +}
  1.2457 +
  1.2458 +void
  1.2459 +WebGLContext::StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
  1.2460 +{
  1.2461 +    if (IsContextLost())
  1.2462 +        return;
  1.2463 +
  1.2464 +    if (!ValidateFaceEnum(face, "stencilFuncSeparate: face") ||
  1.2465 +        !ValidateComparisonEnum(func, "stencilFuncSeparate: func"))
  1.2466 +        return;
  1.2467 +
  1.2468 +    switch (face) {
  1.2469 +        case LOCAL_GL_FRONT_AND_BACK:
  1.2470 +            mStencilRefFront = ref;
  1.2471 +            mStencilRefBack = ref;
  1.2472 +            mStencilValueMaskFront = mask;
  1.2473 +            mStencilValueMaskBack = mask;
  1.2474 +            break;
  1.2475 +        case LOCAL_GL_FRONT:
  1.2476 +            mStencilRefFront = ref;
  1.2477 +            mStencilValueMaskFront = mask;
  1.2478 +            break;
  1.2479 +        case LOCAL_GL_BACK:
  1.2480 +            mStencilRefBack = ref;
  1.2481 +            mStencilValueMaskBack = mask;
  1.2482 +            break;
  1.2483 +    }
  1.2484 +
  1.2485 +    MakeContextCurrent();
  1.2486 +    gl->fStencilFuncSeparate(face, func, ref, mask);
  1.2487 +}
  1.2488 +
  1.2489 +void
  1.2490 +WebGLContext::StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
  1.2491 +{
  1.2492 +    if (IsContextLost())
  1.2493 +        return;
  1.2494 +
  1.2495 +    if (!ValidateStencilOpEnum(sfail, "stencilOp: sfail") ||
  1.2496 +        !ValidateStencilOpEnum(dpfail, "stencilOp: dpfail") ||
  1.2497 +        !ValidateStencilOpEnum(dppass, "stencilOp: dppass"))
  1.2498 +        return;
  1.2499 +
  1.2500 +    MakeContextCurrent();
  1.2501 +    gl->fStencilOp(sfail, dpfail, dppass);
  1.2502 +}
  1.2503 +
  1.2504 +void
  1.2505 +WebGLContext::StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)
  1.2506 +{
  1.2507 +    if (IsContextLost())
  1.2508 +        return;
  1.2509 +
  1.2510 +    if (!ValidateFaceEnum(face, "stencilOpSeparate: face") ||
  1.2511 +        !ValidateStencilOpEnum(sfail, "stencilOpSeparate: sfail") ||
  1.2512 +        !ValidateStencilOpEnum(dpfail, "stencilOpSeparate: dpfail") ||
  1.2513 +        !ValidateStencilOpEnum(dppass, "stencilOpSeparate: dppass"))
  1.2514 +        return;
  1.2515 +
  1.2516 +    MakeContextCurrent();
  1.2517 +    gl->fStencilOpSeparate(face, sfail, dpfail, dppass);
  1.2518 +}
  1.2519 +
  1.2520 +nsresult
  1.2521 +WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
  1.2522 +                                                     RefPtr<DataSourceSurface>& imageOut, WebGLTexelFormat *format)
  1.2523 +{
  1.2524 +   *format = WebGLTexelFormat::None;
  1.2525 +
  1.2526 +    if (!res.mSourceSurface)
  1.2527 +        return NS_OK;
  1.2528 +    RefPtr<DataSourceSurface> data = res.mSourceSurface->GetDataSurface();
  1.2529 +    if (!data) {
  1.2530 +        // SurfaceFromElement lied!
  1.2531 +        return NS_OK;
  1.2532 +    }
  1.2533 +
  1.2534 +    if (!mPixelStorePremultiplyAlpha && res.mIsPremultiplied) {
  1.2535 +      data = gfxUtils::UnpremultiplyDataSurface(data);
  1.2536 +    }
  1.2537 +
  1.2538 +    // We disallow loading cross-domain images and videos that have not been validated
  1.2539 +    // with CORS as WebGL textures. The reason for doing that is that timing
  1.2540 +    // attacks on WebGL shaders are able to retrieve approximations of the
  1.2541 +    // pixel values in WebGL textures; see bug 655987.
  1.2542 +    //
  1.2543 +    // To prevent a loophole where a Canvas2D would be used as a proxy to load
  1.2544 +    // cross-domain textures, we also disallow loading textures from write-only
  1.2545 +    // Canvas2D's.
  1.2546 +
  1.2547 +    // part 1: check that the DOM element is same-origin, or has otherwise been
  1.2548 +    // validated for cross-domain use.
  1.2549 +    if (!res.mCORSUsed) {
  1.2550 +        bool subsumes;
  1.2551 +        nsresult rv = mCanvasElement->NodePrincipal()->Subsumes(res.mPrincipal, &subsumes);
  1.2552 +        if (NS_FAILED(rv) || !subsumes) {
  1.2553 +            GenerateWarning("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
  1.2554 +                                "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
  1.2555 +            return NS_ERROR_DOM_SECURITY_ERR;
  1.2556 +        }
  1.2557 +    }
  1.2558 +
  1.2559 +    // part 2: if the DOM element is write-only, it might contain
  1.2560 +    // cross-domain image data.
  1.2561 +    if (res.mIsWriteOnly) {
  1.2562 +        GenerateWarning("The canvas used as source for texImage2D here is tainted (write-only). It is forbidden "
  1.2563 +                        "to load a WebGL texture from a tainted canvas. A Canvas becomes tainted for example "
  1.2564 +                        "when a cross-domain image is drawn on it. "
  1.2565 +                        "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
  1.2566 +        return NS_ERROR_DOM_SECURITY_ERR;
  1.2567 +    }
  1.2568 +
  1.2569 +    // End of security checks, now we should be safe regarding cross-domain images
  1.2570 +    // Notice that there is never a need to mark the WebGL canvas as write-only, since we reject write-only/cross-domain
  1.2571 +    // texture sources in the first place.
  1.2572 +
  1.2573 +    switch (data->GetFormat()) {
  1.2574 +        case SurfaceFormat::B8G8R8A8:
  1.2575 +            *format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA
  1.2576 +            break;
  1.2577 +        case SurfaceFormat::B8G8R8X8:
  1.2578 +            *format = WebGLTexelFormat::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8.
  1.2579 +            break;
  1.2580 +        case SurfaceFormat::A8:
  1.2581 +            *format = WebGLTexelFormat::A8;
  1.2582 +            break;
  1.2583 +        case SurfaceFormat::R5G6B5:
  1.2584 +            *format = WebGLTexelFormat::RGB565;
  1.2585 +            break;
  1.2586 +        default:
  1.2587 +            NS_ASSERTION(false, "Unsupported image format. Unimplemented.");
  1.2588 +            return NS_ERROR_NOT_IMPLEMENTED;
  1.2589 +    }
  1.2590 +
  1.2591 +    imageOut = data;
  1.2592 +
  1.2593 +    return NS_OK;
  1.2594 +}
  1.2595 +
  1.2596 +
  1.2597 +
  1.2598 +void
  1.2599 +WebGLContext::Uniform1i(WebGLUniformLocation *location_object, GLint a1)
  1.2600 +{
  1.2601 +    GLint location;
  1.2602 +    if (!ValidateUniformSetter("Uniform1i", location_object, location))
  1.2603 +        return;
  1.2604 +
  1.2605 +    // Only uniform1i can take sampler settings.
  1.2606 +    if (!ValidateSamplerUniformSetter("Uniform1i", location_object, a1))
  1.2607 +        return;
  1.2608 +
  1.2609 +    MakeContextCurrent();
  1.2610 +    gl->fUniform1i(location, a1);
  1.2611 +}
  1.2612 +
  1.2613 +void
  1.2614 +WebGLContext::Uniform2i(WebGLUniformLocation *location_object, GLint a1,
  1.2615 +                        GLint a2)
  1.2616 +{
  1.2617 +    GLint location;
  1.2618 +    if (!ValidateUniformSetter("Uniform2i", location_object, location))
  1.2619 +        return;
  1.2620 +
  1.2621 +    MakeContextCurrent();
  1.2622 +    gl->fUniform2i(location, a1, a2);
  1.2623 +}
  1.2624 +
  1.2625 +void
  1.2626 +WebGLContext::Uniform3i(WebGLUniformLocation *location_object, GLint a1,
  1.2627 +                        GLint a2, GLint a3)
  1.2628 +{
  1.2629 +    GLint location;
  1.2630 +    if (!ValidateUniformSetter("Uniform3i", location_object, location))
  1.2631 +        return;
  1.2632 +
  1.2633 +    MakeContextCurrent();
  1.2634 +    gl->fUniform3i(location, a1, a2, a3);
  1.2635 +}
  1.2636 +
  1.2637 +void
  1.2638 +WebGLContext::Uniform4i(WebGLUniformLocation *location_object, GLint a1,
  1.2639 +                        GLint a2, GLint a3, GLint a4)
  1.2640 +{
  1.2641 +    GLint location;
  1.2642 +    if (!ValidateUniformSetter("Uniform4i", location_object, location))
  1.2643 +        return;
  1.2644 +
  1.2645 +    MakeContextCurrent();
  1.2646 +    gl->fUniform4i(location, a1, a2, a3, a4);
  1.2647 +}
  1.2648 +
  1.2649 +void
  1.2650 +WebGLContext::Uniform1f(WebGLUniformLocation *location_object, GLfloat a1)
  1.2651 +{
  1.2652 +    GLint location;
  1.2653 +    if (!ValidateUniformSetter("Uniform1f", location_object, location))
  1.2654 +        return;
  1.2655 +    MakeContextCurrent();
  1.2656 +    gl->fUniform1f(location, a1);
  1.2657 +}
  1.2658 +
  1.2659 +void
  1.2660 +WebGLContext::Uniform2f(WebGLUniformLocation *location_object, GLfloat a1,
  1.2661 +                        GLfloat a2)
  1.2662 +{
  1.2663 +    GLint location;
  1.2664 +    if (!ValidateUniformSetter("Uniform2f", location_object, location))
  1.2665 +        return;
  1.2666 +    MakeContextCurrent();
  1.2667 +    gl->fUniform2f(location, a1, a2);
  1.2668 +}
  1.2669 +
  1.2670 +void
  1.2671 +WebGLContext::Uniform3f(WebGLUniformLocation *location_object, GLfloat a1,
  1.2672 +                        GLfloat a2, GLfloat a3)
  1.2673 +{
  1.2674 +    GLint location;
  1.2675 +    if (!ValidateUniformSetter("Uniform3f", location_object, location))
  1.2676 +        return;
  1.2677 +    MakeContextCurrent();
  1.2678 +    gl->fUniform3f(location, a1, a2, a3);
  1.2679 +}
  1.2680 +
  1.2681 +void
  1.2682 +WebGLContext::Uniform4f(WebGLUniformLocation *location_object, GLfloat a1,
  1.2683 +                        GLfloat a2, GLfloat a3, GLfloat a4)
  1.2684 +{
  1.2685 +    GLint location;
  1.2686 +    if (!ValidateUniformSetter("Uniform4f", location_object, location))
  1.2687 +        return;
  1.2688 +    MakeContextCurrent();
  1.2689 +    gl->fUniform4f(location, a1, a2, a3, a4);
  1.2690 +}
  1.2691 +
  1.2692 +void
  1.2693 +WebGLContext::Uniform1iv_base(WebGLUniformLocation *location_object,
  1.2694 +                              uint32_t arrayLength, const GLint* data)
  1.2695 +{
  1.2696 +    uint32_t numElementsToUpload;
  1.2697 +    GLint location;
  1.2698 +    if (!ValidateUniformArraySetter("Uniform1iv", 1, location_object, location,
  1.2699 +                                    numElementsToUpload, arrayLength)) {
  1.2700 +        return;
  1.2701 +    }
  1.2702 +
  1.2703 +    if (!ValidateSamplerUniformSetter("Uniform1iv", location_object, data[0]))
  1.2704 +        return;
  1.2705 +
  1.2706 +    MakeContextCurrent();
  1.2707 +    gl->fUniform1iv(location, numElementsToUpload, data);
  1.2708 +}
  1.2709 +
  1.2710 +void
  1.2711 +WebGLContext::Uniform2iv_base(WebGLUniformLocation *location_object,
  1.2712 +                              uint32_t arrayLength, const GLint* data)
  1.2713 +{
  1.2714 +    uint32_t numElementsToUpload;
  1.2715 +    GLint location;
  1.2716 +    if (!ValidateUniformArraySetter("Uniform2iv", 2, location_object, location,
  1.2717 +                                    numElementsToUpload, arrayLength)) {
  1.2718 +        return;
  1.2719 +    }
  1.2720 +
  1.2721 +    if (!ValidateSamplerUniformSetter("Uniform2iv", location_object, data[0]) ||
  1.2722 +        !ValidateSamplerUniformSetter("Uniform2iv", location_object, data[1]))
  1.2723 +    {
  1.2724 +        return;
  1.2725 +    }
  1.2726 +
  1.2727 +    MakeContextCurrent();
  1.2728 +    gl->fUniform2iv(location, numElementsToUpload, data);
  1.2729 +}
  1.2730 +
  1.2731 +void
  1.2732 +WebGLContext::Uniform3iv_base(WebGLUniformLocation *location_object,
  1.2733 +                              uint32_t arrayLength, const GLint* data)
  1.2734 +{
  1.2735 +    uint32_t numElementsToUpload;
  1.2736 +    GLint location;
  1.2737 +    if (!ValidateUniformArraySetter("Uniform3iv", 3, location_object, location,
  1.2738 +                                    numElementsToUpload, arrayLength)) {
  1.2739 +        return;
  1.2740 +    }
  1.2741 +
  1.2742 +    if (!ValidateSamplerUniformSetter("Uniform3iv", location_object, data[0]) ||
  1.2743 +        !ValidateSamplerUniformSetter("Uniform3iv", location_object, data[1]) ||
  1.2744 +        !ValidateSamplerUniformSetter("Uniform3iv", location_object, data[2]))
  1.2745 +    {
  1.2746 +        return;
  1.2747 +    }
  1.2748 +
  1.2749 +    MakeContextCurrent();
  1.2750 +    gl->fUniform3iv(location, numElementsToUpload, data);
  1.2751 +}
  1.2752 +
  1.2753 +void
  1.2754 +WebGLContext::Uniform4iv_base(WebGLUniformLocation *location_object,
  1.2755 +                              uint32_t arrayLength, const GLint* data)
  1.2756 +{
  1.2757 +    uint32_t numElementsToUpload;
  1.2758 +    GLint location;
  1.2759 +    if (!ValidateUniformArraySetter("Uniform4iv", 4, location_object, location,
  1.2760 +                                    numElementsToUpload, arrayLength)) {
  1.2761 +        return;
  1.2762 +    }
  1.2763 +
  1.2764 +    if (!ValidateSamplerUniformSetter("Uniform4iv", location_object, data[0]) ||
  1.2765 +        !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[1]) ||
  1.2766 +        !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[2]) ||
  1.2767 +        !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[3]))
  1.2768 +    {
  1.2769 +        return;
  1.2770 +    }
  1.2771 +
  1.2772 +    MakeContextCurrent();
  1.2773 +    gl->fUniform4iv(location, numElementsToUpload, data);
  1.2774 +}
  1.2775 +
  1.2776 +void
  1.2777 +WebGLContext::Uniform1fv_base(WebGLUniformLocation *location_object,
  1.2778 +                              uint32_t arrayLength, const GLfloat* data)
  1.2779 +{
  1.2780 +    uint32_t numElementsToUpload;
  1.2781 +    GLint location;
  1.2782 +    if (!ValidateUniformArraySetter("Uniform1fv", 1, location_object, location,
  1.2783 +                                    numElementsToUpload, arrayLength)) {
  1.2784 +        return;
  1.2785 +    }
  1.2786 +    MakeContextCurrent();
  1.2787 +    gl->fUniform1fv(location, numElementsToUpload, data);
  1.2788 +}
  1.2789 +
  1.2790 +void
  1.2791 +WebGLContext::Uniform2fv_base(WebGLUniformLocation *location_object,
  1.2792 +                              uint32_t arrayLength, const GLfloat* data)
  1.2793 +{
  1.2794 +    uint32_t numElementsToUpload;
  1.2795 +    GLint location;
  1.2796 +    if (!ValidateUniformArraySetter("Uniform2fv", 2, location_object, location,
  1.2797 +                                    numElementsToUpload, arrayLength)) {
  1.2798 +        return;
  1.2799 +    }
  1.2800 +    MakeContextCurrent();
  1.2801 +    gl->fUniform2fv(location, numElementsToUpload, data);
  1.2802 +}
  1.2803 +
  1.2804 +void
  1.2805 +WebGLContext::Uniform3fv_base(WebGLUniformLocation *location_object,
  1.2806 +                              uint32_t arrayLength, const GLfloat* data)
  1.2807 +{
  1.2808 +    uint32_t numElementsToUpload;
  1.2809 +    GLint location;
  1.2810 +    if (!ValidateUniformArraySetter("Uniform3fv", 3, location_object, location,
  1.2811 +                                    numElementsToUpload, arrayLength)) {
  1.2812 +        return;
  1.2813 +    }
  1.2814 +    MakeContextCurrent();
  1.2815 +    gl->fUniform3fv(location, numElementsToUpload, data);
  1.2816 +}
  1.2817 +
  1.2818 +void
  1.2819 +WebGLContext::Uniform4fv_base(WebGLUniformLocation *location_object,
  1.2820 +                              uint32_t arrayLength, const GLfloat* data)
  1.2821 +{
  1.2822 +    uint32_t numElementsToUpload;
  1.2823 +    GLint location;
  1.2824 +    if (!ValidateUniformArraySetter("Uniform4fv", 4, location_object, location,
  1.2825 +                                    numElementsToUpload, arrayLength)) {
  1.2826 +        return;
  1.2827 +    }
  1.2828 +    MakeContextCurrent();
  1.2829 +    gl->fUniform4fv(location, numElementsToUpload, data);
  1.2830 +}
  1.2831 +
  1.2832 +void
  1.2833 +WebGLContext::UniformMatrix2fv_base(WebGLUniformLocation* location_object,
  1.2834 +                                    WebGLboolean aTranspose, uint32_t arrayLength,
  1.2835 +                                    const float* data)
  1.2836 +{
  1.2837 +    uint32_t numElementsToUpload;
  1.2838 +    GLint location;
  1.2839 +    if (!ValidateUniformMatrixArraySetter("UniformMatrix2fv", 2, location_object, location,
  1.2840 +                                         numElementsToUpload, arrayLength, aTranspose)) {
  1.2841 +        return;
  1.2842 +    }
  1.2843 +    MakeContextCurrent();
  1.2844 +    gl->fUniformMatrix2fv(location, numElementsToUpload, false, data);
  1.2845 +}
  1.2846 +
  1.2847 +void
  1.2848 +WebGLContext::UniformMatrix3fv_base(WebGLUniformLocation* location_object,
  1.2849 +                                    WebGLboolean aTranspose, uint32_t arrayLength,
  1.2850 +                                    const float* data)
  1.2851 +{
  1.2852 +    uint32_t numElementsToUpload;
  1.2853 +    GLint location;
  1.2854 +    if (!ValidateUniformMatrixArraySetter("UniformMatrix3fv", 3, location_object, location,
  1.2855 +                                         numElementsToUpload, arrayLength, aTranspose)) {
  1.2856 +        return;
  1.2857 +    }
  1.2858 +    MakeContextCurrent();
  1.2859 +    gl->fUniformMatrix3fv(location, numElementsToUpload, false, data);
  1.2860 +}
  1.2861 +
  1.2862 +void
  1.2863 +WebGLContext::UniformMatrix4fv_base(WebGLUniformLocation* location_object,
  1.2864 +                                    WebGLboolean aTranspose, uint32_t arrayLength,
  1.2865 +                                    const float* data)
  1.2866 +{
  1.2867 +    uint32_t numElementsToUpload;
  1.2868 +    GLint location;
  1.2869 +    if (!ValidateUniformMatrixArraySetter("UniformMatrix4fv", 4, location_object, location,
  1.2870 +                                         numElementsToUpload, arrayLength, aTranspose)) {
  1.2871 +        return;
  1.2872 +    }
  1.2873 +    MakeContextCurrent();
  1.2874 +    gl->fUniformMatrix4fv(location, numElementsToUpload, false, data);
  1.2875 +}
  1.2876 +
  1.2877 +void
  1.2878 +WebGLContext::UseProgram(WebGLProgram *prog)
  1.2879 +{
  1.2880 +    if (IsContextLost())
  1.2881 +        return;
  1.2882 +
  1.2883 +    if (!ValidateObjectAllowNull("useProgram", prog))
  1.2884 +        return;
  1.2885 +
  1.2886 +    MakeContextCurrent();
  1.2887 +
  1.2888 +    InvalidateBufferFetching();
  1.2889 +
  1.2890 +    GLuint progname = prog ? prog->GLName() : 0;
  1.2891 +
  1.2892 +    if (prog && !prog->LinkStatus())
  1.2893 +        return ErrorInvalidOperation("useProgram: program was not linked successfully");
  1.2894 +
  1.2895 +    gl->fUseProgram(progname);
  1.2896 +
  1.2897 +    mCurrentProgram = prog;
  1.2898 +}
  1.2899 +
  1.2900 +void
  1.2901 +WebGLContext::ValidateProgram(WebGLProgram *prog)
  1.2902 +{
  1.2903 +    if (IsContextLost())
  1.2904 +        return;
  1.2905 +
  1.2906 +    if (!ValidateObject("validateProgram", prog))
  1.2907 +        return;
  1.2908 +
  1.2909 +    MakeContextCurrent();
  1.2910 +
  1.2911 +#ifdef XP_MACOSX
  1.2912 +    // see bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed with Mac OS 10.6.7
  1.2913 +    if (gl->WorkAroundDriverBugs()) {
  1.2914 +        GenerateWarning("validateProgram: implemented as a no-operation on Mac to work around crashes");
  1.2915 +        return;
  1.2916 +    }
  1.2917 +#endif
  1.2918 +
  1.2919 +    GLuint progname = prog->GLName();
  1.2920 +    gl->fValidateProgram(progname);
  1.2921 +}
  1.2922 +
  1.2923 +already_AddRefed<WebGLFramebuffer>
  1.2924 +WebGLContext::CreateFramebuffer()
  1.2925 +{
  1.2926 +    if (IsContextLost())
  1.2927 +        return nullptr;
  1.2928 +    nsRefPtr<WebGLFramebuffer> globj = new WebGLFramebuffer(this);
  1.2929 +    return globj.forget();
  1.2930 +}
  1.2931 +
  1.2932 +already_AddRefed<WebGLRenderbuffer>
  1.2933 +WebGLContext::CreateRenderbuffer()
  1.2934 +{
  1.2935 +    if (IsContextLost())
  1.2936 +        return nullptr;
  1.2937 +    nsRefPtr<WebGLRenderbuffer> globj = new WebGLRenderbuffer(this);
  1.2938 +    return globj.forget();
  1.2939 +}
  1.2940 +
  1.2941 +void
  1.2942 +WebGLContext::Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
  1.2943 +{
  1.2944 +    if (IsContextLost())
  1.2945 +        return;
  1.2946 +
  1.2947 +    if (width < 0 || height < 0)
  1.2948 +        return ErrorInvalidValue("viewport: negative size");
  1.2949 +
  1.2950 +    MakeContextCurrent();
  1.2951 +    gl->fViewport(x, y, width, height);
  1.2952 +
  1.2953 +    mViewportX = x;
  1.2954 +    mViewportY = y;
  1.2955 +    mViewportWidth = width;
  1.2956 +    mViewportHeight = height;
  1.2957 +}
  1.2958 +
  1.2959 +void
  1.2960 +WebGLContext::CompileShader(WebGLShader *shader)
  1.2961 +{
  1.2962 +    if (IsContextLost())
  1.2963 +        return;
  1.2964 +
  1.2965 +    if (!ValidateObject("compileShader", shader))
  1.2966 +        return;
  1.2967 +
  1.2968 +    GLuint shadername = shader->GLName();
  1.2969 +
  1.2970 +    shader->SetCompileStatus(false);
  1.2971 +
  1.2972 +    MakeContextCurrent();
  1.2973 +
  1.2974 +    ShShaderOutput targetShaderSourceLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
  1.2975 +    bool useShaderSourceTranslation = true;
  1.2976 +
  1.2977 +    if (shader->NeedsTranslation() && mShaderValidation) {
  1.2978 +        ShHandle compiler = 0;
  1.2979 +        ShBuiltInResources resources;
  1.2980 +        memset(&resources, 0, sizeof(ShBuiltInResources));
  1.2981 +
  1.2982 +        resources.MaxVertexAttribs = mGLMaxVertexAttribs;
  1.2983 +        resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
  1.2984 +        resources.MaxVaryingVectors = mGLMaxVaryingVectors;
  1.2985 +        resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
  1.2986 +        resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
  1.2987 +        resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
  1.2988 +        resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
  1.2989 +        resources.MaxDrawBuffers = mGLMaxDrawBuffers;
  1.2990 +
  1.2991 +        if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
  1.2992 +            resources.EXT_frag_depth = 1;
  1.2993 +
  1.2994 +        if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
  1.2995 +            resources.OES_standard_derivatives = 1;
  1.2996 +
  1.2997 +        if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
  1.2998 +            resources.EXT_draw_buffers = 1;
  1.2999 +
  1.3000 +        // Tell ANGLE to allow highp in frag shaders. (unless disabled)
  1.3001 +        // If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
  1.3002 +        resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1;
  1.3003 +
  1.3004 +        if (gl->WorkAroundDriverBugs()) {
  1.3005 +#ifdef XP_MACOSX
  1.3006 +            if (gl->Vendor() == gl::GLVendor::NVIDIA) {
  1.3007 +                // Work around bug 890432
  1.3008 +                resources.MaxExpressionComplexity = 1000;
  1.3009 +            }
  1.3010 +#endif
  1.3011 +        }
  1.3012 +
  1.3013 +        // We're storing an actual instance of StripComments because, if we don't, the
  1.3014 +        // cleanSource nsAString instance will be destroyed before the reference is
  1.3015 +        // actually used.
  1.3016 +        StripComments stripComments(shader->Source());
  1.3017 +        const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length());
  1.3018 +        if (!ValidateGLSLString(cleanSource, "compileShader"))
  1.3019 +            return;
  1.3020 +
  1.3021 +        // shaderSource() already checks that the source stripped of comments is in the
  1.3022 +        // 7-bit ASCII range, so we can skip the NS_IsAscii() check.
  1.3023 +        NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
  1.3024 +
  1.3025 +        if (gl->WorkAroundDriverBugs()) {
  1.3026 +            const uint32_t maxSourceLength = 0x3ffff;
  1.3027 +            if (sourceCString.Length() > maxSourceLength)
  1.3028 +                return ErrorInvalidValue("compileShader: source has more than %d characters",
  1.3029 +                                         maxSourceLength);
  1.3030 +        }
  1.3031 +
  1.3032 +        const char *s = sourceCString.get();
  1.3033 +
  1.3034 +#define WEBGL2_BYPASS_ANGLE
  1.3035 +#ifdef WEBGL2_BYPASS_ANGLE
  1.3036 +        /*
  1.3037 +         * The bypass don't bring a full support for GLSL ES 3.0, but the main purpose
  1.3038 +         * is to natively bring gl_InstanceID (to do instanced rendering) and gl_FragData
  1.3039 +         *
  1.3040 +         * To remove the bypass code, just comment #define WEBGL2_BYPASS_ANGLE above
  1.3041 +         *
  1.3042 +         * To bypass angle, the context must be a WebGL 2 and the shader must have the
  1.3043 +         * following line at the very top :
  1.3044 +         *      #version proto-200
  1.3045 +         *
  1.3046 +         * In this case, byPassANGLE == true and here is what we do :
  1.3047 +         *  We create two shader source code:
  1.3048 +         *    - one for the driver, that enable GL_EXT_gpu_shader4
  1.3049 +         *    - one for the angle compilor, to get informations about vertex attributes
  1.3050 +         *      and uniforms
  1.3051 +         */
  1.3052 +        static const char *bypassPrefixSearch = "#version proto-200";
  1.3053 +        static const char *bypassANGLEPrefix[2] = {"precision mediump float;\n"
  1.3054 +                                                   "#define gl_VertexID 0\n"
  1.3055 +                                                   "#define gl_InstanceID 0\n",
  1.3056 +
  1.3057 +                                                   "precision mediump float;\n"
  1.3058 +                                                   "#extension GL_EXT_draw_buffers : enable\n"
  1.3059 +                                                   "#define gl_PrimitiveID 0\n"};
  1.3060 +
  1.3061 +        const bool bypassANGLE = IsWebGL2() && (strstr(s, bypassPrefixSearch) != 0);
  1.3062 +
  1.3063 +        const char *angleShaderCode = s;
  1.3064 +        nsTArray<char> bypassANGLEShaderCode;
  1.3065 +        nsTArray<char> bypassDriverShaderCode;
  1.3066 +
  1.3067 +        if (bypassANGLE) {
  1.3068 +            const int bypassStage = (shader->ShaderType() == LOCAL_GL_FRAGMENT_SHADER) ? 1 : 0;
  1.3069 +            const char *originalShader = strstr(s, bypassPrefixSearch) + strlen(bypassPrefixSearch);
  1.3070 +            int originalShaderSize = strlen(s) - (originalShader - s);
  1.3071 +            int bypassShaderCodeSize = originalShaderSize + 4096 + 1;
  1.3072 +
  1.3073 +            bypassANGLEShaderCode.SetLength(bypassShaderCodeSize);
  1.3074 +            strcpy(bypassANGLEShaderCode.Elements(), bypassANGLEPrefix[bypassStage]);
  1.3075 +            strcat(bypassANGLEShaderCode.Elements(), originalShader);
  1.3076 +
  1.3077 +            bypassDriverShaderCode.SetLength(bypassShaderCodeSize);
  1.3078 +            strcpy(bypassDriverShaderCode.Elements(), "#extension GL_EXT_gpu_shader4 : enable\n");
  1.3079 +            strcat(bypassDriverShaderCode.Elements(), originalShader);
  1.3080 +
  1.3081 +            angleShaderCode = bypassANGLEShaderCode.Elements();
  1.3082 +        }
  1.3083 +#endif
  1.3084 +
  1.3085 +        compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
  1.3086 +                                       SH_WEBGL_SPEC,
  1.3087 +                                       targetShaderSourceLanguage,
  1.3088 +                                       &resources);
  1.3089 +
  1.3090 +        int compileOptions = SH_ATTRIBUTES_UNIFORMS |
  1.3091 +                             SH_ENFORCE_PACKING_RESTRICTIONS;
  1.3092 +
  1.3093 +        if (resources.MaxExpressionComplexity > 0) {
  1.3094 +            compileOptions |= SH_LIMIT_EXPRESSION_COMPLEXITY;
  1.3095 +        }
  1.3096 +
  1.3097 +        // We want to do this everywhere, but:
  1.3098 +#ifndef XP_MACOSX // To do this on Mac, we need to do it only on Mac OSX > 10.6 as this
  1.3099 +                  // causes the shader compiler in 10.6 to crash
  1.3100 +        compileOptions |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
  1.3101 +#endif
  1.3102 +
  1.3103 +        if (useShaderSourceTranslation) {
  1.3104 +            compileOptions |= SH_OBJECT_CODE
  1.3105 +                            | SH_MAP_LONG_VARIABLE_NAMES;
  1.3106 +
  1.3107 +#ifdef XP_MACOSX
  1.3108 +            if (gl->WorkAroundDriverBugs()) {
  1.3109 +                // Work around bug 665578 and bug 769810
  1.3110 +                if (gl->Vendor() == gl::GLVendor::ATI) {
  1.3111 +                    compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
  1.3112 +                }
  1.3113 +
  1.3114 +                // Work around bug 735560
  1.3115 +                if (gl->Vendor() == gl::GLVendor::Intel) {
  1.3116 +                    compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
  1.3117 +                }
  1.3118 +            }
  1.3119 +#endif
  1.3120 +        }
  1.3121 +
  1.3122 +#ifdef WEBGL2_BYPASS_ANGLE
  1.3123 +        if (!ShCompile(compiler, &angleShaderCode, 1, compileOptions)) {
  1.3124 +#else
  1.3125 +        if (!ShCompile(compiler, &s, 1, compileOptions)) {
  1.3126 +#endif
  1.3127 +            size_t lenWithNull = 0;
  1.3128 +            ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &lenWithNull);
  1.3129 +
  1.3130 +            if (!lenWithNull) {
  1.3131 +                // Error in ShGetInfo.
  1.3132 +                shader->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log"));
  1.3133 +            } else {
  1.3134 +                size_t len = lenWithNull - 1;
  1.3135 +
  1.3136 +                nsAutoCString info;
  1.3137 +                info.SetLength(len); // Allocates len+1, for the null-term.
  1.3138 +                ShGetInfoLog(compiler, info.BeginWriting());
  1.3139 +
  1.3140 +                shader->SetTranslationFailure(info);
  1.3141 +            }
  1.3142 +            ShDestruct(compiler);
  1.3143 +            shader->SetCompileStatus(false);
  1.3144 +            return;
  1.3145 +        }
  1.3146 +
  1.3147 +        size_t num_attributes = 0;
  1.3148 +        ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTES, &num_attributes);
  1.3149 +        size_t num_uniforms = 0;
  1.3150 +        ShGetInfo(compiler, SH_ACTIVE_UNIFORMS, &num_uniforms);
  1.3151 +        size_t attrib_max_length = 0;
  1.3152 +        ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrib_max_length);
  1.3153 +        size_t uniform_max_length = 0;
  1.3154 +        ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_max_length);
  1.3155 +        size_t mapped_max_length = 0;
  1.3156 +        ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_max_length);
  1.3157 +
  1.3158 +        shader->mAttribMaxNameLength = attrib_max_length;
  1.3159 +
  1.3160 +        shader->mAttributes.Clear();
  1.3161 +        shader->mUniforms.Clear();
  1.3162 +        shader->mUniformInfos.Clear();
  1.3163 +
  1.3164 +        nsAutoArrayPtr<char> attribute_name(new char[attrib_max_length+1]);
  1.3165 +        nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]);
  1.3166 +        nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]);
  1.3167 +
  1.3168 +        for (size_t i = 0; i < num_uniforms; i++) {
  1.3169 +            size_t length;
  1.3170 +            int size;
  1.3171 +            ShDataType type;
  1.3172 +            ShGetActiveUniform(compiler, (int)i,
  1.3173 +                                &length, &size, &type,
  1.3174 +                                uniform_name,
  1.3175 +                                mapped_name);
  1.3176 +            if (useShaderSourceTranslation) {
  1.3177 +                shader->mUniforms.AppendElement(WebGLMappedIdentifier(
  1.3178 +                                                    nsDependentCString(uniform_name),
  1.3179 +                                                    nsDependentCString(mapped_name)));
  1.3180 +            }
  1.3181 +
  1.3182 +            // we always query uniform info, regardless of useShaderSourceTranslation,
  1.3183 +            // as we need it to validate uniform setter calls, and it doesn't rely on
  1.3184 +            // shader translation.
  1.3185 +            char mappedNameLength = strlen(mapped_name);
  1.3186 +            char mappedNameLastChar = mappedNameLength > 1
  1.3187 +                                      ? mapped_name[mappedNameLength - 1]
  1.3188 +                                      : 0;
  1.3189 +            shader->mUniformInfos.AppendElement(WebGLUniformInfo(
  1.3190 +                                                    size,
  1.3191 +                                                    mappedNameLastChar == ']',
  1.3192 +                                                    type));
  1.3193 +        }
  1.3194 +
  1.3195 +        if (useShaderSourceTranslation) {
  1.3196 +
  1.3197 +            for (size_t i = 0; i < num_attributes; i++) {
  1.3198 +                size_t length;
  1.3199 +                int size;
  1.3200 +                ShDataType type;
  1.3201 +                ShGetActiveAttrib(compiler, (int)i,
  1.3202 +                                  &length, &size, &type,
  1.3203 +                                  attribute_name,
  1.3204 +                                  mapped_name);
  1.3205 +                shader->mAttributes.AppendElement(WebGLMappedIdentifier(
  1.3206 +                                                    nsDependentCString(attribute_name),
  1.3207 +                                                    nsDependentCString(mapped_name)));
  1.3208 +            }
  1.3209 +
  1.3210 +            size_t lenWithNull = 0;
  1.3211 +            ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &lenWithNull);
  1.3212 +            MOZ_ASSERT(lenWithNull >= 1);
  1.3213 +            size_t len = lenWithNull - 1;
  1.3214 +
  1.3215 +            nsAutoCString translatedSrc;
  1.3216 +            translatedSrc.SetLength(len); // Allocates len+1, for the null-term.
  1.3217 +            ShGetObjectCode(compiler, translatedSrc.BeginWriting());
  1.3218 +
  1.3219 +            CopyASCIItoUTF16(translatedSrc, shader->mTranslatedSource);
  1.3220 +
  1.3221 +            const char *ts = translatedSrc.get();
  1.3222 +
  1.3223 +#ifdef WEBGL2_BYPASS_ANGLE
  1.3224 +            if (bypassANGLE) {
  1.3225 +                const char* driverShaderCode = bypassDriverShaderCode.Elements();
  1.3226 +                gl->fShaderSource(shadername, 1, (const GLchar**) &driverShaderCode, nullptr);
  1.3227 +            }
  1.3228 +            else {
  1.3229 +                gl->fShaderSource(shadername, 1, &ts, nullptr);
  1.3230 +            }
  1.3231 +#else
  1.3232 +            gl->fShaderSource(shadername, 1, &ts, nullptr);
  1.3233 +#endif
  1.3234 +        } else { // not useShaderSourceTranslation
  1.3235 +            // we just pass the raw untranslated shader source. We then can't use ANGLE idenfier mapping.
  1.3236 +            // that's really bad, as that means we can't be 100% conformant. We should work towards always
  1.3237 +            // using ANGLE identifier mapping.
  1.3238 +            gl->fShaderSource(shadername, 1, &s, nullptr);
  1.3239 +
  1.3240 +            CopyASCIItoUTF16(s, shader->mTranslatedSource);
  1.3241 +        }
  1.3242 +
  1.3243 +        shader->SetTranslationSuccess();
  1.3244 +
  1.3245 +        ShDestruct(compiler);
  1.3246 +
  1.3247 +        gl->fCompileShader(shadername);
  1.3248 +        GLint ok;
  1.3249 +        gl->fGetShaderiv(shadername, LOCAL_GL_COMPILE_STATUS, &ok);
  1.3250 +        shader->SetCompileStatus(ok);
  1.3251 +    }
  1.3252 +}
  1.3253 +
  1.3254 +void
  1.3255 +WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
  1.3256 +                                   GLsizei width, GLsizei height, GLint border,
  1.3257 +                                   const ArrayBufferView& view)
  1.3258 +{
  1.3259 +    if (IsContextLost())
  1.3260 +        return;
  1.3261 +
  1.3262 +    const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexImage;
  1.3263 +
  1.3264 +    if (!ValidateTexImage(2, target, level, internalformat,
  1.3265 +                          0, 0, 0, width, height, 0,
  1.3266 +                          border, internalformat, LOCAL_GL_UNSIGNED_BYTE,
  1.3267 +                          func))
  1.3268 +    {
  1.3269 +        return;
  1.3270 +    }
  1.3271 +
  1.3272 +    view.ComputeLengthAndData();
  1.3273 +
  1.3274 +    uint32_t byteLength = view.Length();
  1.3275 +    if (!ValidateCompTexImageDataSize(target, internalformat, width, height, byteLength, func)) {
  1.3276 +        return;
  1.3277 +    }
  1.3278 +
  1.3279 +    if (!ValidateCompTexImageSize(target, level, internalformat, 0, 0,
  1.3280 +                                  width, height, width, height, func))
  1.3281 +    {
  1.3282 +        return;
  1.3283 +    }
  1.3284 +
  1.3285 +    MakeContextCurrent();
  1.3286 +    gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data());
  1.3287 +    WebGLTexture* tex = activeBoundTextureForTarget(target);
  1.3288 +    MOZ_ASSERT(tex);
  1.3289 +    tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
  1.3290 +                      WebGLImageDataStatus::InitializedImageData);
  1.3291 +}
  1.3292 +
  1.3293 +void
  1.3294 +WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset,
  1.3295 +                                      GLint yoffset, GLsizei width, GLsizei height,
  1.3296 +                                      GLenum format, const ArrayBufferView& view)
  1.3297 +{
  1.3298 +    if (IsContextLost())
  1.3299 +        return;
  1.3300 +
  1.3301 +    const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexSubImage;
  1.3302 +
  1.3303 +    if (!ValidateTexImage(2, target,
  1.3304 +                          level, format,
  1.3305 +                          xoffset, yoffset, 0,
  1.3306 +                          width, height, 0,
  1.3307 +                          0, format, LOCAL_GL_UNSIGNED_BYTE,
  1.3308 +                          func))
  1.3309 +    {
  1.3310 +        return;
  1.3311 +    }
  1.3312 +
  1.3313 +    WebGLTexture *tex = activeBoundTextureForTarget(target);
  1.3314 +    MOZ_ASSERT(tex);
  1.3315 +    WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(target, level);
  1.3316 +
  1.3317 +    view.ComputeLengthAndData();
  1.3318 +
  1.3319 +    uint32_t byteLength = view.Length();
  1.3320 +    if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func))
  1.3321 +        return;
  1.3322 +
  1.3323 +    if (!ValidateCompTexImageSize(target, level, format,
  1.3324 +                                  xoffset, yoffset,
  1.3325 +                                  width, height,
  1.3326 +                                  levelInfo.Width(), levelInfo.Height(),
  1.3327 +                                  func))
  1.3328 +    {
  1.3329 +        return;
  1.3330 +    }
  1.3331 +
  1.3332 +    if (levelInfo.HasUninitializedImageData())
  1.3333 +        tex->DoDeferredImageInitialization(target, level);
  1.3334 +
  1.3335 +    MakeContextCurrent();
  1.3336 +    gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.Data());
  1.3337 +}
  1.3338 +
  1.3339 +JS::Value
  1.3340 +WebGLContext::GetShaderParameter(WebGLShader *shader, GLenum pname)
  1.3341 +{
  1.3342 +    if (IsContextLost())
  1.3343 +        return JS::NullValue();
  1.3344 +
  1.3345 +    if (!ValidateObject("getShaderParameter: shader", shader))
  1.3346 +        return JS::NullValue();
  1.3347 +
  1.3348 +    GLuint shadername = shader->GLName();
  1.3349 +
  1.3350 +    MakeContextCurrent();
  1.3351 +
  1.3352 +    switch (pname) {
  1.3353 +        case LOCAL_GL_SHADER_TYPE:
  1.3354 +        {
  1.3355 +            GLint i = 0;
  1.3356 +            gl->fGetShaderiv(shadername, pname, &i);
  1.3357 +            return JS::NumberValue(uint32_t(i));
  1.3358 +        }
  1.3359 +            break;
  1.3360 +        case LOCAL_GL_DELETE_STATUS:
  1.3361 +            return JS::BooleanValue(shader->IsDeleteRequested());
  1.3362 +            break;
  1.3363 +        case LOCAL_GL_COMPILE_STATUS:
  1.3364 +        {
  1.3365 +            GLint i = 0;
  1.3366 +            gl->fGetShaderiv(shadername, pname, &i);
  1.3367 +            return JS::BooleanValue(bool(i));
  1.3368 +        }
  1.3369 +            break;
  1.3370 +        default:
  1.3371 +            ErrorInvalidEnumInfo("getShaderParameter: parameter", pname);
  1.3372 +    }
  1.3373 +
  1.3374 +    return JS::NullValue();
  1.3375 +}
  1.3376 +
  1.3377 +void
  1.3378 +WebGLContext::GetShaderInfoLog(WebGLShader *shader, nsAString& retval)
  1.3379 +{
  1.3380 +    nsAutoCString s;
  1.3381 +    GetShaderInfoLog(shader, s);
  1.3382 +    if (s.IsVoid())
  1.3383 +        retval.SetIsVoid(true);
  1.3384 +    else
  1.3385 +        CopyASCIItoUTF16(s, retval);
  1.3386 +}
  1.3387 +
  1.3388 +void
  1.3389 +WebGLContext::GetShaderInfoLog(WebGLShader *shader, nsACString& retval)
  1.3390 +{
  1.3391 +    if (IsContextLost())
  1.3392 +    {
  1.3393 +        retval.SetIsVoid(true);
  1.3394 +        return;
  1.3395 +    }
  1.3396 +
  1.3397 +    if (!ValidateObject("getShaderInfoLog: shader", shader))
  1.3398 +        return;
  1.3399 +
  1.3400 +    retval = shader->TranslationLog();
  1.3401 +    if (!retval.IsVoid()) {
  1.3402 +        return;
  1.3403 +    }
  1.3404 +
  1.3405 +    MakeContextCurrent();
  1.3406 +
  1.3407 +    GLuint shadername = shader->GLName();
  1.3408 +    GLint k = -1;
  1.3409 +    gl->fGetShaderiv(shadername, LOCAL_GL_INFO_LOG_LENGTH, &k);
  1.3410 +    if (k == -1) {
  1.3411 +        // XXX GL Error? should never happen.
  1.3412 +        return;
  1.3413 +    }
  1.3414 +
  1.3415 +    if (k == 0) {
  1.3416 +        retval.Truncate();
  1.3417 +        return;
  1.3418 +    }
  1.3419 +
  1.3420 +    retval.SetCapacity(k);
  1.3421 +    gl->fGetShaderInfoLog(shadername, k, &k, (char*) retval.BeginWriting());
  1.3422 +    retval.SetLength(k);
  1.3423 +}
  1.3424 +
  1.3425 +already_AddRefed<WebGLShaderPrecisionFormat>
  1.3426 +WebGLContext::GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype)
  1.3427 +{
  1.3428 +    if (IsContextLost())
  1.3429 +        return nullptr;
  1.3430 +
  1.3431 +    switch (shadertype) {
  1.3432 +        case LOCAL_GL_FRAGMENT_SHADER:
  1.3433 +        case LOCAL_GL_VERTEX_SHADER:
  1.3434 +            break;
  1.3435 +        default:
  1.3436 +            ErrorInvalidEnumInfo("getShaderPrecisionFormat: shadertype", shadertype);
  1.3437 +            return nullptr;
  1.3438 +    }
  1.3439 +
  1.3440 +    switch (precisiontype) {
  1.3441 +        case LOCAL_GL_LOW_FLOAT:
  1.3442 +        case LOCAL_GL_MEDIUM_FLOAT:
  1.3443 +        case LOCAL_GL_HIGH_FLOAT:
  1.3444 +        case LOCAL_GL_LOW_INT:
  1.3445 +        case LOCAL_GL_MEDIUM_INT:
  1.3446 +        case LOCAL_GL_HIGH_INT:
  1.3447 +            break;
  1.3448 +        default:
  1.3449 +            ErrorInvalidEnumInfo("getShaderPrecisionFormat: precisiontype", precisiontype);
  1.3450 +            return nullptr;
  1.3451 +    }
  1.3452 +
  1.3453 +    MakeContextCurrent();
  1.3454 +    GLint range[2], precision;
  1.3455 +
  1.3456 +    if (mDisableFragHighP &&
  1.3457 +        shadertype == LOCAL_GL_FRAGMENT_SHADER &&
  1.3458 +        (precisiontype == LOCAL_GL_HIGH_FLOAT ||
  1.3459 +         precisiontype == LOCAL_GL_HIGH_INT))
  1.3460 +    {
  1.3461 +      precision = 0;
  1.3462 +      range[0] = 0;
  1.3463 +      range[1] = 0;
  1.3464 +    } else {
  1.3465 +      gl->fGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision);
  1.3466 +    }
  1.3467 +
  1.3468 +    nsRefPtr<WebGLShaderPrecisionFormat> retShaderPrecisionFormat
  1.3469 +        = new WebGLShaderPrecisionFormat(this, range[0], range[1], precision);
  1.3470 +    return retShaderPrecisionFormat.forget();
  1.3471 +}
  1.3472 +
  1.3473 +void
  1.3474 +WebGLContext::GetShaderSource(WebGLShader *shader, nsAString& retval)
  1.3475 +{
  1.3476 +    if (IsContextLost()) {
  1.3477 +        retval.SetIsVoid(true);
  1.3478 +        return;
  1.3479 +    }
  1.3480 +
  1.3481 +    if (!ValidateObject("getShaderSource: shader", shader))
  1.3482 +        return;
  1.3483 +
  1.3484 +    retval.Assign(shader->Source());
  1.3485 +}
  1.3486 +
  1.3487 +void
  1.3488 +WebGLContext::ShaderSource(WebGLShader *shader, const nsAString& source)
  1.3489 +{
  1.3490 +    if (IsContextLost())
  1.3491 +        return;
  1.3492 +
  1.3493 +    if (!ValidateObject("shaderSource: shader", shader))
  1.3494 +        return;
  1.3495 +
  1.3496 +    // We're storing an actual instance of StripComments because, if we don't, the
  1.3497 +    // cleanSource nsAString instance will be destroyed before the reference is
  1.3498 +    // actually used.
  1.3499 +    StripComments stripComments(source);
  1.3500 +    const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length());
  1.3501 +    if (!ValidateGLSLString(cleanSource, "compileShader"))
  1.3502 +        return;
  1.3503 +
  1.3504 +    shader->SetSource(source);
  1.3505 +
  1.3506 +    shader->SetNeedsTranslation();
  1.3507 +}
  1.3508 +
  1.3509 +void
  1.3510 +WebGLContext::GetShaderTranslatedSource(WebGLShader *shader, nsAString& retval)
  1.3511 +{
  1.3512 +    if (IsContextLost()) {
  1.3513 +        retval.SetIsVoid(true);
  1.3514 +        return;
  1.3515 +    }
  1.3516 +
  1.3517 +    if (!ValidateObject("getShaderTranslatedSource: shader", shader))
  1.3518 +        return;
  1.3519 +
  1.3520 +    retval.Assign(shader->TranslatedSource());
  1.3521 +}
  1.3522 +
  1.3523 +GLenum WebGLContext::CheckedTexImage2D(GLenum target,
  1.3524 +                                       GLint level,
  1.3525 +                                       GLenum internalFormat,
  1.3526 +                                       GLsizei width,
  1.3527 +                                       GLsizei height,
  1.3528 +                                       GLint border,
  1.3529 +                                       GLenum format,
  1.3530 +                                       GLenum type,
  1.3531 +                                       const GLvoid *data)
  1.3532 +{
  1.3533 +    MOZ_ASSERT(internalFormat == format);
  1.3534 +    WebGLTexture *tex = activeBoundTextureForTarget(target);
  1.3535 +    MOZ_ASSERT(tex != nullptr, "no texture bound");
  1.3536 +
  1.3537 +    bool sizeMayChange = true;
  1.3538 +
  1.3539 +    if (tex->HasImageInfoAt(target, level)) {
  1.3540 +        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
  1.3541 +        sizeMayChange = width != imageInfo.Width() ||
  1.3542 +                        height != imageInfo.Height() ||
  1.3543 +                        format != imageInfo.WebGLFormat() ||
  1.3544 +                        type != imageInfo.WebGLType();
  1.3545 +    }
  1.3546 +
  1.3547 +    // Convert to format and type required by OpenGL 'driver'.
  1.3548 +    GLenum driverType = DriverTypeFromType(gl, type);
  1.3549 +    GLenum driverInternalFormat = LOCAL_GL_NONE;
  1.3550 +    GLenum driverFormat = LOCAL_GL_NONE;
  1.3551 +    DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat);
  1.3552 +
  1.3553 +    if (sizeMayChange) {
  1.3554 +        GetAndFlushUnderlyingGLErrors();
  1.3555 +    }
  1.3556 +
  1.3557 +    gl->fTexImage2D(target, level, driverInternalFormat, width, height, border, driverFormat, driverType, data);
  1.3558 +
  1.3559 +    GLenum error = LOCAL_GL_NO_ERROR;
  1.3560 +    if (sizeMayChange) {
  1.3561 +        error = GetAndFlushUnderlyingGLErrors();
  1.3562 +    }
  1.3563 +
  1.3564 +    return error;
  1.3565 +}
  1.3566 +
  1.3567 +void
  1.3568 +WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
  1.3569 +                              GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
  1.3570 +                              GLint border,
  1.3571 +                              GLenum format, GLenum type,
  1.3572 +                              void* data, uint32_t byteLength,
  1.3573 +                              int jsArrayType, // a TypedArray format enum, or -1 if not relevant
  1.3574 +                              WebGLTexelFormat srcFormat, bool srcPremultiplied)
  1.3575 +{
  1.3576 +    const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
  1.3577 +
  1.3578 +    if (!ValidateTexImage(2, target, level, internalformat,
  1.3579 +                          0, 0, 0,
  1.3580 +                          width, height, 0,
  1.3581 +                          border, format, type, func))
  1.3582 +    {
  1.3583 +        return;
  1.3584 +    }
  1.3585 +
  1.3586 +    const bool isDepthTexture = format == LOCAL_GL_DEPTH_COMPONENT ||
  1.3587 +                                format == LOCAL_GL_DEPTH_STENCIL;
  1.3588 +
  1.3589 +    if (isDepthTexture) {
  1.3590 +        if (data != nullptr || level != 0)
  1.3591 +            return ErrorInvalidOperation("texImage2D: "
  1.3592 +                                         "with format of DEPTH_COMPONENT or DEPTH_STENCIL, "
  1.3593 +                                         "data must be nullptr, "
  1.3594 +                                         "level must be zero");
  1.3595 +    }
  1.3596 +
  1.3597 +    if (!ValidateTexInputData(type, jsArrayType, func))
  1.3598 +        return;
  1.3599 +
  1.3600 +    WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
  1.3601 +    WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
  1.3602 +
  1.3603 +    uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
  1.3604 +
  1.3605 +    CheckedUint32 checked_neededByteLength =
  1.3606 +        GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
  1.3607 +
  1.3608 +    CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
  1.3609 +    CheckedUint32 checked_alignedRowSize =
  1.3610 +        RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
  1.3611 +
  1.3612 +    if (!checked_neededByteLength.isValid())
  1.3613 +        return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size");
  1.3614 +
  1.3615 +    uint32_t bytesNeeded = checked_neededByteLength.value();
  1.3616 +
  1.3617 +    if (byteLength && byteLength < bytesNeeded)
  1.3618 +        return ErrorInvalidOperation("texImage2D: not enough data for operation (need %d, have %d)",
  1.3619 +                                 bytesNeeded, byteLength);
  1.3620 +
  1.3621 +    WebGLTexture *tex = activeBoundTextureForTarget(target);
  1.3622 +
  1.3623 +    if (!tex)
  1.3624 +        return ErrorInvalidOperation("texImage2D: no texture is bound to this target");
  1.3625 +
  1.3626 +    MakeContextCurrent();
  1.3627 +
  1.3628 +    nsAutoArrayPtr<uint8_t> convertedData;
  1.3629 +    void* pixels = nullptr;
  1.3630 +    WebGLImageDataStatus imageInfoStatusIfSuccess = WebGLImageDataStatus::UninitializedImageData;
  1.3631 +
  1.3632 +    if (byteLength) {
  1.3633 +        size_t   srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
  1.3634 +        uint32_t dstTexelSize = GetBitsPerTexel(format, type) / 8;
  1.3635 +        size_t   dstPlainRowSize = dstTexelSize * width;
  1.3636 +        size_t   unpackAlignment = mPixelStoreUnpackAlignment;
  1.3637 +        size_t   dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment;
  1.3638 +
  1.3639 +        if (actualSrcFormat == dstFormat &&
  1.3640 +            srcPremultiplied == mPixelStorePremultiplyAlpha &&
  1.3641 +            srcStride == dstStride &&
  1.3642 +            !mPixelStoreFlipY)
  1.3643 +        {
  1.3644 +            // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
  1.3645 +            pixels = data;
  1.3646 +        }
  1.3647 +        else
  1.3648 +        {
  1.3649 +            size_t convertedDataSize = height * dstStride;
  1.3650 +            convertedData = new uint8_t[convertedDataSize];
  1.3651 +            ConvertImage(width, height, srcStride, dstStride,
  1.3652 +                        static_cast<uint8_t*>(data), convertedData,
  1.3653 +                        actualSrcFormat, srcPremultiplied,
  1.3654 +                        dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize);
  1.3655 +            pixels = reinterpret_cast<void*>(convertedData.get());
  1.3656 +        }
  1.3657 +        imageInfoStatusIfSuccess = WebGLImageDataStatus::InitializedImageData;
  1.3658 +    }
  1.3659 +
  1.3660 +    GLenum error = CheckedTexImage2D(target, level, internalformat, width,
  1.3661 +                                     height, border, format, type, pixels);
  1.3662 +
  1.3663 +    if (error) {
  1.3664 +        GenerateWarning("texImage2D generated error %s", ErrorName(error));
  1.3665 +        return;
  1.3666 +    }
  1.3667 +
  1.3668 +    // in all of the code paths above, we should have either initialized data,
  1.3669 +    // or allocated data and left it uninitialized, but in any case we shouldn't
  1.3670 +    // have NoImageData at this point.
  1.3671 +    MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData);
  1.3672 +
  1.3673 +    tex->SetImageInfo(target, level, width, height, format, type, imageInfoStatusIfSuccess);
  1.3674 +}
  1.3675 +
  1.3676 +void
  1.3677 +WebGLContext::TexImage2D(GLenum target, GLint level,
  1.3678 +                         GLenum internalformat, GLsizei width,
  1.3679 +                         GLsizei height, GLint border, GLenum format,
  1.3680 +                         GLenum type, const Nullable<ArrayBufferView> &pixels, ErrorResult& rv)
  1.3681 +{
  1.3682 +    if (IsContextLost())
  1.3683 +        return;
  1.3684 +
  1.3685 +    void* data;
  1.3686 +    uint32_t length;
  1.3687 +    int jsArrayType;
  1.3688 +    if (pixels.IsNull()) {
  1.3689 +        data = nullptr;
  1.3690 +        length = 0;
  1.3691 +        jsArrayType = -1;
  1.3692 +    } else {
  1.3693 +        const ArrayBufferView& view = pixels.Value();
  1.3694 +        view.ComputeLengthAndData();
  1.3695 +
  1.3696 +        data = view.Data();
  1.3697 +        length = view.Length();
  1.3698 +        jsArrayType = int(JS_GetArrayBufferViewType(view.Obj()));
  1.3699 +    }
  1.3700 +
  1.3701 +    return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
  1.3702 +                           data, length, jsArrayType,
  1.3703 +                           WebGLTexelFormat::Auto, false);
  1.3704 +}
  1.3705 +
  1.3706 +void
  1.3707 +WebGLContext::TexImage2D(GLenum target, GLint level,
  1.3708 +                         GLenum internalformat, GLenum format,
  1.3709 +                         GLenum type, ImageData* pixels, ErrorResult& rv)
  1.3710 +{
  1.3711 +    if (IsContextLost())
  1.3712 +        return;
  1.3713 +
  1.3714 +    if (!pixels) {
  1.3715 +        // Spec says to generate an INVALID_VALUE error
  1.3716 +        return ErrorInvalidValue("texImage2D: null ImageData");
  1.3717 +    }
  1.3718 +
  1.3719 +    Uint8ClampedArray arr(pixels->GetDataObject());
  1.3720 +    arr.ComputeLengthAndData();
  1.3721 +
  1.3722 +    return TexImage2D_base(target, level, internalformat, pixels->Width(),
  1.3723 +                           pixels->Height(), 4*pixels->Width(), 0,
  1.3724 +                           format, type, arr.Data(), arr.Length(), -1,
  1.3725 +                           WebGLTexelFormat::RGBA8, false);
  1.3726 +}
  1.3727 +
  1.3728 +
  1.3729 +void
  1.3730 +WebGLContext::TexSubImage2D_base(GLenum target, GLint level,
  1.3731 +                                 GLint xoffset, GLint yoffset,
  1.3732 +                                 GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
  1.3733 +                                 GLenum format, GLenum type,
  1.3734 +                                 void* data, uint32_t byteLength,
  1.3735 +                                 int jsArrayType,
  1.3736 +                                 WebGLTexelFormat srcFormat, bool srcPremultiplied)
  1.3737 +{
  1.3738 +    const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
  1.3739 +
  1.3740 +    if (!ValidateTexImage(2, target, level, format,
  1.3741 +                          xoffset, yoffset, 0,
  1.3742 +                          width, height, 0,
  1.3743 +                          0, format, type, func))
  1.3744 +    {
  1.3745 +        return;
  1.3746 +    }
  1.3747 +
  1.3748 +    if (!ValidateTexInputData(type, jsArrayType, func))
  1.3749 +        return;
  1.3750 +
  1.3751 +    WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
  1.3752 +    WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
  1.3753 +
  1.3754 +    uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
  1.3755 +
  1.3756 +    if (width == 0 || height == 0)
  1.3757 +        return; // ES 2.0 says it has no effect, we better return right now
  1.3758 +
  1.3759 +    CheckedUint32 checked_neededByteLength =
  1.3760 +        GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
  1.3761 +
  1.3762 +    CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
  1.3763 +
  1.3764 +    CheckedUint32 checked_alignedRowSize =
  1.3765 +        RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
  1.3766 +
  1.3767 +    if (!checked_neededByteLength.isValid())
  1.3768 +        return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
  1.3769 +
  1.3770 +    uint32_t bytesNeeded = checked_neededByteLength.value();
  1.3771 +
  1.3772 +    if (byteLength < bytesNeeded)
  1.3773 +        return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
  1.3774 +
  1.3775 +    WebGLTexture *tex = activeBoundTextureForTarget(target);
  1.3776 +    const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level);
  1.3777 +
  1.3778 +    if (imageInfo.HasUninitializedImageData())
  1.3779 +        tex->DoDeferredImageInitialization(target, level);
  1.3780 +
  1.3781 +    MakeContextCurrent();
  1.3782 +
  1.3783 +    size_t   srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
  1.3784 +    uint32_t dstTexelSize = GetBitsPerTexel(format, type) / 8;
  1.3785 +    size_t   dstPlainRowSize = dstTexelSize * width;
  1.3786 +    // There are checks above to ensure that this won't overflow.
  1.3787 +    size_t   dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mPixelStoreUnpackAlignment).value();
  1.3788 +
  1.3789 +    void* pixels = data;
  1.3790 +    nsAutoArrayPtr<uint8_t> convertedData;
  1.3791 +
  1.3792 +    // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
  1.3793 +    bool noConversion = (actualSrcFormat == dstFormat &&
  1.3794 +                         srcPremultiplied == mPixelStorePremultiplyAlpha &&
  1.3795 +                         srcStride == dstStride &&
  1.3796 +                         !mPixelStoreFlipY);
  1.3797 +
  1.3798 +    if (!noConversion) {
  1.3799 +        size_t convertedDataSize = height * dstStride;
  1.3800 +        convertedData = new uint8_t[convertedDataSize];
  1.3801 +        ConvertImage(width, height, srcStride, dstStride,
  1.3802 +                    static_cast<const uint8_t*>(data), convertedData,
  1.3803 +                    actualSrcFormat, srcPremultiplied,
  1.3804 +                    dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize);
  1.3805 +        pixels = reinterpret_cast<void*>(convertedData.get());
  1.3806 +    }
  1.3807 +
  1.3808 +    GLenum driverType = DriverTypeFromType(gl, type);
  1.3809 +    GLenum driverInternalFormat = LOCAL_GL_NONE;
  1.3810 +    GLenum driverFormat = LOCAL_GL_NONE;
  1.3811 +    DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat);
  1.3812 +
  1.3813 +    gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, driverFormat, driverType, pixels);
  1.3814 +}
  1.3815 +
  1.3816 +void
  1.3817 +WebGLContext::TexSubImage2D(GLenum target, GLint level,
  1.3818 +                            GLint xoffset, GLint yoffset,
  1.3819 +                            GLsizei width, GLsizei height,
  1.3820 +                            GLenum format, GLenum type,
  1.3821 +                            const Nullable<ArrayBufferView> &pixels,
  1.3822 +                            ErrorResult& rv)
  1.3823 +{
  1.3824 +    if (IsContextLost())
  1.3825 +        return;
  1.3826 +
  1.3827 +    if (pixels.IsNull())
  1.3828 +        return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
  1.3829 +
  1.3830 +    const ArrayBufferView& view = pixels.Value();
  1.3831 +    view.ComputeLengthAndData();
  1.3832 +
  1.3833 +    return TexSubImage2D_base(target, level, xoffset, yoffset,
  1.3834 +                              width, height, 0, format, type,
  1.3835 +                              view.Data(), view.Length(),
  1.3836 +                              JS_GetArrayBufferViewType(view.Obj()),
  1.3837 +                              WebGLTexelFormat::Auto, false);
  1.3838 +}
  1.3839 +
  1.3840 +void
  1.3841 +WebGLContext::TexSubImage2D(GLenum target, GLint level,
  1.3842 +                            GLint xoffset, GLint yoffset,
  1.3843 +                            GLenum format, GLenum type, ImageData* pixels,
  1.3844 +                            ErrorResult& rv)
  1.3845 +{
  1.3846 +    if (IsContextLost())
  1.3847 +        return;
  1.3848 +
  1.3849 +    if (!pixels)
  1.3850 +        return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
  1.3851 +
  1.3852 +    Uint8ClampedArray arr(pixels->GetDataObject());
  1.3853 +    arr.ComputeLengthAndData();
  1.3854 +
  1.3855 +    return TexSubImage2D_base(target, level, xoffset, yoffset,
  1.3856 +                              pixels->Width(), pixels->Height(),
  1.3857 +                              4*pixels->Width(), format, type,
  1.3858 +                              arr.Data(), arr.Length(),
  1.3859 +                              -1,
  1.3860 +                              WebGLTexelFormat::RGBA8, false);
  1.3861 +}
  1.3862 +
  1.3863 +bool
  1.3864 +WebGLContext::LoseContext()
  1.3865 +{
  1.3866 +    if (IsContextLost())
  1.3867 +        return false;
  1.3868 +
  1.3869 +    ForceLoseContext();
  1.3870 +
  1.3871 +    return true;
  1.3872 +}
  1.3873 +
  1.3874 +bool
  1.3875 +WebGLContext::RestoreContext()
  1.3876 +{
  1.3877 +    if (!IsContextLost() || !mAllowRestore) {
  1.3878 +        return false;
  1.3879 +    }
  1.3880 +
  1.3881 +    ForceRestoreContext();
  1.3882 +
  1.3883 +    return true;
  1.3884 +}
  1.3885 +
  1.3886 +bool
  1.3887 +BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize)
  1.3888 +{
  1.3889 +    switch (uType) {
  1.3890 +        case LOCAL_GL_INT:
  1.3891 +        case LOCAL_GL_INT_VEC2:
  1.3892 +        case LOCAL_GL_INT_VEC3:
  1.3893 +        case LOCAL_GL_INT_VEC4:
  1.3894 +        case LOCAL_GL_SAMPLER_2D:
  1.3895 +        case LOCAL_GL_SAMPLER_CUBE:
  1.3896 +            *baseType = LOCAL_GL_INT;
  1.3897 +            break;
  1.3898 +        case LOCAL_GL_FLOAT:
  1.3899 +        case LOCAL_GL_FLOAT_VEC2:
  1.3900 +        case LOCAL_GL_FLOAT_VEC3:
  1.3901 +        case LOCAL_GL_FLOAT_VEC4:
  1.3902 +        case LOCAL_GL_FLOAT_MAT2:
  1.3903 +        case LOCAL_GL_FLOAT_MAT3:
  1.3904 +        case LOCAL_GL_FLOAT_MAT4:
  1.3905 +            *baseType = LOCAL_GL_FLOAT;
  1.3906 +            break;
  1.3907 +        case LOCAL_GL_BOOL:
  1.3908 +        case LOCAL_GL_BOOL_VEC2:
  1.3909 +        case LOCAL_GL_BOOL_VEC3:
  1.3910 +        case LOCAL_GL_BOOL_VEC4:
  1.3911 +            *baseType = LOCAL_GL_BOOL; // pretend these are int
  1.3912 +            break;
  1.3913 +        default:
  1.3914 +            return false;
  1.3915 +    }
  1.3916 +
  1.3917 +    switch (uType) {
  1.3918 +        case LOCAL_GL_INT:
  1.3919 +        case LOCAL_GL_FLOAT:
  1.3920 +        case LOCAL_GL_BOOL:
  1.3921 +        case LOCAL_GL_SAMPLER_2D:
  1.3922 +        case LOCAL_GL_SAMPLER_CUBE:
  1.3923 +            *unitSize = 1;
  1.3924 +            break;
  1.3925 +        case LOCAL_GL_INT_VEC2:
  1.3926 +        case LOCAL_GL_FLOAT_VEC2:
  1.3927 +        case LOCAL_GL_BOOL_VEC2:
  1.3928 +            *unitSize = 2;
  1.3929 +            break;
  1.3930 +        case LOCAL_GL_INT_VEC3:
  1.3931 +        case LOCAL_GL_FLOAT_VEC3:
  1.3932 +        case LOCAL_GL_BOOL_VEC3:
  1.3933 +            *unitSize = 3;
  1.3934 +            break;
  1.3935 +        case LOCAL_GL_INT_VEC4:
  1.3936 +        case LOCAL_GL_FLOAT_VEC4:
  1.3937 +        case LOCAL_GL_BOOL_VEC4:
  1.3938 +            *unitSize = 4;
  1.3939 +            break;
  1.3940 +        case LOCAL_GL_FLOAT_MAT2:
  1.3941 +            *unitSize = 4;
  1.3942 +            break;
  1.3943 +        case LOCAL_GL_FLOAT_MAT3:
  1.3944 +            *unitSize = 9;
  1.3945 +            break;
  1.3946 +        case LOCAL_GL_FLOAT_MAT4:
  1.3947 +            *unitSize = 16;
  1.3948 +            break;
  1.3949 +        default:
  1.3950 +            return false;
  1.3951 +    }
  1.3952 +
  1.3953 +    return true;
  1.3954 +}
  1.3955 +
  1.3956 +
  1.3957 +WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum internalformat, GLenum type)
  1.3958 +{
  1.3959 +    //
  1.3960 +    // WEBGL_depth_texture
  1.3961 +    if (internalformat == LOCAL_GL_DEPTH_COMPONENT) {
  1.3962 +        switch (type) {
  1.3963 +            case LOCAL_GL_UNSIGNED_SHORT:
  1.3964 +                return WebGLTexelFormat::D16;
  1.3965 +            case LOCAL_GL_UNSIGNED_INT:
  1.3966 +                return WebGLTexelFormat::D32;
  1.3967 +        }
  1.3968 +
  1.3969 +        MOZ_CRASH("Invalid WebGL texture format/type?");
  1.3970 +    }
  1.3971 +
  1.3972 +    if (internalformat == LOCAL_GL_DEPTH_STENCIL) {
  1.3973 +        switch (type) {
  1.3974 +            case LOCAL_GL_UNSIGNED_INT_24_8_EXT:
  1.3975 +                return WebGLTexelFormat::D24S8;
  1.3976 +        }
  1.3977 +
  1.3978 +        MOZ_CRASH("Invalid WebGL texture format/type?");
  1.3979 +    }
  1.3980 +
  1.3981 +    if (internalformat == LOCAL_GL_DEPTH_COMPONENT16) {
  1.3982 +        return WebGLTexelFormat::D16;
  1.3983 +    }
  1.3984 +
  1.3985 +    if (internalformat == LOCAL_GL_DEPTH_COMPONENT32) {
  1.3986 +        return WebGLTexelFormat::D32;
  1.3987 +    }
  1.3988 +
  1.3989 +    if (internalformat == LOCAL_GL_DEPTH24_STENCIL8) {
  1.3990 +        return WebGLTexelFormat::D24S8;
  1.3991 +    }
  1.3992 +
  1.3993 +    if (type == LOCAL_GL_UNSIGNED_BYTE) {
  1.3994 +        switch (internalformat) {
  1.3995 +            case LOCAL_GL_RGBA:
  1.3996 +            case LOCAL_GL_SRGB_ALPHA_EXT:
  1.3997 +                return WebGLTexelFormat::RGBA8;
  1.3998 +            case LOCAL_GL_RGB:
  1.3999 +            case LOCAL_GL_SRGB_EXT:
  1.4000 +                return WebGLTexelFormat::RGB8;
  1.4001 +            case LOCAL_GL_ALPHA:
  1.4002 +                return WebGLTexelFormat::A8;
  1.4003 +            case LOCAL_GL_LUMINANCE:
  1.4004 +                return WebGLTexelFormat::R8;
  1.4005 +            case LOCAL_GL_LUMINANCE_ALPHA:
  1.4006 +                return WebGLTexelFormat::RA8;
  1.4007 +        }
  1.4008 +
  1.4009 +        MOZ_CRASH("Invalid WebGL texture format/type?");
  1.4010 +    }
  1.4011 +
  1.4012 +    if (type == LOCAL_GL_FLOAT) {
  1.4013 +        // OES_texture_float
  1.4014 +        switch (internalformat) {
  1.4015 +            case LOCAL_GL_RGBA:
  1.4016 +            case LOCAL_GL_RGBA32F:
  1.4017 +                return WebGLTexelFormat::RGBA32F;
  1.4018 +            case LOCAL_GL_RGB:
  1.4019 +            case LOCAL_GL_RGB32F:
  1.4020 +                return WebGLTexelFormat::RGB32F;
  1.4021 +            case LOCAL_GL_ALPHA:
  1.4022 +            case LOCAL_GL_ALPHA32F_ARB:
  1.4023 +                return WebGLTexelFormat::A32F;
  1.4024 +            case LOCAL_GL_LUMINANCE:
  1.4025 +            case LOCAL_GL_LUMINANCE32F_ARB:
  1.4026 +                return WebGLTexelFormat::R32F;
  1.4027 +            case LOCAL_GL_LUMINANCE_ALPHA:
  1.4028 +            case LOCAL_GL_LUMINANCE_ALPHA32F_ARB:
  1.4029 +                return WebGLTexelFormat::RA32F;
  1.4030 +        }
  1.4031 +
  1.4032 +        MOZ_CRASH("Invalid WebGL texture format/type?");
  1.4033 +    } else if (type == LOCAL_GL_HALF_FLOAT_OES) {
  1.4034 +        // OES_texture_half_float
  1.4035 +        switch (internalformat) {
  1.4036 +            case LOCAL_GL_RGBA:
  1.4037 +            case LOCAL_GL_RGBA16F:
  1.4038 +                return WebGLTexelFormat::RGBA16F;
  1.4039 +            case LOCAL_GL_RGB:
  1.4040 +            case LOCAL_GL_RGB16F:
  1.4041 +                return WebGLTexelFormat::RGB16F;
  1.4042 +            case LOCAL_GL_ALPHA:
  1.4043 +            case LOCAL_GL_ALPHA16F_ARB:
  1.4044 +                return WebGLTexelFormat::A16F;
  1.4045 +            case LOCAL_GL_LUMINANCE:
  1.4046 +            case LOCAL_GL_LUMINANCE16F_ARB:
  1.4047 +                return WebGLTexelFormat::R16F;
  1.4048 +            case LOCAL_GL_LUMINANCE_ALPHA:
  1.4049 +            case LOCAL_GL_LUMINANCE_ALPHA16F_ARB:
  1.4050 +                return WebGLTexelFormat::RA16F;
  1.4051 +            default:
  1.4052 +                MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
  1.4053 +                return WebGLTexelFormat::BadFormat;
  1.4054 +        }
  1.4055 +    }
  1.4056 +
  1.4057 +    switch (type) {
  1.4058 +        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
  1.4059 +           return WebGLTexelFormat::RGBA4444;
  1.4060 +        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
  1.4061 +           return WebGLTexelFormat::RGBA5551;
  1.4062 +        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
  1.4063 +           return WebGLTexelFormat::RGB565;
  1.4064 +        default:
  1.4065 +            MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
  1.4066 +            return WebGLTexelFormat::BadFormat;
  1.4067 +    }
  1.4068 +
  1.4069 +    MOZ_CRASH("Invalid WebGL texture format/type?");
  1.4070 +}
  1.4071 +
  1.4072 +void
  1.4073 +WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
  1.4074 +    if (IsContextLost())
  1.4075 +        return;
  1.4076 +    MakeContextCurrent();
  1.4077 +    gl->fBlendColor(r, g, b, a);
  1.4078 +}
  1.4079 +
  1.4080 +void
  1.4081 +WebGLContext::Flush() {
  1.4082 +    if (IsContextLost())
  1.4083 +        return;
  1.4084 +    MakeContextCurrent();
  1.4085 +    gl->fFlush();
  1.4086 +}
  1.4087 +
  1.4088 +void
  1.4089 +WebGLContext::Finish() {
  1.4090 +    if (IsContextLost())
  1.4091 +        return;
  1.4092 +    MakeContextCurrent();
  1.4093 +    gl->fFinish();
  1.4094 +}
  1.4095 +
  1.4096 +void
  1.4097 +WebGLContext::LineWidth(GLfloat width) {
  1.4098 +    if (IsContextLost())
  1.4099 +        return;
  1.4100 +    MakeContextCurrent();
  1.4101 +    gl->fLineWidth(width);
  1.4102 +}
  1.4103 +
  1.4104 +void
  1.4105 +WebGLContext::PolygonOffset(GLfloat factor, GLfloat units) {
  1.4106 +    if (IsContextLost())
  1.4107 +        return;
  1.4108 +    MakeContextCurrent();
  1.4109 +    gl->fPolygonOffset(factor, units);
  1.4110 +}
  1.4111 +
  1.4112 +void
  1.4113 +WebGLContext::SampleCoverage(GLclampf value, WebGLboolean invert) {
  1.4114 +    if (IsContextLost())
  1.4115 +        return;
  1.4116 +    MakeContextCurrent();
  1.4117 +    gl->fSampleCoverage(value, invert);
  1.4118 +}

mercurial