Bug 1063053 - Add stronger types to WebGL texture code for better debug/compile time checking. r=jgilbert,kamidphish
authorWalter Litwinczyk <wlitwinczyk@mozilla.com>
Thu, 18 Sep 2014 16:14:22 -0700
changeset 206280 7283eb58334189852bb1aa06c611b599f3c31109
parent 206279 f5a2e2a16e8469d994620b9f863837f38089c355
child 206281 3f395d9d894a542339348a067951096f01edced6
push id27520
push userkwierso@gmail.com
push dateSat, 20 Sep 2014 00:25:19 +0000
treeherdermozilla-central@27253887d2cc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert, kamidphish
bugs1063053
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1063053 - Add stronger types to WebGL texture code for better debug/compile time checking. r=jgilbert,kamidphish
dom/canvas/WebGLBindableName.cpp
dom/canvas/WebGLBindableName.h
dom/canvas/WebGLBuffer.cpp
dom/canvas/WebGLBuffer.h
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextUtils.cpp
dom/canvas/WebGLContextUtils.h
dom/canvas/WebGLContextValidate.cpp
dom/canvas/WebGLFramebuffer.cpp
dom/canvas/WebGLFramebuffer.h
dom/canvas/WebGLRenderbuffer.cpp
dom/canvas/WebGLRenderbuffer.h
dom/canvas/WebGLSampler.cpp
dom/canvas/WebGLSampler.h
dom/canvas/WebGLStrongTypes.h
dom/canvas/WebGLTexture.cpp
dom/canvas/WebGLTexture.h
dom/canvas/WebGLTransformFeedback.cpp
dom/canvas/WebGLTransformFeedback.h
dom/canvas/WebGLVertexArray.cpp
dom/canvas/WebGLVertexArray.h
dom/canvas/moz.build
deleted file mode 100644
--- a/dom/canvas/WebGLBindableName.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "WebGLBindableName.h"
-#include "GLConsts.h"
-#include "mozilla/Assertions.h"
-
-using namespace mozilla;
-
-WebGLBindableName::WebGLBindableName()
-    : mGLName(LOCAL_GL_NONE)
-    , mTarget(LOCAL_GL_NONE)
-{ }
-
-void
-WebGLBindableName::BindTo(GLenum target)
-{
-    MOZ_ASSERT(target != LOCAL_GL_NONE, "Can't bind to GL_NONE.");
-    MOZ_ASSERT(mTarget == LOCAL_GL_NONE || mTarget == target, "Rebinding is illegal.");
-
-    bool targetChanged = (target != mTarget);
-    mTarget = target;
-    if (targetChanged)
-        OnTargetChanged();
-}
--- a/dom/canvas/WebGLBindableName.h
+++ b/dom/canvas/WebGLBindableName.h
@@ -3,34 +3,56 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGLBINDABLENAME_H_
 #define WEBGLBINDABLENAME_H_
 
 #include "WebGLTypes.h"
 
+#include "GLDefs.h"
+#include "mozilla/TypeTraits.h"
+#include "mozilla/Assertions.h"
+
 namespace mozilla {
 
 /** Represents a GL name that can be bound to a target.
  */
+template<typename T>
 class WebGLBindableName
 {
 public:
-    WebGLBindableName();
-    void BindTo(GLenum target);
+
+    WebGLBindableName()
+        : mGLName(0)
+        , mTarget(LOCAL_GL_NONE)
+    { }
+
+    void BindTo(T target)
+    {
+        MOZ_ASSERT(target != LOCAL_GL_NONE, "Can't bind to GL_NONE.");
+        MOZ_ASSERT(!HasEverBeenBound() || mTarget == target, "Rebinding is illegal.");
 
-    bool HasEverBeenBound() const { return mTarget != 0; }
+        bool targetChanged = (target != mTarget);
+        mTarget = target;
+        if (targetChanged)
+            OnTargetChanged();
+    }
+
+    bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; }
     GLuint GLName() const { return mGLName; }
-    GLenum Target() const { return mTarget; }
+    T Target() const {
+        MOZ_ASSERT(HasEverBeenBound());
+        return mTarget;
+    }
 
 protected:
 
     //! Called after mTarget has been changed by BindTo(target).
     virtual void OnTargetChanged() {}
 
     GLuint mGLName;
-    GLenum mTarget;
+    T mTarget;
 };
 
 } // namespace mozilla
 
 #endif // !WEBGLBINDABLENAME_H_
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -8,17 +8,17 @@
 #include "GLContext.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "WebGLContext.h"
 #include "WebGLElementArrayCache.h"
 
 using namespace mozilla;
 
 WebGLBuffer::WebGLBuffer(WebGLContext *context)
-    : WebGLBindableName()
+    : WebGLBindableName<GLenum>()
     , WebGLContextBoundObject(context)
     , mByteLength(0)
 {
     SetIsDOMBinding();
     mContext->MakeContextCurrent();
     mContext->gl->fGenBuffers(1, &mGLName);
     mContext->mBuffers.insertBack(this);
 }
--- a/dom/canvas/WebGLBuffer.h
+++ b/dom/canvas/WebGLBuffer.h
@@ -15,17 +15,17 @@
 #include "WebGLTypes.h"
 
 namespace mozilla {
 
 class WebGLElementArrayCache;
 
 class WebGLBuffer MOZ_FINAL
     : public nsWrapperCache
-    , public WebGLBindableName
+    , public WebGLBindableName<GLenum>
     , public WebGLRefCountedObject<WebGLBuffer>
     , public LinkedListElement<WebGLBuffer>
     , public WebGLContextBoundObject
 {
 public:
     explicit WebGLBuffer(WebGLContext* aContext);
 
     void Delete();
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1741,17 +1741,17 @@ WebGLContext::GetSurfaceSnapshot(bool* a
 void
 WebGLContext::DidRefresh()
 {
     if (gl) {
         gl->FlushIfHeavyGLCallsSinceLastFlush();
     }
 }
 
-bool WebGLContext::TexImageFromVideoElement(GLenum texImageTarget, GLint level,
+bool WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget, GLint level,
                               GLenum internalformat, GLenum format, GLenum type,
                               mozilla::dom::Element& elt)
 {
     HTMLVideoElement* video = HTMLVideoElement::FromContentOrNull(&elt);
     if (!video) {
         return false;
     }
 
@@ -1788,19 +1788,19 @@ bool WebGLContext::TexImageFromVideoElem
     nsRefPtr<mozilla::layers::Image> srcImage = container->LockCurrentImage();
     WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
 
     const WebGLTexture::ImageInfo& info = tex->ImageInfoAt(texImageTarget, 0);
     bool dimensionsMatch = info.Width() == srcImage->GetSize().width &&
                            info.Height() == srcImage->GetSize().height;
     if (!dimensionsMatch) {
         // we need to allocation
-        gl->fTexImage2D(texImageTarget, level, internalformat, srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr);
+        gl->fTexImage2D(texImageTarget.get(), level, internalformat, srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr);
     }
-    bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), tex->GLName(), texImageTarget, mPixelStoreFlipY);
+    bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), tex->GLName(), texImageTarget.get(), mPixelStoreFlipY);
     if (ok) {
         tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, format, type, WebGLImageDataStatus::InitializedImageData);
         tex->Bind(TexImageTargetToTexTarget(texImageTarget));
     }
     srcImage = nullptr;
     container->UnlockCurrentImage();
     return ok;
 }
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -12,16 +12,17 @@
 #include "mozilla/LinkedList.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 
 #include "GLDefs.h"
 #include "WebGLActiveInfo.h"
 #include "WebGLObjectModel.h"
 #include "WebGLRenderbuffer.h"
+#include "WebGLStrongTypes.h"
 #include <stdarg.h>
 
 #include "nsTArray.h"
 #include "nsCycleCollectionNoteChild.h"
 
 #include "nsIDOMWebGLRenderingContext.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
@@ -118,17 +119,17 @@ struct WebGLContextOptions {
     bool depth;
     bool stencil;
     bool premultipliedAlpha;
     bool antialias;
     bool preserveDrawingBuffer;
 };
 
 // From WebGLContextUtils
-GLenum TexImageTargetToTexTarget(GLenum texImageTarget);
+TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget);
 
 class WebGLContext :
     public nsIDOMWebGLRenderingContext,
     public nsICanvasRenderingContextInternal,
     public nsSupportsWeakReference,
     public WebGLRectangleObject,
     public nsWrapperCache,
     public SupportsWeakPtr<WebGLContext>
@@ -219,28 +220,27 @@ public:
      * keep consistency with how errors are reported from WebGL.
      */
     static const char *EnumName(GLenum glenum);
 
     bool IsTextureFormatCompressed(GLenum format);
 
     void DummyFramebufferOperation(const char *info);
 
-    WebGLTexture* activeBoundTextureForTarget(GLenum texTarget) const {
-        MOZ_ASSERT(texTarget == LOCAL_GL_TEXTURE_2D || texTarget == LOCAL_GL_TEXTURE_CUBE_MAP);
+    WebGLTexture* activeBoundTextureForTarget(const TexTarget texTarget) const {
         return texTarget == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
                                                 : mBoundCubeMapTextures[mActiveTexture];
     }
 
     /* Use this function when you have the texture image target, for example:
      * GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP_[POSITIVE|NEGATIVE]_[X|Y|Z], and
      * not the actual texture binding target: GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
      */
-    WebGLTexture* activeBoundTextureForTexImageTarget(GLenum texImgTarget) const {
-        const GLenum texTarget = TexImageTargetToTexTarget(texImgTarget);
+    WebGLTexture* activeBoundTextureForTexImageTarget(const TexImageTarget texImgTarget) const {
+        const TexTarget texTarget = TexImageTargetToTexTarget(texImgTarget);
         return activeBoundTextureForTarget(texTarget);
     }
 
     already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                                  CanvasLayer *aOldLayer,
                                                  LayerManager *aManager) MOZ_OVERRIDE;
 
     // Note that 'clean' here refers to its invalidation state, not the
@@ -460,43 +460,46 @@ public:
                     GLenum type,
                     const Nullable<dom::ArrayBufferView> &pixels,
                     ErrorResult& rv);
     void TexImage2D(GLenum target, GLint level,
                     GLenum internalformat, GLenum format, GLenum type,
                     dom::ImageData* pixels, ErrorResult& rv);
     // Allow whatever element types the bindings are willing to pass
     // us in TexImage2D
-    bool TexImageFromVideoElement(GLenum texImageTarget, GLint level,
+    bool TexImageFromVideoElement(TexImageTarget texImageTarget, GLint level,
                                   GLenum internalformat, GLenum format, GLenum type,
                                   mozilla::dom::Element& image);
 
     template<class ElementType>
-    void TexImage2D(GLenum texImageTarget, GLint level,
+    void TexImage2D(GLenum rawTexImgTarget, GLint level,
                     GLenum internalformat, GLenum format, GLenum type,
                     ElementType& elt, ErrorResult& rv)
     {
         if (IsContextLost())
             return;
 
-        const GLenum target = TexImageTargetToTexTarget(texImageTarget);
-        if (target == LOCAL_GL_NONE)
-            return ErrorInvalidEnumInfo("texImage2D: target", target);
+        auto dims = 2;
+
+        if (!ValidateTexImageTarget(dims, rawTexImgTarget, WebGLTexImageFunc::TexImage))
+            return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImgTarget);
+
+        const TexImageTarget texImageTarget(rawTexImgTarget);
 
         if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
             return;
 
         if (level < 0)
             return ErrorInvalidValue("texImage2D: level is negative");
 
         const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
         if (level > maxLevel)
             return ErrorInvalidValue("texImage2D: level %d is too large, max is %d", level, maxLevel);
 
-        WebGLTexture* tex = activeBoundTextureForTarget(target);
+        WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
 
         if (!tex)
             return ErrorInvalidOperation("no texture is bound to this target");
 
         // Trying to handle the video by GPU directly first
         if (TexImageFromVideoElement(texImageTarget, level, internalformat, format, type, elt)) {
             return;
         }
@@ -531,26 +534,27 @@ public:
                        const Nullable<dom::ArrayBufferView> &pixels,
                        ErrorResult& rv);
     void TexSubImage2D(GLenum target, GLint level,
                        GLint xoffset, GLint yoffset, GLenum format,
                        GLenum type, dom::ImageData* pixels, ErrorResult& rv);
     // Allow whatever element types the bindings are willing to pass
     // us in TexSubImage2D
     template<class ElementType>
-    void TexSubImage2D(GLenum texImageTarget, GLint level,
+    void TexSubImage2D(GLenum rawTexImageTarget, GLint level,
                        GLint xoffset, GLint yoffset, GLenum format,
                        GLenum type, ElementType& elt, ErrorResult& rv)
     {
         if (IsContextLost())
             return;
 
-        const GLenum target = TexImageTargetToTexTarget(texImageTarget);
-        if (target == LOCAL_GL_NONE)
-            return ErrorInvalidEnumInfo("texSubImage2D: target", texImageTarget);
+        if (!ValidateTexImageTarget(2, rawTexImageTarget, WebGLTexImageFunc::TexSubImage))
+            return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget);
+
+        const TexImageTarget texImageTarget(rawTexImageTarget);
 
         if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
             return;
 
         if (level < 0)
             return ErrorInvalidValue("texSubImage2D: level is negative");
 
         const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
@@ -1083,35 +1087,35 @@ protected:
     bool ValidateAttribIndex(GLuint index, const char *info);
     bool ValidateStencilParamsForDrawCall();
 
     bool ValidateGLSLVariableName(const nsAString& name, const char *info);
     bool ValidateGLSLCharacter(char16_t c);
     bool ValidateGLSLString(const nsAString& string, const char *info);
 
     bool ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func);
-    bool ValidateTexImage(GLuint dims, GLenum target,
+    bool ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
                           GLint level, GLint internalFormat,
                           GLint xoffset, GLint yoffset, GLint zoffset,
                           GLint width, GLint height, GLint depth,
                           GLint border, GLenum format, GLenum type,
                           WebGLTexImageFunc func);
     bool ValidateTexImageTarget(GLuint dims, GLenum target, WebGLTexImageFunc func);
     bool ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func);
     bool ValidateTexImageType(GLenum type, WebGLTexImageFunc func);
     bool ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTexImageFunc func);
-    bool ValidateTexImageSize(GLenum target, GLint level,
+    bool ValidateTexImageSize(TexImageTarget target, GLint level,
                               GLint width, GLint height, GLint depth,
                               WebGLTexImageFunc func);
     bool ValidateTexSubImageSize(GLint x, GLint y, GLint z,
                                  GLsizei width, GLsizei height, GLsizei depth,
                                  GLsizei baseWidth, GLsizei baseHeight, GLsizei baseDepth,
                                  WebGLTexImageFunc func);
 
-    bool ValidateCompTexImageSize(GLenum target, GLint level, GLenum format,
+    bool ValidateCompTexImageSize(GLint level, GLenum format,
                                   GLint xoffset, GLint yoffset,
                                   GLsizei width, GLsizei height,
                                   GLsizei levelWidth, GLsizei levelHeight,
                                   WebGLTexImageFunc func);
     bool ValidateCompTexImageDataSize(GLint level, GLenum format,
                                       GLsizei width, GLsizei height,
                                       uint32_t byteLength, WebGLTexImageFunc func);
 
@@ -1119,23 +1123,23 @@ protected:
     static uint32_t GetBitsPerTexel(GLenum format, GLenum type);
 
     void Invalidate();
     void DestroyResourcesAndContext();
 
     void MakeContextCurrent() const;
 
     // helpers
-    void TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
+    void TexImage2D_base(TexImageTarget target, GLint level, GLenum internalformat,
                          GLsizei width, GLsizei height, GLsizei srcStrideOrZero, GLint border,
                          GLenum format, GLenum type,
                          void *data, uint32_t byteLength,
                          int jsArrayType,
                          WebGLTexelFormat srcFormat, bool srcPremultiplied);
-    void TexSubImage2D_base(GLenum target, GLint level,
+    void TexSubImage2D_base(TexImageTarget target, GLint level,
                             GLint xoffset, GLint yoffset,
                             GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
                             GLenum format, GLenum type,
                             void *pixels, uint32_t byteLength,
                             int jsArrayType,
                             WebGLTexelFormat srcFormat, bool srcPremultiplied);
     void TexParameter_base(GLenum target, GLenum pname,
                            GLint *intParamPtr, GLfloat *floatParamPtr);
@@ -1163,17 +1167,17 @@ protected:
     {
       return SurfaceFromElement(&aElement);
     }
 
     nsresult SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
                                                     RefPtr<gfx::DataSourceSurface>& imageOut,
                                                     WebGLTexelFormat *format);
 
-    void CopyTexSubImage2D_base(GLenum target,
+    void CopyTexSubImage2D_base(TexImageTarget texImageTarget,
                                 GLint level,
                                 GLenum internalformat,
                                 GLint xoffset,
                                 GLint yoffset,
                                 GLint x,
                                 GLint y,
                                 GLsizei width,
                                 GLsizei height,
@@ -1195,39 +1199,34 @@ protected:
     bool ValidateObjectAllowDeleted(const char* info, ObjectType *aObject);
 private:
     // Like ValidateObject, but only for cases when aObject is known
     // to not be null already.
     template<class ObjectType>
     bool ValidateObjectAssumeNonNull(const char* info, ObjectType *aObject);
 
 protected:
-    int32_t MaxTextureSizeForTarget(GLenum target) const {
-        MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D ||
-                   (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
-                    target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z),
-                   "Invalid target enum");
+    int32_t MaxTextureSizeForTarget(TexTarget target) const {
         return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize : mGLMaxCubeMapTextureSize;
     }
 
-    int32_t MaxTextureLevelForTexImageTarget(GLenum texImageTarget) const {
-        const GLenum target = TexImageTargetToTexTarget(texImageTarget);
-        MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP);
+    int32_t MaxTextureLevelForTexImageTarget(TexImageTarget texImageTarget) const {
+        const TexTarget target = TexImageTargetToTexTarget(texImageTarget);
         return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSizeLog2 : mGLMaxCubeMapTextureSizeLog2;
     }
 
     /** like glBufferData but if the call may change the buffer size, checks any GL error generated
      * by this glBufferData call and returns it */
     GLenum CheckedBufferData(GLenum target,
                              GLsizeiptr size,
                              const GLvoid *data,
                              GLenum usage);
     /** like glTexImage2D but if the call may change the texture size, checks any GL error generated
      * by this glTexImage2D call and returns it */
-    GLenum CheckedTexImage2D(GLenum target,
+    GLenum CheckedTexImage2D(TexImageTarget texImageTarget,
                              GLint level,
                              GLenum internalFormat,
                              GLsizei width,
                              GLsizei height,
                              GLint border,
                              GLenum format,
                              GLenum type,
                              const GLvoid *data);
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -210,46 +210,49 @@ WebGLContext::BindRenderbuffer(GLenum ta
     } else {
         gl->fBindRenderbuffer(target, 0);
     }
 
     mBoundRenderbuffer = wrb;
 }
 
 void
-WebGLContext::BindTexture(GLenum target, WebGLTexture *newTex)
+WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture *newTex)
 {
     if (IsContextLost())
         return;
 
      if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex))
         return;
 
-    if (newTex) {
-        // silently ignore a deleted texture
-        if (newTex->IsDeleted())
-            return;
-
-        if (newTex->Target() != LOCAL_GL_NONE && newTex->Target() != target)
-            return ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
-    }
-
+    // Need to check rawTarget first before comparing against newTex->Target() as
+    // newTex->Target() returns a TexTarget, which will assert on invalid value.
     WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
-
-    switch (target) {
+    switch (rawTarget) {
         case LOCAL_GL_TEXTURE_2D:
             currentTexPtr = &mBound2DTextures[mActiveTexture];
             break;
        case LOCAL_GL_TEXTURE_CUBE_MAP:
             currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
             break;
        default:
-            return ErrorInvalidEnumInfo("bindTexture: target", target);
+            return ErrorInvalidEnumInfo("bindTexture: target", rawTarget);
     }
 
+    if (newTex) {
+        // silently ignore a deleted texture
+        if (newTex->IsDeleted())
+            return;
+
+        if (newTex->HasEverBeenBound() && newTex->Target() != rawTarget)
+            return ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
+    }
+
+    const TexTarget target(rawTarget);
+
     WebGLTextureFakeBlackStatus currentTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
     if (*currentTexPtr) {
         currentTexFakeBlackStatus = (*currentTexPtr)->ResolvedFakeBlackStatus();
     }
     WebGLTextureFakeBlackStatus newTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
     if (newTex) {
         newTexFakeBlackStatus = newTex->ResolvedFakeBlackStatus();
     }
@@ -260,17 +263,17 @@ WebGLContext::BindTexture(GLenum target,
         SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
     }
 
     MakeContextCurrent();
 
     if (newTex)
         newTex->Bind(target);
     else
-        gl->fBindTexture(target, 0 /* == texturename */);
+        gl->fBindTexture(target.get(), 0 /* == texturename */);
 }
 
 void WebGLContext::BlendEquation(GLenum mode)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateBlendEquationEnum(mode, "blendEquation: mode"))
@@ -344,17 +347,17 @@ WebGLContext::CheckFramebufferStatus(GLe
 
     if (!mBoundFramebuffer)
         return LOCAL_GL_FRAMEBUFFER_COMPLETE;
 
     return mBoundFramebuffer->CheckFramebufferStatus();
 }
 
 void
-WebGLContext::CopyTexSubImage2D_base(GLenum target,
+WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
                                      GLint level,
                                      GLenum internalformat,
                                      GLint xoffset,
                                      GLint yoffset,
                                      GLint x,
                                      GLint y,
                                      GLsizei width,
                                      GLsizei height,
@@ -364,43 +367,43 @@ WebGLContext::CopyTexSubImage2D_base(GLe
     GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
     GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
 
     const char* info = sub ? "copyTexSubImage2D" : "copyTexImage2D";
     WebGLTexImageFunc func = sub ? WebGLTexImageFunc::CopyTexSubImage : WebGLTexImageFunc::CopyTexImage;
 
     // TODO: This changes with color_buffer_float. Reassess when the
     // patch lands.
-    if (!ValidateTexImage(2, target, level, internalformat,
+    if (!ValidateTexImage(2, texImageTarget, level, internalformat,
                           xoffset, yoffset, 0,
                           width, height, 0,
                           0, internalformat, LOCAL_GL_UNSIGNED_BYTE,
                           func))
     {
         return;
     }
 
     if (!ValidateCopyTexImage(internalformat, func))
         return;
 
     if (!mBoundFramebuffer)
         ClearBackbufferIfNeeded();
 
     MakeContextCurrent();
 
-    WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
+    WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
 
     if (!tex)
         return ErrorInvalidOperation("%s: no texture is bound to this target");
 
     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
         if (sub)
-            gl->fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+            gl->fCopyTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, x, y, width, height);
         else
-            gl->fCopyTexImage2D(target, level, internalformat, x, y, width, height, 0);
+            gl->fCopyTexImage2D(texImageTarget.get(), level, internalformat, x, y, width, height, 0);
     } else {
 
         // the rect doesn't fit in the framebuffer
 
         /*** first, we initialize the texture as black ***/
 
         // first, compute the size of the buffer we should allocate to initialize the texture as black
 
@@ -424,20 +427,20 @@ WebGLContext::CopyTexSubImage2D_base(GLe
         // Hopefully calloc will just mmap zero pages here.
         void* tempZeroData = calloc(1, bytesNeeded);
         if (!tempZeroData)
             return ErrorOutOfMemory("%s: could not allocate %d bytes (for zero fill)", info, bytesNeeded);
 
         // now initialize the texture as black
 
         if (sub)
-            gl->fTexSubImage2D(target, level, 0, 0, width, height,
+            gl->fTexSubImage2D(texImageTarget.get(), level, 0, 0, width, height,
                                internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
         else
-            gl->fTexImage2D(target, level, internalformat, width, height,
+            gl->fTexImage2D(texImageTarget.get(), level, internalformat, width, height,
                             0, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
         free(tempZeroData);
 
         // if we are completely outside of the framebuffer, we can exit now with our black texture
         if (   x >= framebufferWidth
             || x+width <= 0
             || y >= framebufferHeight
             || y+height <= 0)
@@ -451,146 +454,153 @@ WebGLContext::CopyTexSubImage2D_base(GLe
         GLsizei actual_width   = actual_x_plus_width  - actual_x;
         GLint   actual_xoffset = xoffset + actual_x - x;
 
         GLint   actual_y             = clamped(y, 0, framebufferHeight);
         GLint   actual_y_plus_height = clamped(y + height, 0, framebufferHeight);
         GLsizei actual_height  = actual_y_plus_height - actual_y;
         GLint   actual_yoffset = yoffset + actual_y - y;
 
-        gl->fCopyTexSubImage2D(target, level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height);
+        gl->fCopyTexSubImage2D(texImageTarget.get(), level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height);
     }
 }
 
 void
-WebGLContext::CopyTexImage2D(GLenum target,
+WebGLContext::CopyTexImage2D(GLenum rawTexImgTarget,
                              GLint level,
                              GLenum internalformat,
                              GLint x,
                              GLint y,
                              GLsizei width,
                              GLsizei height,
                              GLint border)
 {
     if (IsContextLost())
         return;
 
     // copyTexImage2D only generates textures with type = UNSIGNED_BYTE
     const WebGLTexImageFunc func = WebGLTexImageFunc::CopyTexImage;
     const GLenum format = internalformat; // WebGL/ES Format
     const GLenum type = LOCAL_GL_UNSIGNED_BYTE; // WebGL/ES Format
 
-    if (!ValidateTexImage(2, target, level, format,
+    if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CopyTexImage))
+        return;
+
+    if (!ValidateTexImage(2, rawTexImgTarget, level, format,
                           0, 0, 0,
                           width, height, 0,
                           border, format, type,
                           func))
     {
         return;
     }
 
     if (!ValidateCopyTexImage(format, func))
         return;
 
     if (!mBoundFramebuffer)
         ClearBackbufferIfNeeded();
 
+    const TexImageTarget texImageTarget(rawTexImgTarget);
+
     // check if the memory size of this texture may change with this call
     bool sizeMayChange = true;
-    WebGLTexture* tex = activeBoundTextureForTexImageTarget(target);
-    if (tex->HasImageInfoAt(target, level)) {
-        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
+    WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
+    if (tex->HasImageInfoAt(texImageTarget, level)) {
+        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
 
         sizeMayChange = width != imageInfo.Width() ||
                         height != imageInfo.Height() ||
                         format != imageInfo.WebGLFormat() ||
                         type != imageInfo.WebGLType();
     }
 
     if (sizeMayChange)
         GetAndFlushUnderlyingGLErrors();
 
-    CopyTexSubImage2D_base(target, level, format, 0, 0, x, y, width, height, false);
+    CopyTexSubImage2D_base(texImageTarget, level, format, 0, 0, x, y, width, height, false);
 
     if (sizeMayChange) {
         GLenum error = GetAndFlushUnderlyingGLErrors();
         if (error) {
             GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
             return;
         }
     }
 
-    tex->SetImageInfo(target, level, width, height, format, type,
+    tex->SetImageInfo(texImageTarget, level, width, height, format, type,
                       WebGLImageDataStatus::InitializedImageData);
 }
 
 void
-WebGLContext::CopyTexSubImage2D(GLenum target,
+WebGLContext::CopyTexSubImage2D(GLenum rawTexImgTarget,
                                 GLint level,
                                 GLint xoffset,
                                 GLint yoffset,
                                 GLint x,
                                 GLint y,
                                 GLsizei width,
                                 GLsizei height)
 {
     if (IsContextLost())
         return;
 
-    switch (target) {
+    switch (rawTexImgTarget) {
         case LOCAL_GL_TEXTURE_2D:
         case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
         case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
         case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
         case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
         case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
         case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
             break;
         default:
-            return ErrorInvalidEnumInfo("copyTexSubImage2D: target", target);
+            return ErrorInvalidEnumInfo("copyTexSubImage2D: target", rawTexImgTarget);
     }
 
+    const TexImageTarget texImageTarget(rawTexImgTarget);
+
     if (level < 0)
         return ErrorInvalidValue("copyTexSubImage2D: level may not be negative");
 
-    GLsizei maxTextureSize = MaxTextureSizeForTarget(target);
+    GLsizei maxTextureSize = MaxTextureSizeForTarget(TexImageTargetToTexTarget(texImageTarget));
     if (!(maxTextureSize >> level))
         return ErrorInvalidValue("copyTexSubImage2D: 2^level exceeds maximum texture size");
 
     if (width < 0 || height < 0)
         return ErrorInvalidValue("copyTexSubImage2D: width and height may not be negative");
 
     if (xoffset < 0 || yoffset < 0)
         return ErrorInvalidValue("copyTexSubImage2D: xoffset and yoffset may not be negative");
 
-    WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
+    WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
     if (!tex)
         return ErrorInvalidOperation("copyTexSubImage2D: no texture bound to this target");
 
-    if (!tex->HasImageInfoAt(target, level))
+    if (!tex->HasImageInfoAt(texImageTarget, level))
         return ErrorInvalidOperation("copyTexSubImage2D: no texture image previously defined for this level and face");
 
-    const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level);
+    const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(texImageTarget, level);
     GLsizei texWidth = imageInfo.Width();
     GLsizei texHeight = imageInfo.Height();
 
     if (xoffset + width > texWidth || xoffset + width < 0)
       return ErrorInvalidValue("copyTexSubImage2D: xoffset+width is too large");
 
     if (yoffset + height > texHeight || yoffset + height < 0)
       return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
 
     if (!mBoundFramebuffer)
         ClearBackbufferIfNeeded();
 
     if (imageInfo.HasUninitializedImageData()) {
-        tex->DoDeferredImageInitialization(target, level);
+        tex->DoDeferredImageInitialization(texImageTarget, level);
     }
 
-    return CopyTexSubImage2D_base(target, level, imageInfo.WebGLFormat(), xoffset, yoffset, x, y, width, height, true);
+    return CopyTexSubImage2D_base(texImageTarget, level, imageInfo.WebGLFormat(), xoffset, yoffset, x, y, width, height, true);
 }
 
 
 already_AddRefed<WebGLProgram>
 WebGLContext::CreateProgram()
 {
     if (IsContextLost())
         return nullptr;
@@ -687,21 +697,21 @@ WebGLContext::DeleteTexture(WebGLTexture
     if (mBoundFramebuffer)
         mBoundFramebuffer->DetachTexture(tex);
 
     // Invalidate framebuffer status cache
     tex->NotifyFBsStatusChanged();
 
     GLuint activeTexture = mActiveTexture;
     for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
-        if ((tex->Target() == LOCAL_GL_TEXTURE_2D && mBound2DTextures[i] == tex) ||
-            (tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP && mBoundCubeMapTextures[i] == tex))
+        if ((mBound2DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_2D) ||
+            (mBoundCubeMapTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP))
         {
             ActiveTexture(LOCAL_GL_TEXTURE0 + i);
-            BindTexture(tex->Target(), static_cast<WebGLTexture*>(nullptr));
+            BindTexture(tex->Target().get(), static_cast<WebGLTexture*>(nullptr));
         }
     }
     ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture);
 
     tex->RequestDelete();
 }
 
 void
@@ -796,17 +806,24 @@ WebGLContext::FramebufferTexture2D(GLenu
                                    GLint level)
 {
     if (IsContextLost())
         return;
 
     if (!mBoundFramebuffer)
         return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
 
-    return mBoundFramebuffer->FramebufferTexture2D(target, attachment, textarget, tobj, level);
+    if (textarget != LOCAL_GL_TEXTURE_2D &&
+        (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
+         textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
+    {
+        return ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
+    }
+
+    return mBoundFramebuffer->FramebufferTexture2D(target, attachment, TexImageTarget(textarget), tobj, level);
 }
 
 void
 WebGLContext::FrontFace(GLenum mode)
 {
     if (IsContextLost())
         return;
 
@@ -852,31 +869,34 @@ WebGLContext::GetActiveAttrib(WebGLProgr
     prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
 
     nsRefPtr<WebGLActiveInfo> retActiveInfo =
         new WebGLActiveInfo(attrsize, attrtype, reverseMappedName);
     return retActiveInfo.forget();
 }
 
 void
-WebGLContext::GenerateMipmap(GLenum target)
+WebGLContext::GenerateMipmap(GLenum rawTarget)
 {
     if (IsContextLost())
         return;
 
-    if (!ValidateTextureTargetEnum(target, "generateMipmap"))
+    if (!ValidateTextureTargetEnum(rawTarget, "generateMipmap"))
         return;
 
+    const TexTarget target(rawTarget);
+
     WebGLTexture *tex = activeBoundTextureForTarget(target);
 
     if (!tex)
         return ErrorInvalidOperation("generateMipmap: No texture is bound to this target.");
 
-    GLenum imageTarget = (target == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_2D
-                                                         : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+    const TexImageTarget imageTarget = (target == LOCAL_GL_TEXTURE_2D)
+                                                  ? LOCAL_GL_TEXTURE_2D
+                                                  : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
     if (!tex->HasImageInfoAt(imageTarget, 0))
     {
         return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
     }
 
     if (!tex->IsFirstImagePowerOfTwo())
         return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
 
@@ -900,21 +920,21 @@ WebGLContext::GenerateMipmap(GLenum targ
     MakeContextCurrent();
 
     if (gl->WorkAroundDriverBugs()) {
         // bug 696495 - to work around failures in the texture-mips.html test on various drivers, we
         // set the minification filter before calling glGenerateMipmap. This should not carry a significant performance
         // overhead so we do it unconditionally.
         //
         // note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105.
-        gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST_MIPMAP_NEAREST);
-        gl->fGenerateMipmap(target);
-        gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, tex->MinFilter());
+        gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST_MIPMAP_NEAREST);
+        gl->fGenerateMipmap(target.get());
+        gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, tex->MinFilter());
     } else {
-        gl->fGenerateMipmap(target);
+        gl->fGenerateMipmap(target.get());
     }
 }
 
 already_AddRefed<WebGLActiveInfo>
 WebGLContext::GetActiveUniform(WebGLProgram *prog, uint32_t index)
 {
     if (IsContextLost())
         return nullptr;
@@ -1168,20 +1188,20 @@ WebGLContext::GetFramebufferAttachmentPa
 
             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
                 return JS::NumberValue(uint32_t(LOCAL_GL_TEXTURE));
 
             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
                 return WebGLObjectAsJSValue(cx, fba.Texture(), rv);
 
             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
-                return JS::Int32Value(fba.TexImageLevel());
+                return JS::Int32Value(fba.MipLevel());
 
             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: {
-                GLenum face = fba.TexImageTarget();
+                GLenum face = fba.ImageTarget().get();
                 if (face == LOCAL_GL_TEXTURE_2D)
                     face = 0;
                 return JS::Int32Value(face);
             }
 
             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: {
                 if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) &&
                     !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
@@ -1194,18 +1214,18 @@ WebGLContext::GetFramebufferAttachmentPa
                                           " type of depth-stencil attachments.");
                     return JS::NullValue();
                 }
 
                 if (!fba.IsComplete())
                     return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
 
                 uint32_t ret = LOCAL_GL_NONE;
-                GLenum type = fba.Texture()->ImageInfoAt(fba.TexImageTarget(),
-                                                         fba.TexImageLevel()).WebGLType();
+                GLenum type = fba.Texture()->ImageInfoAt(fba.ImageTarget(),
+                                                         fba.MipLevel()).WebGLType();
                 switch (type) {
                 case LOCAL_GL_UNSIGNED_BYTE:
                 case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
                 case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
                 case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
                     ret = LOCAL_GL_UNSIGNED_NORMALIZED;
                     break;
                 case LOCAL_GL_FLOAT:
@@ -1440,32 +1460,34 @@ WebGLContext::GetProgramInfoLog(WebGLPro
     retval.SetCapacity(k);
     gl->fGetProgramInfoLog(progname, k, &k, (char*) retval.BeginWriting());
     retval.SetLength(k);
 }
 
 // here we have to support all pnames with both int and float params.
 // See this discussion:
 //  https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
-void WebGLContext::TexParameter_base(GLenum target, GLenum pname,
+void WebGLContext::TexParameter_base(GLenum rawTarget, GLenum pname,
                                      GLint *intParamPtr,
                                      GLfloat *floatParamPtr)
 {
     MOZ_ASSERT(intParamPtr || floatParamPtr);
 
     if (IsContextLost())
         return;
 
     GLint intParam = intParamPtr ? *intParamPtr : GLint(*floatParamPtr);
     GLfloat floatParam = floatParamPtr ? *floatParamPtr : GLfloat(*intParamPtr);
 
-    if (!ValidateTextureTargetEnum(target, "texParameter: target"))
+    if (!ValidateTextureTargetEnum(rawTarget, "texParameter: target"))
         return;
 
-    WebGLTexture *tex = activeBoundTextureForTarget(target);
+    const TexTarget texTarget = TexTarget(rawTarget);
+
+    WebGLTexture *tex = activeBoundTextureForTarget(texTarget);
     if (!tex)
         return ErrorInvalidOperation("texParameter: no texture is bound to this target");
 
     bool pnameAndParamAreIncompatible = false;
     bool paramValueInvalid = false;
 
     switch (pname) {
         case LOCAL_GL_TEXTURE_MIN_FILTER:
@@ -1541,51 +1563,53 @@ void WebGLContext::TexParameter_base(GLe
                                     pname, intParam, intParam);
         else
             return ErrorInvalidValue("texParameterf: pname %x and param %g is invalid",
                                     pname, floatParam);
     }
 
     MakeContextCurrent();
     if (intParamPtr)
-        gl->fTexParameteri(target, pname, intParam);
+        gl->fTexParameteri(texTarget.get(), pname, intParam);
     else
-        gl->fTexParameterf(target, pname, floatParam);
+        gl->fTexParameterf(texTarget.get(), pname, floatParam);
 }
 
 JS::Value
-WebGLContext::GetTexParameter(GLenum target, GLenum pname)
+WebGLContext::GetTexParameter(GLenum rawTarget, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
     MakeContextCurrent();
 
-    if (!ValidateTextureTargetEnum(target, "getTexParameter: target"))
+    if (!ValidateTextureTargetEnum(rawTarget, "getTexParameter: target"))
         return JS::NullValue();
 
+    const TexTarget target(rawTarget);
+
     if (!activeBoundTextureForTarget(target)) {
         ErrorInvalidOperation("getTexParameter: no texture bound");
         return JS::NullValue();
     }
 
     switch (pname) {
         case LOCAL_GL_TEXTURE_MIN_FILTER:
         case LOCAL_GL_TEXTURE_MAG_FILTER:
         case LOCAL_GL_TEXTURE_WRAP_S:
         case LOCAL_GL_TEXTURE_WRAP_T:
         {
             GLint i = 0;
-            gl->fGetTexParameteriv(target, pname, &i);
+            gl->fGetTexParameteriv(target.get(), pname, &i);
             return JS::NumberValue(uint32_t(i));
         }
         case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
             if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
                 GLfloat f = 0.f;
-                gl->fGetTexParameterfv(target, pname, &f);
+                gl->fGetTexParameterfv(target.get(), pname, &f);
                 return JS::DoubleValue(f);
             }
 
             ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
             break;
 
         default:
             ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
@@ -3270,98 +3294,107 @@ WebGLContext::CompileShader(WebGLShader 
 
     gl->fCompileShader(shadername);
     GLint ok;
     gl->fGetShaderiv(shadername, LOCAL_GL_COMPILE_STATUS, &ok);
     shader->SetCompileStatus(ok);
 }
 
 void
-WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
+WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget, GLint level, GLenum internalformat,
                                    GLsizei width, GLsizei height, GLint border,
                                    const ArrayBufferView& view)
 {
     if (IsContextLost())
         return;
 
     const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexImage;
 
-    if (!ValidateTexImage(2, target, level, internalformat,
+    if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CompTexImage))
+        return;
+
+    if (!ValidateTexImage(2, rawTexImgTarget, level, internalformat,
                           0, 0, 0, width, height, 0,
                           border, internalformat, LOCAL_GL_UNSIGNED_BYTE,
                           func))
     {
         return;
     }
 
     view.ComputeLengthAndData();
 
     uint32_t byteLength = view.Length();
-    if (!ValidateCompTexImageDataSize(target, internalformat, width, height, byteLength, func)) {
+    if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func)) {
         return;
     }
 
-    if (!ValidateCompTexImageSize(target, level, internalformat, 0, 0,
-                                  width, height, width, height, func))
+    if (!ValidateCompTexImageSize(level, internalformat, 0, 0, width, height, width, height, func))
     {
         return;
     }
 
+    const TexImageTarget texImageTarget(rawTexImgTarget);
+
     MakeContextCurrent();
-    gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data());
-    WebGLTexture* tex = activeBoundTextureForTexImageTarget(target);
+    gl->fCompressedTexImage2D(texImageTarget.get(), level, internalformat, width, height, border, byteLength, view.Data());
+    WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
     MOZ_ASSERT(tex);
-    tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
+    tex->SetImageInfo(texImageTarget, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
                       WebGLImageDataStatus::InitializedImageData);
 }
 
 void
-WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset,
+WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint xoffset,
                                       GLint yoffset, GLsizei width, GLsizei height,
                                       GLenum format, const ArrayBufferView& view)
 {
     if (IsContextLost())
         return;
 
     const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexSubImage;
 
-    if (!ValidateTexImage(2, target,
+    if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CompTexSubImage))
+        return;
+
+    if (!ValidateTexImage(2, rawTexImgTarget,
                           level, format,
                           xoffset, yoffset, 0,
                           width, height, 0,
                           0, format, LOCAL_GL_UNSIGNED_BYTE,
                           func))
     {
         return;
     }
 
-    WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
+    const TexImageTarget texImageTarget(rawTexImgTarget);
+
+    WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
     MOZ_ASSERT(tex);
-    WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(target, level);
+    WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(texImageTarget, level);
 
     view.ComputeLengthAndData();
 
     uint32_t byteLength = view.Length();
-    if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func))
+    if (!ValidateCompTexImageDataSize(level, format, width, height, byteLength, func))
         return;
 
-    if (!ValidateCompTexImageSize(target, level, format,
+    if (!ValidateCompTexImageSize(level, format,
                                   xoffset, yoffset,
                                   width, height,
                                   levelInfo.Width(), levelInfo.Height(),
                                   func))
     {
         return;
     }
 
     if (levelInfo.HasUninitializedImageData())
-        tex->DoDeferredImageInitialization(target, level);
+        tex->DoDeferredImageInitialization(texImageTarget, level);
 
     MakeContextCurrent();
-    gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.Data());
+    gl->fCompressedTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, format, byteLength, view.Data());
 }
 
 JS::Value
 WebGLContext::GetShaderParameter(WebGLShader *shader, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
@@ -3538,72 +3571,72 @@ WebGLContext::GetShaderTranslatedSource(
     }
 
     if (!ValidateObject("getShaderTranslatedSource: shader", shader))
         return;
 
     retval.Assign(shader->TranslatedSource());
 }
 
-GLenum WebGLContext::CheckedTexImage2D(GLenum target,
+GLenum WebGLContext::CheckedTexImage2D(TexImageTarget texImageTarget,
                                        GLint level,
                                        GLenum internalFormat,
                                        GLsizei width,
                                        GLsizei height,
                                        GLint border,
                                        GLenum format,
                                        GLenum type,
                                        const GLvoid *data)
 {
     MOZ_ASSERT(internalFormat == format);
-    WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
+    WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
     MOZ_ASSERT(tex != nullptr, "no texture bound");
 
     bool sizeMayChange = true;
 
-    if (tex->HasImageInfoAt(target, level)) {
-        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
+    if (tex->HasImageInfoAt(texImageTarget, level)) {
+        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
         sizeMayChange = width != imageInfo.Width() ||
                         height != imageInfo.Height() ||
                         format != imageInfo.WebGLFormat() ||
                         type != imageInfo.WebGLType();
     }
 
     // Convert to format and type required by OpenGL 'driver'.
     GLenum driverType = DriverTypeFromType(gl, type);
     GLenum driverInternalFormat = LOCAL_GL_NONE;
     GLenum driverFormat = LOCAL_GL_NONE;
     DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat);
 
     if (sizeMayChange) {
         GetAndFlushUnderlyingGLErrors();
     }
 
-    gl->fTexImage2D(target, level, driverInternalFormat, width, height, border, driverFormat, driverType, data);
+    gl->fTexImage2D(texImageTarget.get(), level, driverInternalFormat, width, height, border, driverFormat, driverType, data);
 
     GLenum error = LOCAL_GL_NO_ERROR;
     if (sizeMayChange) {
         error = GetAndFlushUnderlyingGLErrors();
     }
 
     return error;
 }
 
 void
-WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
+WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level, GLenum internalformat,
                               GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
                               GLint border,
                               GLenum format, GLenum type,
                               void* data, uint32_t byteLength,
                               int jsArrayType, // a TypedArray format enum, or -1 if not relevant
                               WebGLTexelFormat srcFormat, bool srcPremultiplied)
 {
     const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
 
-    if (!ValidateTexImage(2, target, level, internalformat,
+    if (!ValidateTexImage(2, texImageTarget, level, internalformat,
                           0, 0, 0,
                           width, height, 0,
                           border, format, type, func))
     {
         return;
     }
 
     const bool isDepthTexture = format == LOCAL_GL_DEPTH_COMPONENT ||
@@ -3636,17 +3669,17 @@ WebGLContext::TexImage2D_base(GLenum tar
         return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size");
 
     uint32_t bytesNeeded = checked_neededByteLength.value();
 
     if (byteLength && byteLength < bytesNeeded)
         return ErrorInvalidOperation("texImage2D: not enough data for operation (need %d, have %d)",
                                  bytesNeeded, byteLength);
 
-    WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
+    WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
 
     if (!tex)
         return ErrorInvalidOperation("texImage2D: no texture is bound to this target");
 
     MakeContextCurrent();
 
     nsAutoArrayPtr<uint8_t> convertedData;
     void* pixels = nullptr;
@@ -3675,34 +3708,34 @@ WebGLContext::TexImage2D_base(GLenum tar
                         static_cast<uint8_t*>(data), convertedData,
                         actualSrcFormat, srcPremultiplied,
                         dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize);
             pixels = reinterpret_cast<void*>(convertedData.get());
         }
         imageInfoStatusIfSuccess = WebGLImageDataStatus::InitializedImageData;
     }
 
-    GLenum error = CheckedTexImage2D(target, level, internalformat, width,
+    GLenum error = CheckedTexImage2D(texImageTarget, level, internalformat, width,
                                      height, border, format, type, pixels);
 
     if (error) {
         GenerateWarning("texImage2D generated error %s", ErrorName(error));
         return;
     }
 
     // in all of the code paths above, we should have either initialized data,
     // or allocated data and left it uninitialized, but in any case we shouldn't
     // have NoImageData at this point.
     MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData);
 
-    tex->SetImageInfo(target, level, width, height, format, type, imageInfoStatusIfSuccess);
+    tex->SetImageInfo(texImageTarget, level, width, height, format, type, imageInfoStatusIfSuccess);
 }
 
 void
-WebGLContext::TexImage2D(GLenum target, GLint level,
+WebGLContext::TexImage2D(GLenum rawTarget, GLint level,
                          GLenum internalformat, GLsizei width,
                          GLsizei height, GLint border, GLenum format,
                          GLenum type, const Nullable<ArrayBufferView> &pixels, ErrorResult& rv)
 {
     if (IsContextLost())
         return;
 
     void* data;
@@ -3716,58 +3749,67 @@ WebGLContext::TexImage2D(GLenum target, 
         const ArrayBufferView& view = pixels.Value();
         view.ComputeLengthAndData();
 
         data = view.Data();
         length = view.Length();
         jsArrayType = int(JS_GetArrayBufferViewType(view.Obj()));
     }
 
-    return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
+    if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexImage))
+        return;
+
+    return TexImage2D_base(rawTarget, level, internalformat, width, height, 0, border, format, type,
                            data, length, jsArrayType,
                            WebGLTexelFormat::Auto, false);
 }
 
 void
-WebGLContext::TexImage2D(GLenum target, GLint level,
+WebGLContext::TexImage2D(GLenum rawTarget, GLint level,
                          GLenum internalformat, GLenum format,
                          GLenum type, ImageData* pixels, ErrorResult& rv)
 {
     if (IsContextLost())
         return;
 
     if (!pixels) {
         // Spec says to generate an INVALID_VALUE error
         return ErrorInvalidValue("texImage2D: null ImageData");
     }
 
     Uint8ClampedArray arr;
     DebugOnly<bool> inited = arr.Init(pixels->GetDataObject());
     MOZ_ASSERT(inited);
     arr.ComputeLengthAndData();
 
-    return TexImage2D_base(target, level, internalformat, pixels->Width(),
+    void* pixelData = arr.Data();
+    const uint32_t pixelDataLength = arr.Length();
+
+    if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexImage))
+        return;
+
+    return TexImage2D_base(rawTarget, level, internalformat, pixels->Width(),
                            pixels->Height(), 4*pixels->Width(), 0,
-                           format, type, arr.Data(), arr.Length(), -1,
+                           format, type, pixelData, pixelDataLength, -1,
                            WebGLTexelFormat::RGBA8, false);
 }
 
 
 void
-WebGLContext::TexSubImage2D_base(GLenum target, GLint level,
+WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
                                  GLint xoffset, GLint yoffset,
                                  GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
                                  GLenum format, GLenum type,
                                  void* data, uint32_t byteLength,
                                  int jsArrayType,
                                  WebGLTexelFormat srcFormat, bool srcPremultiplied)
 {
     const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
 
-    if (!ValidateTexImage(2, target, level, format,
+    if (!ValidateTexImage(2, texImageTarget, level, format,
                           xoffset, yoffset, 0,
                           width, height, 0,
                           0, format, type, func))
     {
         return;
     }
 
     if (!ValidateTexInputData(type, jsArrayType, func))
@@ -3792,21 +3834,21 @@ WebGLContext::TexSubImage2D_base(GLenum 
     if (!checked_neededByteLength.isValid())
         return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
 
     uint32_t bytesNeeded = checked_neededByteLength.value();
 
     if (byteLength < bytesNeeded)
         return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
 
-    WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
-    const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level);
+    WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
+    const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(texImageTarget, level);
 
     if (imageInfo.HasUninitializedImageData())
-        tex->DoDeferredImageInitialization(target, level);
+        tex->DoDeferredImageInitialization(texImageTarget, level);
 
     MakeContextCurrent();
 
     size_t   srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
     uint32_t dstTexelSize = GetBitsPerTexel(format, type) / 8;
     size_t   dstPlainRowSize = dstTexelSize * width;
     // There are checks above to ensure that this won't overflow.
     size_t   dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mPixelStoreUnpackAlignment).value();
@@ -3830,37 +3872,40 @@ WebGLContext::TexSubImage2D_base(GLenum 
         pixels = reinterpret_cast<void*>(convertedData.get());
     }
 
     GLenum driverType = DriverTypeFromType(gl, type);
     GLenum driverInternalFormat = LOCAL_GL_NONE;
     GLenum driverFormat = LOCAL_GL_NONE;
     DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat);
 
-    gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, driverFormat, driverType, pixels);
+    gl->fTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, driverFormat, driverType, pixels);
 }
 
 void
-WebGLContext::TexSubImage2D(GLenum target, GLint level,
+WebGLContext::TexSubImage2D(GLenum rawTarget, GLint level,
                             GLint xoffset, GLint yoffset,
                             GLsizei width, GLsizei height,
                             GLenum format, GLenum type,
                             const Nullable<ArrayBufferView> &pixels,
                             ErrorResult& rv)
 {
     if (IsContextLost())
         return;
 
     if (pixels.IsNull())
         return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
 
     const ArrayBufferView& view = pixels.Value();
     view.ComputeLengthAndData();
 
-    return TexSubImage2D_base(target, level, xoffset, yoffset,
+    if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexSubImage))
+        return;
+
+    return TexSubImage2D_base(rawTarget, level, xoffset, yoffset,
                               width, height, 0, format, type,
                               view.Data(), view.Length(),
                               JS_GetArrayBufferViewType(view.Obj()),
                               WebGLTexelFormat::Auto, false);
 }
 
 void
 WebGLContext::TexSubImage2D(GLenum target, GLint level,
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -51,30 +51,32 @@ FormatHasAlpha(GLenum webGLFormat)
     return webGLFormat == LOCAL_GL_RGBA ||
            webGLFormat == LOCAL_GL_LUMINANCE_ALPHA ||
            webGLFormat == LOCAL_GL_ALPHA ||
            webGLFormat == LOCAL_GL_RGBA4 ||
            webGLFormat == LOCAL_GL_RGB5_A1 ||
            webGLFormat == LOCAL_GL_SRGB_ALPHA;
 }
 
-GLenum
-TexImageTargetToTexTarget(GLenum texImageTarget)
+TexTarget
+TexImageTargetToTexTarget(TexImageTarget texImageTarget)
 {
-    switch (texImageTarget) {
+    switch (texImageTarget.get()) {
     case LOCAL_GL_TEXTURE_2D:
         return LOCAL_GL_TEXTURE_2D;
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
         return LOCAL_GL_TEXTURE_CUBE_MAP;
     default:
+        MOZ_ASSERT(false, "Bad texture conversion");
+        // Should be caught by the constructor for TexTarget
         return LOCAL_GL_NONE;
     }
 }
 
 GLComponents::GLComponents(GLenum format)
 {
     mComponents = 0;
 
--- a/dom/canvas/WebGLContextUtils.h
+++ b/dom/canvas/WebGLContextUtils.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGLCONTEXTUTILS_H_
 #define WEBGLCONTEXTUTILS_H_
 
 #include "WebGLContext.h"
+#include "WebGLStrongTypes.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/BindingUtils.h"
 
 namespace mozilla {
 
 bool IsGLDepthFormat(GLenum webGLFormat);
 bool IsGLDepthStencilFormat(GLenum webGLFormat);
 bool FormatHasAlpha(GLenum webGLFormat);
@@ -26,17 +27,17 @@ GLenum DriverTypeFromType(gl::GLContext*
 // For example, cube maps would pass GL_TEXTURE_CUBE_MAP_[POS|NEG]_[X|Y|Z]
 // instead of just GL_TEXTURE_CUBE_MAP.
 //
 // This function converts the texture image target to the texture target a.k.a.
 // binding location. The returned binding location can be used to check that
 // the currently bound texture is appropriate for this texImageTarget.
 //
 // Returns GL_NONE if passed an invalid texture image target
-GLenum TexImageTargetToTexTarget(GLenum texImageTarget);
+TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget);
 
 struct GLComponents
 {
     unsigned char mComponents;
 
     enum Components {
         Red     = (1 << 0),
         Green   = (1 << 1),
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -144,20 +144,20 @@ IsSubFunc(WebGLTexImageFunc func)
             func == WebGLTexImageFunc::CopyTexSubImage ||
             func == WebGLTexImageFunc::CompTexSubImage);
 }
 
 /**
  * returns true is target is a texture cube map target.
  */
 static bool
-IsTexImageCubemapTarget(GLenum target)
+IsTexImageCubemapTarget(GLenum texImageTarget)
 {
-    return (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
-            target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
+    return (texImageTarget >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
+            texImageTarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
 }
 
 /*
  * Pull data out of the program, post-linking
  */
 bool
 WebGLProgram::UpdateInfo()
 {
@@ -707,17 +707,17 @@ WebGLContext::ValidateTexImageType(GLenu
 }
 
 /**
  * Validate texture image sizing extra constraints for
  * CompressedTex(Sub)?Image.
  */
 // TODO: WebGL 2
 bool
-WebGLContext::ValidateCompTexImageSize(GLenum target, GLint level, GLenum format,
+WebGLContext::ValidateCompTexImageSize(GLint level, GLenum format,
                                        GLint xoffset, GLint yoffset,
                                        GLsizei width, GLsizei height,
                                        GLsizei levelWidth, GLsizei levelHeight,
                                        WebGLTexImageFunc func)
 {
     // Negative parameters must already have been handled above
     MOZ_ASSERT(xoffset >= 0 && yoffset >= 0 &&
                width >= 0 && height >= 0);
@@ -879,17 +879,17 @@ WebGLContext::ValidateCompTexImageDataSi
 
 /**
  * Validate the width, height, and depth of a texture image, \return
  * true is valid, false otherwise.
  * Used by all the (Compressed|Copy)?Tex(Sub)?Image functions.
  * Target and level must have been validated before calling.
  */
 bool
-WebGLContext::ValidateTexImageSize(GLenum target, GLint level,
+WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
                                    GLint width, GLint height, GLint depth,
                                    WebGLTexImageFunc func)
 {
     MOZ_ASSERT(level >= 0, "level should already be validated");
 
     /* Bug 966630: maxTextureSize >> level runs into "undefined"
      * behaviour depending on ISA. For example, on Intel shifts
      * amounts are mod 64 (in 64-bit mode on 64-bit dest) and mod 32
@@ -898,32 +898,32 @@ WebGLContext::ValidateTexImageSize(GLenu
      * clamping to a shift of 31 bits if level is greater than that
      * ammount. This will give 0 that if (!maxAllowedSize) is
      * expecting.
      */
 
     if (level > 31)
         level = 31;
 
-    const GLuint maxTexImageSize = MaxTextureSizeForTarget(target) >> level;
-    const bool isCubemapTarget = IsTexImageCubemapTarget(target);
+    const GLuint maxTexImageSize = MaxTextureSizeForTarget(TexImageTargetToTexTarget(texImageTarget)) >> level;
+    const bool isCubemapTarget = IsTexImageCubemapTarget(texImageTarget.get());
     const bool isSub = IsSubFunc(func);
 
     if (!isSub && isCubemapTarget && (width != height)) {
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "When the target parameter to TexImage2D is one of the
          *   six cube map two-dimensional image targets, the error
          *   INVALID_VALUE is generated if the width and height
          *   parameters are not equal."
          */
         ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func));
         return false;
     }
 
-    if (target == LOCAL_GL_TEXTURE_2D || isCubemapTarget)
+    if (texImageTarget == LOCAL_GL_TEXTURE_2D || isCubemapTarget)
     {
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "If wt and ht are the specified image width and height,
          *   and if either wt or ht are less than zero, then the error
          *   INVALID_VALUE is generated."
          */
         if (width < 0) {
             ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func));
@@ -973,17 +973,17 @@ WebGLContext::ValidateTexImageSize(GLenu
                 ErrorInvalidValue("%s: level >= 0, height of %d must be a power of two.",
                                   InfoFrom(func), height);
                 return false;
             }
         }
     }
 
     // TODO: WebGL 2
-    if (target == LOCAL_GL_TEXTURE_3D) {
+    if (texImageTarget == LOCAL_GL_TEXTURE_3D) {
         if (depth < 0) {
             ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func));
             return false;
         }
 
         if (!is_pot_assuming_nonnegative(depth)) {
             ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
                               InfoFrom(func), depth);
@@ -1303,29 +1303,25 @@ WebGLContext::ValidateCopyTexImage(GLenu
 }
 
 /**
  * Test the gl(Copy|Compressed)?Tex[Sub]?Image[23]() parameters for errors.
  * Verifies each of the parameters against the WebGL standard and enabled extensions.
  */
 // TODO: Texture dims is here for future expansion in WebGL 2.0
 bool
-WebGLContext::ValidateTexImage(GLuint dims, GLenum target,
+WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
                                GLint level, GLint internalFormat,
                                GLint xoffset, GLint yoffset, GLint zoffset,
                                GLint width, GLint height, GLint depth,
                                GLint border, GLenum format, GLenum type,
                                WebGLTexImageFunc func)
 {
     const char* info = InfoFrom(func);
 
-    /* Check target */
-    if (!ValidateTexImageTarget(dims, target, func))
-        return false;
-
     /* Check level */
     if (level < 0) {
         ErrorInvalidValue("%s: level must be >= 0", info);
         return false;
     }
 
     /* Check border */
     if (border != 0) {
@@ -1352,39 +1348,39 @@ WebGLContext::ValidateTexImage(GLuint di
     // TODO: Not sure if this is a bit of over kill.
     if (BaseTexFormat(internalFormat) == LOCAL_GL_NONE) {
         MOZ_ASSERT(false);
         ErrorInvalidValue("%s:", info);
         return false;
     }
 
     /* Check texture image size */
-    if (!ValidateTexImageSize(target, level, width, height, 0, func))
+    if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func))
         return false;
 
     /* 5.14.8 Texture objects - WebGL Spec.
      *   "If an attempt is made to call these functions with no
      *    WebGLTexture bound (see above), an INVALID_OPERATION error
      *    is generated."
      */
-    WebGLTexture* tex = activeBoundTextureForTexImageTarget(target);
+    WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
     if (!tex) {
         ErrorInvalidOperation("%s: no texture is bound to target %s",
-                              info, WebGLContext::EnumName(target));
+                              info, WebGLContext::EnumName(texImageTarget.get()));
         return false;
     }
 
     if (IsSubFunc(func)) {
-        if (!tex->HasImageInfoAt(target, level)) {
+        if (!tex->HasImageInfoAt(texImageTarget, level)) {
             ErrorInvalidOperation("%s: no texture image previously defined for target %s at level %d",
-                                  info, WebGLContext::EnumName(target), level);
+                                  info, WebGLContext::EnumName(texImageTarget.get()), level);
             return false;
         }
 
-        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
+        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
         if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
                                      width, height, depth,
                                      imageInfo.Width(), imageInfo.Height(), 0,
                                      func))
         {
             return false;
         }
 
@@ -1396,17 +1392,17 @@ WebGLContext::ValidateTexImage(GLuint di
         {
             ErrorInvalidOperation("%s: format or type doesn't match the existing texture",
                                   info);
             return false;
         }
     }
 
     /* Additional checks for depth textures */
-    if (target != LOCAL_GL_TEXTURE_2D &&
+    if (texImageTarget != LOCAL_GL_TEXTURE_2D &&
         (format == LOCAL_GL_DEPTH_COMPONENT ||
          format == LOCAL_GL_DEPTH_STENCIL))
     {
         ErrorInvalidOperation("%s: with format of %s target must be TEXTURE_2D",
                               info, WebGLContext::EnumName(format));
         return false;
     }
 
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -19,17 +19,17 @@ using namespace mozilla::gl;
 
 JSObject*
 WebGLFramebuffer::WrapObject(JSContext* cx)
 {
     return dom::WebGLFramebufferBinding::Wrap(cx, this);
 }
 
 WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context)
-    : WebGLBindableName()
+    : WebGLBindableName<GLenum>()
     , WebGLContextBoundObject(context)
     , mStatus(0)
     , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
     , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT)
     , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
 {
     SetIsDOMBinding();
     mContext->MakeContextCurrent();
@@ -37,16 +37,17 @@ WebGLFramebuffer::WebGLFramebuffer(WebGL
     mContext->mFramebuffers.insertBack(this);
 
     mColorAttachments.SetLength(1);
     mColorAttachments[0].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0;
 }
 
 WebGLFramebuffer::Attachment::Attachment(GLenum aAttachmentPoint)
     : mAttachmentPoint(aAttachmentPoint)
+    , mTexImageTarget(LOCAL_GL_NONE)
     , mNeedsFinalize(false)
 {}
 
 WebGLFramebuffer::Attachment::~Attachment()
 {}
 
 void
 WebGLFramebuffer::Attachment::Reset()
@@ -79,19 +80,19 @@ WebGLFramebuffer::Attachment::HasAlpha()
 GLenum
 WebGLFramebuffer::GetFormatForAttachment(const WebGLFramebuffer::Attachment& attachment) const
 {
     MOZ_ASSERT(attachment.IsDefined());
     MOZ_ASSERT(attachment.Texture() || attachment.Renderbuffer());
 
     if (attachment.Texture()) {
         const WebGLTexture& tex = *attachment.Texture();
-        MOZ_ASSERT(tex.HasImageInfoAt(tex.Target(), 0));
+        MOZ_ASSERT(tex.HasImageInfoAt(attachment.ImageTarget(), 0));
 
-        const WebGLTexture::ImageInfo& imgInfo = tex.ImageInfoAt(tex.Target(), 0);
+        const WebGLTexture::ImageInfo& imgInfo = tex.ImageInfoAt(attachment.ImageTarget(), 0);
         return imgInfo.WebGLFormat();
     }
 
     if (attachment.Renderbuffer())
         return attachment.Renderbuffer()->InternalFormat();
 
     return LOCAL_GL_NONE;
 }
@@ -125,17 +126,17 @@ WebGLFramebuffer::Attachment::IsReadable
 
     // If we arrive here Attachment isn't correct setup because it has
     // no texture nor render buffer pointer.
     MOZ_ASSERT(false, "Should not get here.");
     return false;
 }
 
 void
-WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level)
+WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level)
 {
     mTexturePtr = tex;
     mRenderbufferPtr = nullptr;
     mTexImageTarget = target;
     mTexImageLevel = level;
 
     mNeedsFinalize = true;
 }
@@ -390,24 +391,28 @@ WebGLFramebuffer::Attachment::FinalizeAt
 
         return;
     }
     MOZ_ASSERT(HasImage());
 
     if (Texture()) {
         MOZ_ASSERT(gl == Texture()->Context()->gl);
 
+        const GLenum imageTarget = ImageTarget().get();
+        const GLint mipLevel = MipLevel();
+        const GLuint glName = Texture()->GLName();
+
         if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
             gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
-                                      TexImageTarget(), Texture()->GLName(), TexImageLevel());
+                                      imageTarget, glName, mipLevel);
             gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
-                                      TexImageTarget(), Texture()->GLName(), TexImageLevel());
+                                      imageTarget, glName, mipLevel);
         } else {
             gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc,
-                                      TexImageTarget(), Texture()->GLName(), TexImageLevel());
+                                      imageTarget, glName, mipLevel);
         }
         return;
     }
 
     if (Renderbuffer()) {
         Renderbuffer()->FramebufferRenderbuffer(attachmentLoc);
         return;
     }
@@ -495,38 +500,31 @@ WebGLFramebuffer::FramebufferRenderbuffe
         wrb->AttachTo(this, attachment);
 
     a->SetRenderbuffer(wrb);
 }
 
 void
 WebGLFramebuffer::FramebufferTexture2D(GLenum target,
                                        GLenum attachment,
-                                       GLenum textarget,
+                                       TexImageTarget texImageTarget,
                                        WebGLTexture* wtex,
                                        GLint level)
 {
     MOZ_ASSERT(mContext->mBoundFramebuffer == this);
 
     if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", wtex))
         return;
 
     if (target != LOCAL_GL_FRAMEBUFFER)
         return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
 
-    if (textarget != LOCAL_GL_TEXTURE_2D &&
-        (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
-         textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
-    {
-        return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
-    }
-
     if (wtex) {
         bool isTexture2D = wtex->Target() == LOCAL_GL_TEXTURE_2D;
-        bool isTexTarget2D = textarget == LOCAL_GL_TEXTURE_2D;
+        bool isTexTarget2D = texImageTarget == LOCAL_GL_TEXTURE_2D;
         if (isTexture2D != isTexTarget2D) {
             return mContext->ErrorInvalidOperation("framebufferTexture2D: mismatched texture and texture target");
         }
     }
 
     if (level != 0)
         return mContext->ErrorInvalidValue("framebufferTexture2D: level must be 0");
 
@@ -550,17 +548,17 @@ WebGLFramebuffer::FramebufferTexture2D(G
         a->Texture()->DetachFrom(this, attachment);
     else if (a->Renderbuffer())
         a->Renderbuffer()->DetachFrom(this, attachment);
 
     // Attach new
     if (wtex)
         wtex->AttachTo(this, attachment);
 
-    a->SetTexImage(wtex, textarget, level);
+    a->SetTexImage(wtex, texImageTarget, level);
 }
 
 WebGLFramebuffer::Attachment*
 WebGLFramebuffer::GetAttachmentOrNull(GLenum attachment)
 {
     if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
         return &mDepthStencilAttachment;
 
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -3,84 +3,85 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGLFRAMEBUFFER_H_
 #define WEBGLFRAMEBUFFER_H_
 
 #include "WebGLBindableName.h"
 #include "WebGLObjectModel.h"
+#include "WebGLStrongTypes.h"
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/LinkedList.h"
 
 namespace mozilla {
 
 class WebGLFramebufferAttachable;
 class WebGLTexture;
 class WebGLRenderbuffer;
 namespace gl {
     class GLContext;
 }
 
 class WebGLFramebuffer MOZ_FINAL
     : public nsWrapperCache
-    , public WebGLBindableName
+    , public WebGLBindableName<GLenum>
     , public WebGLRefCountedObject<WebGLFramebuffer>
     , public LinkedListElement<WebGLFramebuffer>
     , public WebGLContextBoundObject
     , public SupportsWeakPtr<WebGLFramebuffer>
 {
 public:
     MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLFramebuffer)
 
     explicit WebGLFramebuffer(WebGLContext* context);
 
     struct Attachment
     {
         // deleting a texture or renderbuffer immediately detaches it
         WebGLRefPtr<WebGLTexture> mTexturePtr;
         WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
         GLenum mAttachmentPoint;
-        GLenum mTexImageTarget;
+        TexImageTarget mTexImageTarget;
         GLint mTexImageLevel;
         mutable bool mNeedsFinalize;
 
         explicit Attachment(GLenum aAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0);
         ~Attachment();
 
         bool IsDefined() const {
             return Texture() || Renderbuffer();
         }
 
         bool IsDeleteRequested() const;
 
         bool HasAlpha() const;
         bool IsReadableFloat() const;
 
-        void SetTexImage(WebGLTexture* tex, GLenum target, GLint level);
+        void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
         void SetRenderbuffer(WebGLRenderbuffer* rb);
 
         const WebGLTexture* Texture() const {
             return mTexturePtr;
         }
         WebGLTexture* Texture() {
             return mTexturePtr;
         }
         const WebGLRenderbuffer* Renderbuffer() const {
             return mRenderbufferPtr;
         }
         WebGLRenderbuffer* Renderbuffer() {
             return mRenderbufferPtr;
         }
-        GLenum TexImageTarget() const {
+        TexImageTarget ImageTarget() const {
             return mTexImageTarget;
         }
-        GLint TexImageLevel() const {
+        GLint MipLevel() const {
             return mTexImageLevel;
         }
 
         bool HasUninitializedImageData() const;
         void SetImageDataStatus(WebGLImageDataStatus x);
 
         void Reset();
 
@@ -96,17 +97,17 @@ public:
 
     void FramebufferRenderbuffer(GLenum target,
                                  GLenum attachment,
                                  GLenum rbtarget,
                                  WebGLRenderbuffer* wrb);
 
     void FramebufferTexture2D(GLenum target,
                               GLenum attachment,
-                              GLenum textarget,
+                              TexImageTarget texImageTarget,
                               WebGLTexture* wtex,
                               GLint level);
 
 private:
     void DetachAttachment(WebGLFramebuffer::Attachment& attachment);
     void DetachAllAttachments();
     const WebGLRectangleObject& GetAnyRectObject() const;
     Attachment* GetAttachmentOrNull(GLenum attachment);
--- a/dom/canvas/WebGLRenderbuffer.cpp
+++ b/dom/canvas/WebGLRenderbuffer.cpp
@@ -38,17 +38,17 @@ NeedsDepthStencilEmu(GLContext* gl, GLen
 }
 
 JSObject*
 WebGLRenderbuffer::WrapObject(JSContext *cx) {
     return dom::WebGLRenderbufferBinding::Wrap(cx, this);
 }
 
 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context)
-    : WebGLBindableName()
+    : WebGLBindableName<GLenum>()
     , WebGLContextBoundObject(context)
     , mPrimaryRB(0)
     , mSecondaryRB(0)
     , mInternalFormat(0)
     , mInternalFormatForGL(0)
     , mImageDataStatus(WebGLImageDataStatus::NoImageData)
 {
     SetIsDOMBinding();
--- a/dom/canvas/WebGLRenderbuffer.h
+++ b/dom/canvas/WebGLRenderbuffer.h
@@ -13,17 +13,17 @@
 #include "nsWrapperCache.h"
 
 #include "mozilla/LinkedList.h"
 
 namespace mozilla {
 
 class WebGLRenderbuffer MOZ_FINAL
     : public nsWrapperCache
-    , public WebGLBindableName
+    , public WebGLBindableName<GLenum>
     , public WebGLRefCountedObject<WebGLRenderbuffer>
     , public LinkedListElement<WebGLRenderbuffer>
     , public WebGLRectangleObject
     , public WebGLContextBoundObject
     , public WebGLFramebufferAttachable
 {
 public:
     explicit WebGLRenderbuffer(WebGLContext* context);
--- a/dom/canvas/WebGLSampler.cpp
+++ b/dom/canvas/WebGLSampler.cpp
@@ -8,18 +8,17 @@
 
 #include "GLContext.h"
 
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 
 using namespace mozilla;
 
 WebGLSampler::WebGLSampler(WebGLContext* context)
-    : WebGLBindableName()
-    , WebGLContextBoundObject(context)
+    : WebGLContextBoundObject(context)
 {
     SetIsDOMBinding();
     MOZ_CRASH("Not Implemented.");
 }
 
 WebGLSampler::~WebGLSampler()
 {}
 
--- a/dom/canvas/WebGLSampler.h
+++ b/dom/canvas/WebGLSampler.h
@@ -11,17 +11,17 @@
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/LinkedList.h"
 
 namespace mozilla {
 
 class WebGLSampler MOZ_FINAL
-    : public WebGLBindableName
+    : public WebGLBindableName<GLenum>
     , public nsWrapperCache
     , public WebGLRefCountedObject<WebGLSampler>
     , public LinkedListElement<WebGLSampler>
     , public WebGLContextBoundObject
 {
     friend class WebGLContext2;
 
 public:
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -0,0 +1,152 @@
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef WEBGLSTRONGTYPES_H_
+#define WEBGLSTRONGTYPES_H_
+
+#include "GLDefs.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/ArrayUtils.h"
+
+// Usage:
+// ===========
+//
+// To create a new type from a set of GLenums do the following:
+//
+//   STRONG_GLENUM_BEGIN(TypeName)
+//     Enum1,
+//     Enum2,
+//     ...
+//   STRONG_GLENUM_END()
+//
+// where TypeName is the name you want to give the type. Now simply use TypeName
+// instead of GLenum.
+//
+// ~~~~~~~~~~~~~~~~
+// Important Notes:
+// ~~~~~~~~~~~~~~~~
+//
+// Boolean operators (==, !=) are provided in an effort to prevent some mistakes
+// when using constants. For example we want to make sure that GL_ENUM_X is
+// a valid value for the type in code like:
+//
+//   if (myNewType == LOCAL_GL_SOME_ENUM)
+//       ...
+//
+// The operators will assert that LOCAL_GL_SOME_ENUM is a value that myNewType
+// can have.
+//
+// ----
+//
+// A get() method is provided to allow access to the underlying GLenum. This
+// method should ideally only be called when passing parameters to the gl->fXXXX
+// functions, and be used very minimally everywhere else.
+//
+// Definitely XXX - DO NOT DO - XXX:
+//
+//   if (myNewType.get() == LOCAL_GL_SOME_ENUM)
+//       ...
+//
+// As that undermines the debug checks that were implemented in the ==, and !=
+// operators. If you see code like this it should be treated with suspicion.
+//
+// Background:
+// ===========
+//
+// This macro is the first step in an effort to make the WebGL code safer.
+// Many of the different functions take GLenum as their parameter which leads
+// to bugs because of subtle differences in the enums purpose. For example there
+// are two types of 'texture targets'. One is the texture binding locations:
+//
+//   GL_TEXTURE_2D
+//   GL_TEXTURE_CUBE_MAP
+//
+// Yet, this is not the same as texture image targets:
+//
+//   GL_TEXTURE_2D
+//   GL_TEXTURE_CUBE_MAP_POSITIVE_X
+//   GL_TEXTURE_CUBE_MAP_NEGATIVE_X
+//   GL_TEXTURE_CUBE_MAP_POSITIVE_Y
+//   ...
+//
+// This subtle distinction has already led to many bugs in the texture code
+// because of invalid assumptions about what type goes where. The macro below
+// is an attempt at fixing this by providing a small wrapper around GLenum that
+// validates its values.
+//
+#ifdef DEBUG
+
+template<size_t N>
+static bool
+IsValueInArr(GLenum value, const GLenum (&arr)[N])
+{
+    for (size_t i = 0; i < N; ++i) {
+        if (value == arr[i])
+            return true;
+    }
+
+    return false;
+}
+
+#endif
+
+#define STRONG_GLENUM_BEGIN(NAME)                  \
+    class NAME {                                   \
+    private:                                       \
+        GLenum mValue;                             \
+    public:                                        \
+        MOZ_CONSTEXPR NAME(const NAME& other)      \
+            : mValue(other.mValue) { }             \
+                                                   \
+        bool operator==(const NAME& other) const { \
+            return mValue == other.mValue;         \
+        }                                          \
+                                                   \
+        bool operator!=(const NAME& other) const { \
+            return mValue != other.mValue;         \
+        }                                          \
+                                                   \
+        GLenum get() const {                       \
+            MOZ_ASSERT(mValue != LOCAL_GL_NONE);   \
+            return mValue;                         \
+        }                                          \
+                                                   \
+        NAME(GLenum val)                           \
+            : mValue(val)                          \
+        {                                          \
+            const GLenum validValues[] = {
+
+#define STRONG_GLENUM_END()                        \
+            };                                     \
+            (void)validValues;                     \
+            MOZ_ASSERT(IsValueInArr(mValue, validValues)); \
+        }                                          \
+    };
+
+/******************************************************************************
+ *  Add your types after this comment
+ *****************************************************************************/
+
+STRONG_GLENUM_BEGIN(TexImageTarget)
+    LOCAL_GL_NONE,
+    LOCAL_GL_TEXTURE_2D,
+    LOCAL_GL_TEXTURE_3D,
+    LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+    LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+    LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+    LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+    LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+    LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+STRONG_GLENUM_END()
+
+STRONG_GLENUM_BEGIN(TexTarget)
+    LOCAL_GL_NONE,
+    LOCAL_GL_TEXTURE_2D,
+    LOCAL_GL_TEXTURE_3D,
+    LOCAL_GL_TEXTURE_CUBE_MAP,
+STRONG_GLENUM_END()
+
+#endif
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -18,17 +18,17 @@
 using namespace mozilla;
 
 JSObject*
 WebGLTexture::WrapObject(JSContext *cx) {
     return dom::WebGLTextureBinding::Wrap(cx, this);
 }
 
 WebGLTexture::WebGLTexture(WebGLContext *context)
-    : WebGLBindableName()
+    : WebGLBindableName<TexTarget>()
     , WebGLContextBoundObject(context)
     , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
     , mMagFilter(LOCAL_GL_LINEAR)
     , mWrapS(LOCAL_GL_REPEAT)
     , mWrapT(LOCAL_GL_REPEAT)
     , mFacesCount(0)
     , mMaxLevelWithCustomImages(0)
     , mHaveGeneratedMipmap(false)
@@ -71,17 +71,17 @@ WebGLTexture::MemoryUsage() const {
             for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
                 result += ImageInfoAtFace(face, level).MemoryUsage();
         }
     }
     return result;
 }
 
 bool
-WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImageTarget) const {
+WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const {
     if (mHaveGeneratedMipmap)
         return true;
 
     // We want a copy here so we can modify it temporarily.
     ImageInfo expected = ImageInfoAt(texImageTarget, 0);
 
     // checks if custom level>0 images are all defined up to the highest level defined
     // and have the expected dimensions
@@ -98,51 +98,50 @@ WebGLTexture::DoesTexture2DMipmapHaveAll
             return true;
     }
 
     // if we're here, we've exhausted all levels without finding a 1x1 image
     return false;
 }
 
 void
-WebGLTexture::Bind(GLenum aTarget) {
+WebGLTexture::Bind(TexTarget aTexTarget) {
     // this function should only be called by bindTexture().
     // it assumes that the GL context is already current.
 
     bool firstTimeThisTextureIsBound = !HasEverBeenBound();
 
     if (firstTimeThisTextureIsBound) {
-        BindTo(aTarget);
-    } else if (aTarget != Target()) {
+        BindTo(aTexTarget);
+    } else if (aTexTarget != Target()) {
         mContext->ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
         // very important to return here before modifying texture state! This was the place when I lost a whole day figuring
         // very strange 'invalid write' crashes.
         return;
     }
 
     GLuint name = GLName();
-    GLenum target = Target();
 
-    mContext->gl->fBindTexture(target, name);
+    mContext->gl->fBindTexture(aTexTarget.get(), name);
 
     if (firstTimeThisTextureIsBound) {
-        mFacesCount = (mTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
+        mFacesCount = (aTexTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
         EnsureMaxLevelWithCustomImagesAtLeast(0);
         SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
 
         // thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
         // present in GLES 2, but is present in GL and it seems as if for cube maps
         // we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior.
         if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES())
-            mContext->gl->fTexParameteri(mTarget, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
+            mContext->gl->fTexParameteri(aTexTarget.get(), LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
     }
 }
 
 void
-WebGLTexture::SetImageInfo(GLenum aTexImageTarget, GLint aLevel,
+WebGLTexture::SetImageInfo(TexImageTarget aTexImageTarget, GLint aLevel,
                   GLsizei aWidth, GLsizei aHeight,
                   GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus)
 {
     MOZ_ASSERT(TexImageTargetToTexTarget(aTexImageTarget) == mTarget);
     if (TexImageTargetToTexTarget(aTexImageTarget) != mTarget)
         return;
 
     EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
@@ -222,31 +221,29 @@ WebGLTexture::IsCubeComplete() const {
     if (mTarget != LOCAL_GL_TEXTURE_CUBE_MAP)
         return false;
     const ImageInfo &first = ImageInfoAt(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
     if (!first.IsPositive() || !first.IsSquare())
         return false;
     return AreAllLevel0ImageInfosEqual();
 }
 
-static GLenum
+static TexImageTarget
 GLCubeMapFaceById(int id)
 {
-    GLenum result = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + id;
-    MOZ_ASSERT(result >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
-               result <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
-    return result;
+    // Correctness is checked by the constructor for TexImageTarget
+    return TexImageTarget(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + id);
 }
 
 bool
 WebGLTexture::IsMipmapCubeComplete() const {
     if (!IsCubeComplete()) // in particular, this checks that this is a cube map
         return false;
     for (int i = 0; i < 6; i++) {
-        GLenum face = GLCubeMapFaceById(i);
+        const TexImageTarget face = GLCubeMapFaceById(i);
         if (!DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(face))
             return false;
     }
     return true;
 }
 
 WebGLTextureFakeBlackStatus
 WebGLTexture::ResolvedFakeBlackStatus() {
@@ -274,31 +271,31 @@ WebGLTexture::ResolvedFakeBlackStatus() 
     {
         if (DoesMinFilterRequireMipmap())
         {
             if (!IsMipmapTexture2DComplete()) {
                 mContext->GenerateWarning
                     ("%s is a 2D texture, with a minification filter requiring a mipmap, "
                       "and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
-            } else if (!ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
+            } else if (!ImageInfoBase().IsPowerOfTwo()) {
                 mContext->GenerateWarning
                     ("%s is a 2D texture, with a minification filter requiring a mipmap, "
                       "and either its width or height is not a power of two.", msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             }
         }
         else // no mipmap required
         {
-            if (!ImageInfoAt(mTarget, 0).IsPositive()) {
+            if (!ImageInfoBase().IsPositive()) {
                 mContext->GenerateWarning
                     ("%s is a 2D texture and its width or height is equal to zero.",
                       msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
-            } else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
+            } else if (!AreBothWrapModesClampToEdge() && !ImageInfoBase().IsPowerOfTwo()) {
                 mContext->GenerateWarning
                     ("%s is a 2D texture, with a minification filter not requiring a mipmap, "
                       "with its width or height not a power of two, and with a wrap mode "
                       "different from CLAMP_TO_EDGE.", msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             }
         }
     }
@@ -406,19 +403,19 @@ WebGLTexture::ResolvedFakeBlackStatus() 
         if (hasAnyInitializedImageData) {
             // The texture contains some initialized image data, and some uninitialized image data.
             // In this case, we have no choice but to initialize all image data now. Fortunately,
             // in this case we know that we can't be dealing with a depth texture per WEBGL_depth_texture
             // and ANGLE_depth_texture (which allow only one image per texture) so we can assume that
             // glTexImage2D is able to upload data to images.
             for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
                 for (size_t face = 0; face < mFacesCount; ++face) {
-                    GLenum imageTarget = mTarget == LOCAL_GL_TEXTURE_2D
-                                         ? LOCAL_GL_TEXTURE_2D
-                                         : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
+                    TexImageTarget imageTarget = mTarget == LOCAL_GL_TEXTURE_2D
+                                                 ? LOCAL_GL_TEXTURE_2D
+                                                 : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
                     const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
                     if (imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData) {
                         DoDeferredImageInitialization(imageTarget, level);
                     }
                 }
             }
             mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
         } else {
@@ -456,17 +453,17 @@ ClearByMask(WebGLContext* context, GLbit
 
     context->ForceClearFramebufferWithDefaultValues(mask, colorAttachmentsMask);
     return true;
 }
 
 // `mask` from glClear.
 static bool
 ClearWithTempFB(WebGLContext* context, GLuint tex,
-                GLenum texImageTarget, GLint level,
+                TexImageTarget texImageTarget, GLint level,
                 GLenum baseInternalFormat,
                 GLsizei width, GLsizei height)
 {
     if (texImageTarget != LOCAL_GL_TEXTURE_2D)
         return false;
 
     gl::GLContext* gl = context->GL();
     MOZ_ASSERT(gl->IsCurrent());
@@ -480,32 +477,32 @@ ClearWithTempFB(WebGLContext* context, G
     case LOCAL_GL_LUMINANCE_ALPHA:
     case LOCAL_GL_ALPHA:
     case LOCAL_GL_RGB:
     case LOCAL_GL_RGBA:
     case LOCAL_GL_BGR:
     case LOCAL_GL_BGRA:
         mask = LOCAL_GL_COLOR_BUFFER_BIT;
         gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
-                                  texImageTarget, tex, level);
+                                  texImageTarget.get(), tex, level);
         break;
 
     case LOCAL_GL_DEPTH_COMPONENT:
         mask = LOCAL_GL_DEPTH_BUFFER_BIT;
         gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
-                                  texImageTarget, tex, level);
+                                  texImageTarget.get(), tex, level);
         break;
 
     case LOCAL_GL_DEPTH_STENCIL:
         mask = LOCAL_GL_DEPTH_BUFFER_BIT |
                LOCAL_GL_STENCIL_BUFFER_BIT;
         gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
-                                  texImageTarget, tex, level);
+                                  texImageTarget.get(), tex, level);
         gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
-                                  texImageTarget, tex, level);
+                                  texImageTarget.get(), tex, level);
         break;
 
     default:
         return false;
     }
     MOZ_ASSERT(mask);
 
     if (ClearByMask(context, mask))
@@ -532,17 +529,17 @@ ClearWithTempFB(WebGLContext* context, G
     mask |= LOCAL_GL_COLOR_BUFFER_BIT;
 
     // Last chance!
     return ClearByMask(context, mask);
 }
 
 
 void
-WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level)
+WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint level)
 {
     const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
     MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
 
     mContext->MakeContextCurrent();
 
     // Try to clear with glCLear.
     GLenum format = imageInfo.mWebGLFormat;
@@ -553,17 +550,17 @@ WebGLTexture::DoDeferredImageInitializat
                                    imageTarget, level,
                                    format, imageInfo.mHeight, imageInfo.mWidth);
     if (cleared) {
         SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
         return;
     }
 
     // That didn't work. Try uploading zeros then.
-    gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget);
+    gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget.get());
 
     uint32_t texelsize = WebGLTexelConversions::TexelBytesForFormat(texelformat);
     CheckedUint32 checked_byteLength
         = WebGLContext::GetImageSize(
                         imageInfo.mHeight,
                         imageInfo.mWidth,
                         texelsize,
                         mContext->mPixelStoreUnpackAlignment);
@@ -573,17 +570,17 @@ WebGLTexture::DoDeferredImageInitializat
 
     gl::GLContext* gl = mContext->gl;
     GLenum driverType = DriverTypeFromType(gl, type);
     GLenum driverInternalFormat = LOCAL_GL_NONE;
     GLenum driverFormat = LOCAL_GL_NONE;
     DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat);
 
     mContext->GetAndFlushUnderlyingGLErrors();
-    gl->fTexImage2D(imageTarget, level, driverInternalFormat,
+    gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat,
                     imageInfo.mWidth, imageInfo.mHeight,
                     0, driverFormat, driverType,
                     zeros);
     GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
     if (error) {
         // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here.
         printf_stderr("Error: 0x%4x\n", error);
         MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past.
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGLTEXTURE_H_
 #define WEBGLTEXTURE_H_
 
 #include "WebGLBindableName.h"
 #include "WebGLFramebufferAttachable.h"
 #include "WebGLObjectModel.h"
+#include "WebGLStrongTypes.h"
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/LinkedList.h"
 #include <algorithm>
 
 namespace mozilla {
@@ -23,17 +24,17 @@ inline bool is_pot_assuming_nonnegative(
 {
     return x && (x & (x-1)) == 0;
 }
 
 // NOTE: When this class is switched to new DOM bindings, update the (then-slow)
 // WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
 class WebGLTexture MOZ_FINAL
     : public nsWrapperCache
-    , public WebGLBindableName
+    , public WebGLBindableName<TexTarget>
     , public WebGLRefCountedObject<WebGLTexture>
     , public LinkedListElement<WebGLTexture>
     , public WebGLContextBoundObject
     , public WebGLFramebufferAttachable
 {
 public:
     explicit WebGLTexture(WebGLContext* aContext);
 
@@ -124,53 +125,47 @@ public:
         GLenum mWebGLFormat; //!< This is the WebGL/GLES format
         GLenum mWebGLType;   //!< This is the WebGL/GLES type
         WebGLImageDataStatus mImageDataStatus;
 
         friend class WebGLTexture;
     };
 
 private:
-    static size_t FaceForTarget(GLenum target) {
-        // Call this out explicitly:
-        MOZ_ASSERT(target != LOCAL_GL_TEXTURE_CUBE_MAP);
-        MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D ||
-                   (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
-                    target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z));
-        return target == LOCAL_GL_TEXTURE_2D ? 0 : target - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+    static size_t FaceForTarget(TexImageTarget texImageTarget) {
+        if (texImageTarget == LOCAL_GL_TEXTURE_2D)
+            return 0;
+
+        return texImageTarget.get() - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
     }
 
     ImageInfo& ImageInfoAtFace(size_t face, GLint level) {
         MOZ_ASSERT(face < mFacesCount, "wrong face index, must be 0 for TEXTURE_2D and at most 5 for cube maps");
 
         // no need to check level as a wrong value would be caught by ElementAt().
         return mImageInfos.ElementAt(level * mFacesCount + face);
     }
 
     const ImageInfo& ImageInfoAtFace(size_t face, GLint level) const {
         return const_cast<const ImageInfo&>(
             const_cast<WebGLTexture*>(this)->ImageInfoAtFace(face, level)
         );
     }
 
 public:
-    ImageInfo& ImageInfoAt(GLenum imageTarget, GLint level) {
-        MOZ_ASSERT(imageTarget);
-
+    ImageInfo& ImageInfoAt(TexImageTarget imageTarget, GLint level) {
         size_t face = FaceForTarget(imageTarget);
         return ImageInfoAtFace(face, level);
     }
 
-    const ImageInfo& ImageInfoAt(GLenum imageTarget, GLint level) const {
+    const ImageInfo& ImageInfoAt(TexImageTarget imageTarget, GLint level) const {
         return const_cast<WebGLTexture*>(this)->ImageInfoAt(imageTarget, level);
     }
 
-    bool HasImageInfoAt(GLenum imageTarget, GLint level) const {
-        MOZ_ASSERT(imageTarget);
-
+    bool HasImageInfoAt(TexImageTarget imageTarget, GLint level) const {
         size_t face = FaceForTarget(imageTarget);
         CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face;
         return checked_index.isValid() &&
                checked_index.value() < mImageInfos.Length() &&
                ImageInfoAt(imageTarget, level).mImageDataStatus != WebGLImageDataStatus::NoImageData;
     }
 
     ImageInfo& ImageInfoBase() {
@@ -178,29 +173,29 @@ public:
     }
 
     const ImageInfo& ImageInfoBase() const {
         return ImageInfoAtFace(0, 0);
     }
 
     int64_t MemoryUsage() const;
 
-    void SetImageDataStatus(GLenum imageTarget, GLint level, WebGLImageDataStatus newStatus) {
+    void SetImageDataStatus(TexImageTarget imageTarget, GLint level, WebGLImageDataStatus newStatus) {
         MOZ_ASSERT(HasImageInfoAt(imageTarget, level));
         ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
         // there is no way to go from having image data to not having any
         MOZ_ASSERT(newStatus != WebGLImageDataStatus::NoImageData ||
                    imageInfo.mImageDataStatus == WebGLImageDataStatus::NoImageData);
         if (imageInfo.mImageDataStatus != newStatus) {
             SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
         }
         imageInfo.mImageDataStatus = newStatus;
     }
 
-    void DoDeferredImageInitialization(GLenum imageTarget, GLint level);
+    void DoDeferredImageInitialization(TexImageTarget imageTarget, GLint level);
 
 protected:
 
     GLenum mMinFilter, mMagFilter, mWrapS, mWrapT;
 
     size_t mFacesCount, mMaxLevelWithCustomImages;
     nsTArray<ImageInfo> mImageInfos;
 
@@ -217,23 +212,23 @@ protected:
         return (mMagFilter == LOCAL_GL_NEAREST) &&
             (mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
     }
 
     bool AreBothWrapModesClampToEdge() const {
         return mWrapS == LOCAL_GL_CLAMP_TO_EDGE && mWrapT == LOCAL_GL_CLAMP_TO_EDGE;
     }
 
-    bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImageTarget) const;
+    bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const;
 
 public:
 
-    void Bind(GLenum aTarget);
+    void Bind(TexTarget aTexTarget);
 
-    void SetImageInfo(GLenum aTarget, GLint aLevel,
+    void SetImageInfo(TexImageTarget aTarget, GLint aLevel,
                       GLsizei aWidth, GLsizei aHeight,
                       GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus);
 
     void SetMinFilter(GLenum aMinFilter) {
         mMinFilter = aMinFilter;
         SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
     }
     void SetMagFilter(GLenum aMagFilter) {
--- a/dom/canvas/WebGLTransformFeedback.cpp
+++ b/dom/canvas/WebGLTransformFeedback.cpp
@@ -8,18 +8,17 @@
 
 #include "GLContext.h"
 
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 
 using namespace mozilla;
 
 WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* context)
-    : WebGLBindableName()
-    , WebGLContextBoundObject(context)
+    : WebGLContextBoundObject(context)
 {
     SetIsDOMBinding();
     MOZ_CRASH("Not Implemented.");
 }
 
 WebGLTransformFeedback::~WebGLTransformFeedback()
 {}
 
--- a/dom/canvas/WebGLTransformFeedback.h
+++ b/dom/canvas/WebGLTransformFeedback.h
@@ -11,17 +11,17 @@
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/LinkedList.h"
 
 namespace mozilla {
 
 class WebGLTransformFeedback MOZ_FINAL
-    : public WebGLBindableName
+    : public WebGLBindableName<GLenum>
     , public nsWrapperCache
     , public WebGLRefCountedObject<WebGLTransformFeedback>
     , public LinkedListElement<WebGLTransformFeedback>
     , public WebGLContextBoundObject
 {
     friend class WebGLContext;
 
 public:
--- a/dom/canvas/WebGLVertexArray.cpp
+++ b/dom/canvas/WebGLVertexArray.cpp
@@ -15,17 +15,17 @@
 using namespace mozilla;
 
 JSObject*
 WebGLVertexArray::WrapObject(JSContext *cx) {
     return dom::WebGLVertexArrayBinding::Wrap(cx, this);
 }
 
 WebGLVertexArray::WebGLVertexArray(WebGLContext* context)
-    : WebGLBindableName()
+    : WebGLBindableName<GLenum>()
     , WebGLContextBoundObject(context)
 {
     SetIsDOMBinding();
     context->mVertexArrays.insertBack(this);
 }
 
 WebGLVertexArray*
 WebGLVertexArray::Create(WebGLContext* context)
--- a/dom/canvas/WebGLVertexArray.h
+++ b/dom/canvas/WebGLVertexArray.h
@@ -16,17 +16,17 @@
 #include "mozilla/LinkedList.h"
 
 namespace mozilla {
 
 class WebGLVertexArrayFake;
 
 class WebGLVertexArray
     : public nsWrapperCache
-    , public WebGLBindableName
+    , public WebGLBindableName<GLenum>
     , public WebGLRefCountedObject<WebGLVertexArray>
     , public LinkedListElement<WebGLVertexArray>
     , public WebGLContextBoundObject
 {
 // -----------------------------------------------------------------------------
 // PUBLIC
 public:
     static WebGLVertexArray* Create(WebGLContext* context);
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -48,17 +48,16 @@ UNIFIED_SOURCES += [
     'WebGL2ContextQueries.cpp',
     'WebGL2ContextSamplers.cpp',
     'WebGL2ContextSync.cpp',
     'WebGL2ContextTextures.cpp',
     'WebGL2ContextTransformFeedback.cpp',
     'WebGL2ContextUniforms.cpp',
     'WebGL2ContextVAOs.cpp',
     'WebGLActiveInfo.cpp',
-    'WebGLBindableName.cpp',
     'WebGLBuffer.cpp',
     'WebGLContext.cpp',
     'WebGLContextAsyncQueries.cpp',
     'WebGLContextBuffers.cpp',
     'WebGLContextDraw.cpp',
     'WebGLContextExtensions.cpp',
     'WebGLContextFramebufferOperations.cpp',
     'WebGLContextGL.cpp',