void
WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, const WebGLProgram& program,
                                              GLuint uniformBlockIndex, GLenum pname,
                                              JS::MutableHandleValue out_retval,
                                              ErrorResult& out_error)
{
    out_retval.setNull();
    if (IsContextLost())
        return;

    if (!ValidateObject("getActiveUniformBlockParameter: program", program))
        return;

    MakeContextCurrent();

    switch(pname) {
    case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
    case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
    case LOCAL_GL_UNIFORM_BLOCK_BINDING:
    case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE:
    case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
        out_retval.set(program.GetActiveUniformBlockParam(uniformBlockIndex, pname));
        return;

    case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
        out_retval.set(program.GetActiveUniformBlockActiveUniforms(cx, uniformBlockIndex,
                                                                   &out_error));
        return;
    }

    ErrorInvalidEnumInfo("getActiveUniformBlockParameter: parameter", pname);
}
GLuint WebGL2Context::GetUniformBlockIndex(const WebGLProgram& program,
                                           const nsAString& uniformBlockName) {
  const FuncScope funcScope(*this, "getUniformBlockIndex");
  if (IsContextLost()) return 0;

  if (!ValidateObject("program", program)) return 0;

  return program.GetUniformBlockIndex(uniformBlockName);
}
void WebGL2Context::UniformBlockBinding(WebGLProgram& program,
                                        GLuint uniformBlockIndex,
                                        GLuint uniformBlockBinding) {
  const FuncScope funcScope(*this, "uniformBlockBinding");
  if (IsContextLost()) return;

  if (!ValidateObject("program", program)) return;

  program.UniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
}
void WebGL2Context::GetActiveUniformBlockName(const WebGLProgram& program,
                                              GLuint uniformBlockIndex,
                                              nsAString& retval) {
  const FuncScope funcScope(*this, "getActiveUniformBlockName");
  retval.SetIsVoid(true);
  if (IsContextLost()) return;

  if (!ValidateObject("program", program)) return;

  program.GetActiveUniformBlockName(uniformBlockIndex, retval);
}
already_AddRefed<WebGLActiveInfo>
WebGL2Context::GetTransformFeedbackVarying(const WebGLProgram& program, GLuint index)
{
    if (IsContextLost())
        return nullptr;

    if (!ValidateObject("getTransformFeedbackVarying: program", program))
        return nullptr;

    return program.GetTransformFeedbackVarying(index);
}
void
WebGL2Context::UniformBlockBinding(WebGLProgram& program, GLuint uniformBlockIndex,
                                   GLuint uniformBlockBinding)
{
    if (IsContextLost())
        return;

    if (!ValidateObject("uniformBlockBinding: program", program))
        return;

    program.UniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
}
GLuint
WebGL2Context::GetUniformBlockIndex(const WebGLProgram& program,
                                    const nsAString& uniformBlockName)
{
    if (IsContextLost())
        return 0;

    if (!ValidateObject("getUniformBlockIndex: program", program))
        return 0;

    return program.GetUniformBlockIndex(uniformBlockName);
}
void WebGL2Context::GetUniformIndices(
    const WebGLProgram& program, const dom::Sequence<nsString>& uniformNames,
    dom::Nullable<nsTArray<GLuint> >& retval) {
  const FuncScope funcScope(*this, "getUniformIndices");
  retval.SetNull();
  if (IsContextLost()) return;

  if (!ValidateObject("program", program)) return;

  if (!uniformNames.Length()) return;

  program.GetUniformIndices(uniformNames, retval);
}
void
WebGL2Context::TransformFeedbackVaryings(WebGLProgram& program,
                                         const dom::Sequence<nsString>& varyings,
                                         GLenum bufferMode)
{
    if (IsContextLost())
        return;

    if (!ValidateObject("transformFeedbackVaryings: program", program))
        return;

    program.TransformFeedbackVaryings(varyings, bufferMode);
}
void
WebGL2Context::GetActiveUniforms(JSContext* cx, const WebGLProgram& program,
                                 const dom::Sequence<GLuint>& uniformIndices,
                                 GLenum pname, JS::MutableHandleValue retval)
{
    const char funcName[] = "getActiveUniforms";
    retval.setNull();
    if (IsContextLost())
        return;

    if (!ValidateUniformEnum(this, pname, funcName))
        return;

    if (!ValidateObject("getActiveUniforms: program", program))
        return;

    const auto& numActiveUniforms = program.LinkInfo()->uniforms.size();
    for (const auto& curIndex : uniformIndices) {
        if (curIndex >= numActiveUniforms) {
            ErrorInvalidValue("%s: Too-large active uniform index queried.", funcName);
            return;
        }
    }

    const auto& count = uniformIndices.Length();

    JS::Rooted<JSObject*> array(cx, JS_NewArrayObject(cx, count));
    UniquePtr<GLint[]> samples(new GLint[count]);
    if (!array || !samples) {
        ErrorOutOfMemory("%s: Failed to allocate buffers.", funcName);
        return;
    }
    retval.setObject(*array);

    MakeContextCurrent();
    gl->fGetActiveUniformsiv(program.mGLName, count, uniformIndices.Elements(), pname,
                             samples.get());

    switch (pname) {
    case LOCAL_GL_UNIFORM_TYPE:
    case LOCAL_GL_UNIFORM_SIZE:
    case LOCAL_GL_UNIFORM_BLOCK_INDEX:
    case LOCAL_GL_UNIFORM_OFFSET:
    case LOCAL_GL_UNIFORM_ARRAY_STRIDE:
    case LOCAL_GL_UNIFORM_MATRIX_STRIDE:
        for (size_t i = 0; i < count; ++i) {
            JS::RootedValue value(cx);
            value = JS::Int32Value(samples[i]);
            if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE))
                return;
        }
        break;
    case LOCAL_GL_UNIFORM_IS_ROW_MAJOR:
        for (size_t i = 0; i < count; ++i) {
            JS::RootedValue value(cx);
            value = JS::BooleanValue(samples[i]);
            if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE))
                return;
        }
        break;

    default:
        MOZ_CRASH("Invalid pname");
    }
}