Bug 728017 - Implement WEBGL_compressed_texture_s3tc - r=bjacob
authorJon Buckley <jon@jbuckley.ca>
Tue, 08 May 2012 13:29:31 -0400
changeset 93513 91a83411164efebb9ae2d7ad95d31f908e144e9b
parent 93512 f2f8b1127a54a88ea8c96192f17dce12f8642283
child 93514 3f5473a24f939874ad8cf728cd9846a8cb9c1695
push id22639
push userryanvm@gmail.com
push dateWed, 09 May 2012 01:32:57 +0000
treeherdermozilla-central@bbaa66c0efec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob
bugs728017
milestone15.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 728017 - Implement WEBGL_compressed_texture_s3tc - r=bjacob
content/canvas/src/Makefile.in
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextNotSupported.cpp
content/canvas/src/WebGLContextValidate.cpp
content/canvas/src/WebGLExtensionCompressedTextureS3TC.cpp
content/canvas/src/WebGLExtensionLoseContext.cpp
content/canvas/src/WebGLExtensionStandardDerivatives.cpp
content/canvas/src/WebGLExtensionTextureFilterAnisotropic.cpp
content/canvas/src/WebGLExtensions.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextSymbols.h
js/xpconnect/src/dom_quickstubs.qsconf
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -64,16 +64,17 @@ EXPORTS_mozilla/dom = \
 CPPSRCS	= \
 	CanvasImageCache.cpp \
 	CanvasUtils.cpp \
 	nsCanvasRenderingContext2D.cpp \
 	nsCanvasRenderingContext2DAzure.cpp \
 	DocumentRendererParent.cpp \
 	DocumentRendererChild.cpp \
 	ImageData.cpp \
+	WebGLExtensionCompressedTextureS3TC.cpp \
 	$(NULL)
 
 ifdef MOZ_WEBGL
 
 CPPSRCS += \
 	WebGLContext.cpp \
 	WebGLContextGL.cpp \
 	WebGLContextUtils.cpp \
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -878,20 +878,23 @@ bool WebGLContext::IsExtensionSupported(
 	    break;
         case WebGL_OES_standard_derivatives:
             // We always support this extension.
             isSupported = true;
             break;
         case WebGL_EXT_texture_filter_anisotropic:
             isSupported = gl->IsExtensionSupported(GLContext::EXT_texture_filter_anisotropic);
             break;
-        case WebGL_MOZ_WEBGL_lose_context:
+        case WebGL_WEBGL_lose_context:
             // We always support this extension.
             isSupported = true;
             break;
+        case WebGL_WEBGL_compressed_texture_s3tc:
+            isSupported = gl->IsExtensionSupported(GLContext::EXT_texture_compression_s3tc);
+            break;
         default:
             isSupported = false;
     }
 
     return isSupported;
 }
 
 NS_IMETHODIMP
@@ -922,32 +925,39 @@ WebGLContext::GetExtension(const nsAStri
         if (IsExtensionSupported(WebGL_OES_standard_derivatives))
             ei = WebGL_OES_standard_derivatives;
     }
     else if (aName.EqualsLiteral("MOZ_EXT_texture_filter_anisotropic")) {
         if (IsExtensionSupported(WebGL_EXT_texture_filter_anisotropic))
             ei = WebGL_EXT_texture_filter_anisotropic;
     }
     else if (aName.EqualsLiteral("MOZ_WEBGL_lose_context")) {
-        if (IsExtensionSupported(WebGL_MOZ_WEBGL_lose_context))
-            ei = WebGL_MOZ_WEBGL_lose_context;
+        if (IsExtensionSupported(WebGL_WEBGL_lose_context))
+            ei = WebGL_WEBGL_lose_context;
+    }
+    else if (aName.EqualsLiteral("MOZ_WEBGL_compressed_texture_s3tc")) {
+        if (IsExtensionSupported(WebGL_WEBGL_compressed_texture_s3tc))
+            ei = WebGL_WEBGL_compressed_texture_s3tc;
     }
 
     if (ei != WebGLExtensionID_Max) {
         if (!IsExtensionEnabled(ei)) {
             switch (ei) {
                 case WebGL_OES_standard_derivatives:
                     mEnabledExtensions[ei] = new WebGLExtensionStandardDerivatives(this);
                     break;
                 case WebGL_EXT_texture_filter_anisotropic:
                     mEnabledExtensions[ei] = new WebGLExtensionTextureFilterAnisotropic(this);
                     break;
-                case WebGL_MOZ_WEBGL_lose_context:
+                case WebGL_WEBGL_lose_context:
                     mEnabledExtensions[ei] = new WebGLExtensionLoseContext(this);
                     break;
+                case WebGL_WEBGL_compressed_texture_s3tc:
+                    mEnabledExtensions[ei] = new WebGLExtensionCompressedTextureS3TC(this);
+                    break;
                 // create an extension for any types that don't
                 // have any additional tokens or methods
                 default:
                     mEnabledExtensions[ei] = new WebGLExtension(this);
                     break;
             }
         }
         return mEnabledExtensions[ei];
@@ -1513,18 +1523,20 @@ WebGLContext::GetSupportedExtensions(Nul
     nsTArray<nsString>& arr = retval.SetValue();
     
     if (IsExtensionSupported(WebGL_OES_texture_float))
         arr.AppendElement(NS_LITERAL_STRING("OES_texture_float"));
     if (IsExtensionSupported(WebGL_OES_standard_derivatives))
         arr.AppendElement(NS_LITERAL_STRING("OES_standard_derivatives"));
     if (IsExtensionSupported(WebGL_EXT_texture_filter_anisotropic))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_EXT_texture_filter_anisotropic"));
-    if (IsExtensionSupported(WebGL_MOZ_WEBGL_lose_context))
+    if (IsExtensionSupported(WebGL_WEBGL_lose_context))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"));
+    if (IsExtensionSupported(WebGL_WEBGL_compressed_texture_s3tc))
+        arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"));
 }
 
 NS_IMETHODIMP
 WebGLContext::IsContextLost(WebGLboolean *retval)
 {
     *retval = mContextStatus != ContextStable;
     return NS_OK;
 }
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -566,16 +566,17 @@ class WebGLContext :
     public nsICanvasRenderingContextInternal,
     public nsSupportsWeakReference,
     public nsITimerCallback,
     public WebGLRectangleObject,
     public nsWrapperCache
 {
     friend class WebGLMemoryMultiReporterWrapper;
     friend class WebGLExtensionLoseContext;
+    friend class WebGLExtensionCompressedTextureS3TC;
     friend class WebGLContextUserData;
     friend class WebGLMemoryPressureObserver;
 
 public:
     WebGLContext();
     virtual ~WebGLContext();
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -1190,26 +1191,29 @@ protected:
         ContextLostAwaitingRestore
     };
 
     // extensions
     enum WebGLExtensionID {
         WebGL_OES_texture_float,
         WebGL_OES_standard_derivatives,
         WebGL_EXT_texture_filter_anisotropic,
-        WebGL_MOZ_WEBGL_lose_context,
+        WebGL_WEBGL_lose_context,
+        WebGL_WEBGL_compressed_texture_s3tc,
         WebGLExtensionID_Max
     };
     nsAutoTArray<nsRefPtr<WebGLExtension>, WebGLExtensionID_Max> mEnabledExtensions;
     bool IsExtensionEnabled(WebGLExtensionID ext) const {
         NS_ABORT_IF_FALSE(ext >= 0 && ext < WebGLExtensionID_Max, "bogus index!");
         return mEnabledExtensions[ext] != nsnull;
     }
     bool IsExtensionSupported(WebGLExtensionID ei);
 
+    nsTArray<WebGLenum> mCompressedTextureFormats;
+
     bool InitAndValidateGL();
     bool ValidateBuffers(PRInt32* maxAllowedCount, const char *info);
     bool ValidateCapabilityEnum(WebGLenum cap, const char *info);
     bool ValidateBlendEquationEnum(WebGLenum cap, const char *info);
     bool ValidateBlendFuncDstEnum(WebGLenum mode, const char *info);
     bool ValidateBlendFuncSrcEnum(WebGLenum mode, const char *info);
     bool ValidateBlendFuncEnumsCompatibility(WebGLenum sfactor, WebGLenum dfactor, const char *info);
     bool ValidateTextureTargetEnum(WebGLenum target, const char *info);
@@ -1222,17 +1226,21 @@ protected:
     bool ValidateDrawModeEnum(WebGLenum mode, const char *info);
     bool ValidateAttribIndex(WebGLuint index, const char *info);
     bool ValidateStencilParamsForDrawCall();
     
     bool ValidateGLSLVariableName(const nsAString& name, const char *info);
     bool ValidateGLSLCharacter(PRUnichar c);
     bool ValidateGLSLString(const nsAString& string, const char *info);
 
-    static PRUint32 GetTexelSize(WebGLenum format, WebGLenum type);
+    bool ValidateTexImage2DTarget(WebGLenum target, WebGLsizei width, WebGLsizei height, const char* info);
+    bool ValidateCompressedTextureSize(WebGLint level, WebGLenum format, WebGLsizei width, WebGLsizei height, uint32_t byteLength, const char* info);
+    bool ValidateLevelWidthHeightForTarget(WebGLenum target, WebGLint level, WebGLsizei width, WebGLsizei height, const char* info);
+
+    static PRUint32 GetBitsPerTexel(WebGLenum format, WebGLenum type);
 
     void Invalidate();
     void DestroyResourcesAndContext();
 
     void MakeContextCurrent() { gl->MakeCurrent(); }
 
     // helpers
     void TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum internalformat,
@@ -1708,18 +1716,18 @@ public:
         }
         bool IsPowerOfTwo() const {
             return is_pot_assuming_nonnegative(mWidth) &&
                    is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...)
         }
         PRInt64 MemoryUsage() const {
             if (!mIsDefined)
                 return 0;
-            PRInt64 texelSize = WebGLContext::GetTexelSize(mFormat, mType);
-            return PRInt64(mWidth) * PRInt64(mHeight) * texelSize;
+            PRInt64 texelSizeInBits = WebGLContext::GetBitsPerTexel(mFormat, mType);
+            return PRInt64(mWidth) * PRInt64(mHeight) * texelSizeInBits / 8;
         }
         WebGLenum Format() const { return mFormat; }
         WebGLenum Type() const { return mType; }
     protected:
         WebGLenum mFormat, mType;
         bool mIsDefined;
 
         friend class WebGLTexture;
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -41,17 +41,16 @@
 #include "WebGLContext.h"
 
 #include "nsString.h"
 #include "nsDebug.h"
 
 #include "gfxImageSurface.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
-//#include "nsIDOMHTMLCanvasElement.h"
 
 #include "nsContentUtils.h"
 #include "nsDOMError.h"
 #include "nsLayoutUtils.h"
 
 #include "CanvasUtils.h"
 
 #include "jsfriendapi.h"
@@ -2478,17 +2477,18 @@ WebGLContext::GetParameter(JSContext* cx
 
         case LOCAL_GL_MAX_VARYING_VECTORS:
             return JS::Int32Value(mGLMaxVaryingVectors);
 
         case LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
             return JS::Int32Value(0);
         case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS:
         {
-            JSObject* obj = Uint32Array::Create(cx, 0);
+            PRUint32 length = mCompressedTextureFormats.Length();
+            JSObject* obj = Uint32Array::Create(cx, length, mCompressedTextureFormats.Elements());
             if (!obj) {
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
             return JS::ObjectOrNullValue(obj);
         }
 
 // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as
 // javascript integer values. We just return them as doubles and javascript doesn't care.
@@ -5077,21 +5077,47 @@ void
 WebGLContext::CompressedTexImage2D(WebGLenum target, WebGLint level, WebGLenum internalformat,
                                    WebGLsizei width, WebGLsizei height, WebGLint border,
                                    ArrayBufferView& view)
 {
     if (!IsContextStable()) {
         return;
     }
 
+    if (!ValidateTexImage2DTarget(target, width, height, "compressedTexImage2D")) {
+        return;
+    }
+
     WebGLTexture *tex = activeBoundTextureForTarget(target);
-    if (!tex)
-        return ErrorInvalidOperation("compressedTexImage2D: no texture is bound to this target");
-
-    return ErrorInvalidEnum("compressedTexImage2D: compressed textures are not supported");
+    if (!tex) {
+        ErrorInvalidOperation("compressedTexImage2D: no texture is bound to this target");
+        return;
+    }
+
+    if (!mCompressedTextureFormats.Contains(internalformat)) {
+        ErrorInvalidEnum("compressedTexImage2D: compressed texture format 0x%x is not supported", internalformat);
+        return;
+    }
+
+    if (!ValidateLevelWidthHeightForTarget(target, level, width, height, "compressedTexImage2D")) {
+        return;
+    }
+
+    if (border) {
+        ErrorInvalidValue("compressedTexImage2D: border is not 0");
+        return;
+    }
+
+    uint32_t byteLength = view.mLength;
+    if (!ValidateCompressedTextureSize(level, internalformat, width, height, byteLength, "compressedTexImage2D")) {
+        return;
+    }
+
+    gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.mData);
+    tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE);
 }
 
 NS_IMETHODIMP
 WebGLContext::CompressedTexSubImage2D(WebGLenum target, WebGLint level, WebGLint xoffset,
                                       WebGLint yoffset, WebGLsizei width, WebGLsizei height,
                                       WebGLenum format, const JS::Value& pixels, JSContext *cx)
 {
     if (!pixels.isObject() || !JS_IsTypedArrayObject(&pixels.toObject(), cx)) {
@@ -5108,22 +5134,92 @@ void
 WebGLContext::CompressedTexSubImage2D(WebGLenum target, WebGLint level, WebGLint xoffset,
                                       WebGLint yoffset, WebGLsizei width, WebGLsizei height,
                                       WebGLenum format, ArrayBufferView& view)
 {
     if (!IsContextStable()) {
         return;
     }
 
+    switch (target) {
+        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("texSubImage2D: target", target);
+    }
+
     WebGLTexture *tex = activeBoundTextureForTarget(target);
     if (!tex) {
-        return ErrorInvalidOperation("compressedTexSubImage2D: no texture is bound to this target");
-    }
-
-    return ErrorInvalidEnum("compressedTexSubImage2D: compressed textures are not supported");
+        ErrorInvalidOperation("compressedTexSubImage2D: no texture is bound to this target");
+        return;
+    }
+
+    if (!mCompressedTextureFormats.Contains(format)) {
+        ErrorInvalidEnum("compressedTexSubImage2D: compressed texture format 0x%x is not supported", format);
+        return;
+    }
+
+    if (!ValidateLevelWidthHeightForTarget(target, level, width, height, "compressedTexSubImage2D")) {
+        return;
+    }
+
+    uint32_t byteLength = view.mLength;
+    if (!ValidateCompressedTextureSize(level, format, width, height, byteLength, "compressedTexSubImage2D")) {
+        return;
+    }
+
+    size_t face = WebGLTexture::FaceForTarget(target);
+
+    if (!tex->HasImageInfoAt(level, face)) {
+        ErrorInvalidOperation("compressedTexSubImage2D: no texture image previously defined for this level and face");
+        return;
+    }
+
+    const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(level, face);
+
+    if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, imageInfo.Width(), imageInfo.Height())) {
+        ErrorInvalidValue("compressedTexSubImage2D: subtexture rectangle out of bounds");
+        return;
+    }
+
+    switch (format) {
+        case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+        {
+            if (xoffset < 0 || xoffset % 4 != 0) {
+                ErrorInvalidOperation("compressedTexSubImage2D: xoffset is not a multiple of 4");
+                return;
+            }
+            if (yoffset < 0 || yoffset % 4 != 0) {
+                ErrorInvalidOperation("compressedTexSubImage2D: yoffset is not a multiple of 4");
+                return;
+            }
+            if (width % 4 != 0 && width != imageInfo.Width()) {
+                ErrorInvalidOperation("compressedTexSubImage2D: width is not a multiple of 4 or equal to texture width");
+                return;
+            }
+            if (height % 4 != 0 && height != imageInfo.Height()) {
+                ErrorInvalidOperation("compressedTexSubImage2D: height is not a multiple of 4 or equal to texture height");
+                return;
+            }
+            break;
+        }
+    }
+
+    gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.mData);
+
+    return;
 }
 
 NS_IMETHODIMP
 WebGLContext::GetShaderParameter(nsIWebGLShader *sobj, WebGLenum pname, JS::Value *retval)
 {
     *retval = GetShaderParameter(static_cast<WebGLShader*>(sobj), pname);
     return NS_OK;
 }
@@ -5452,59 +5548,37 @@ void
 WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum internalformat,
                               WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero,
                               WebGLint border,
                               WebGLenum format, WebGLenum type,
                               void *data, PRUint32 byteLength,
                               int jsArrayType, // a TypedArray format enum, or -1 if not relevant
                               WebGLTexelFormat srcFormat, bool srcPremultiplied)
 {
-    switch (target) {
-        case LOCAL_GL_TEXTURE_2D:
-            break;
-        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:
-            if (width != height)
-                return ErrorInvalidValue("texImage2D: with cube map targets, width and height must be equal");
-            break;
-        default:
-            return ErrorInvalidEnumInfo("texImage2D: target", target);
+    if (!ValidateTexImage2DTarget(target, width, height, "texImage2D")) {
+        return;
     }
 
     switch (format) {
         case LOCAL_GL_RGB:
         case LOCAL_GL_RGBA:
         case LOCAL_GL_ALPHA:
         case LOCAL_GL_LUMINANCE:
         case LOCAL_GL_LUMINANCE_ALPHA:
             break;
         default:
             return ErrorInvalidEnumInfo("texImage2D: internal format", internalformat);
     }
 
     if (format != internalformat)
         return ErrorInvalidOperation("texImage2D: format does not match internalformat");
 
-    WebGLsizei maxTextureSize = MaxTextureSizeForTarget(target);
-
-    if (level < 0)
-        return ErrorInvalidValue("texImage2D: level must be >= 0");
-
-    if (!(maxTextureSize >> level))
-        return ErrorInvalidValue("texImage2D: 2^level exceeds maximum texture size");
-
-    if (width < 0 || height < 0)
-        return ErrorInvalidValue("texImage2D: width and height must be >= 0");
-
-    if (width > maxTextureSize || height > maxTextureSize)
-        return ErrorInvalidValue("texImage2D: width or height exceeds maximum texture size");
+    if (!ValidateLevelWidthHeightForTarget(target, level, width, height, "texImage2D")) {
+        return;
+    }
 
     if (level >= 1) {
         if (!(is_pot_assuming_nonnegative(width) &&
               is_pot_assuming_nonnegative(height)))
             return ErrorInvalidValue("texImage2D: with level > 0, width and height must be powers of two");
     }
 
     if (border != 0)
@@ -5733,29 +5807,19 @@ WebGLContext::TexSubImage2D_base(WebGLen
         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("texSubImage2D: target", target);
     }
 
-    WebGLsizei maxTextureSize = MaxTextureSizeForTarget(target);
-
-    if (level < 0)
-        return ErrorInvalidValue("texSubImage2D: level must be >= 0");
-
-    if (!(maxTextureSize >> level))
-        return ErrorInvalidValue("texSubImage2D: 2^level exceeds maximum texture size");
-
-    if (width < 0 || height < 0)
-        return ErrorInvalidValue("texSubImage2D: width and height must be >= 0");
-
-    if (width > maxTextureSize || height > maxTextureSize)
-        return ErrorInvalidValue("texSubImage2D: width or height exceeds maximum texture size");
+    if (!ValidateLevelWidthHeightForTarget(target, level, width, height, "texSubImage2D")) {
+        return;
+    }
 
     if (level >= 1) {
         if (!(is_pot_assuming_nonnegative(width) &&
               is_pot_assuming_nonnegative(height)))
             return ErrorInvalidValue("texSubImage2D: with level > 0, width and height must be powers of two");
     }
 
     PRUint32 dstTexelSize = 0;
--- a/content/canvas/src/WebGLContextNotSupported.cpp
+++ b/content/canvas/src/WebGLContextNotSupported.cpp
@@ -52,8 +52,9 @@ DOMCI_DATA(WebGLFramebuffer, void)
 DOMCI_DATA(WebGLRenderbuffer, void)
 DOMCI_DATA(WebGLUniformLocation, void)
 DOMCI_DATA(WebGLShaderPrecisionFormat, void)
 DOMCI_DATA(WebGLActiveInfo, void)
 DOMCI_DATA(WebGLExtension, void)
 DOMCI_DATA(WebGLExtensionStandardDerivatives, void)
 DOMCI_DATA(WebGLExtensionTextureFilterAnisotropic, void)
 DOMCI_DATA(WebGLExtensionLoseContext, void)
+DOMCI_DATA(WebGLExtensionCompressedTextureS3TC, void)
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -366,38 +366,152 @@ bool WebGLContext::ValidateGLSLString(co
              ErrorInvalidValue("%s: string contains the illegal character '%d'", info, string.CharAt(i));
              return false;
         }
     }
 
     return true;
 }
 
-PRUint32 WebGLContext::GetTexelSize(WebGLenum format, WebGLenum type)
+bool WebGLContext::ValidateTexImage2DTarget(WebGLenum target, WebGLsizei width, WebGLsizei height,
+                                            const char* info)
+{
+    switch (target) {
+        case LOCAL_GL_TEXTURE_2D:
+            break;
+        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:
+            if (width != height) {
+                ErrorInvalidValue("%s: with cube map targets, width and height must be equal", info);
+                return false;
+            }
+            break;
+        default:
+            ErrorInvalidEnum("%s: invalid target enum 0x%x", info, target);
+            return false;
+    }
+
+    return true;
+}
+
+bool WebGLContext::ValidateCompressedTextureSize(WebGLint level, WebGLenum format, WebGLsizei width,
+                                                 WebGLsizei height, uint32_t byteLength, const char* info)
+{
+    CheckedUint32 calculated_byteLength = 0;
+    CheckedUint32 checked_byteLength = byteLength;
+    if (!checked_byteLength.valid()) {
+        ErrorInvalidValue("%s: data length out of bounds", info);
+        return false;
+    }
+
+    switch (format) {
+        case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+        {
+            calculated_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 8;
+            if (!calculated_byteLength.valid() || !(checked_byteLength == calculated_byteLength)) {
+                ErrorInvalidValue("%s: data size does not match dimensions", info);
+                return false;
+            }
+            break;
+        }
+        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+        {
+            calculated_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 16;
+            if (!calculated_byteLength.valid() || !(checked_byteLength == calculated_byteLength)) {
+                ErrorInvalidValue("%s: data size does not match dimensions", info);
+                return false;
+            }
+            break;
+        }
+    }
+
+    switch (format) {
+        case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+        {
+            if (level == 0 && width % 4 == 0 && height % 4 == 0) {
+                return true;
+            }
+            if (level > 0
+                && (width == 0 || width == 1 || width == 2 || width % 4 == 0)
+                && (height == 0 || height == 1 || height == 2 || height % 4 == 0))
+            {
+                return true;
+            }
+        }
+    }
+
+    ErrorInvalidOperation("%s: level parameter does not match width and height", info);
+    return false;
+}
+
+bool WebGLContext::ValidateLevelWidthHeightForTarget(WebGLenum target, WebGLint level, WebGLsizei width,
+                                                     WebGLsizei height, const char* info)
+{
+    WebGLsizei maxTextureSize = MaxTextureSizeForTarget(target);
+
+    if (level < 0) {
+        ErrorInvalidValue("%s: level must be >= 0", info);
+        return false;
+    }
+
+    if (!(maxTextureSize >> level)) {
+        ErrorInvalidValue("%s: 2^level exceeds maximum texture size");
+        return false;
+    }
+
+    if (width < 0 || height < 0) {
+        ErrorInvalidValue("%s: width and height must be >= 0");
+        return false;
+    }
+
+    if (width > maxTextureSize || height > maxTextureSize) {
+        ErrorInvalidValue("%s: width or height exceeds maximum texture size");
+        return false;
+    }
+
+    return true;
+}
+
+PRUint32 WebGLContext::GetBitsPerTexel(WebGLenum format, WebGLenum type)
 {
     if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
-        int multiplier = type == LOCAL_GL_FLOAT ? 4 : 1;
+        int multiplier = type == LOCAL_GL_FLOAT ? 32 : 8;
         switch (format) {
             case LOCAL_GL_ALPHA:
             case LOCAL_GL_LUMINANCE:
                 return 1 * multiplier;
             case LOCAL_GL_LUMINANCE_ALPHA:
                 return 2 * multiplier;
             case LOCAL_GL_RGB:
                 return 3 * multiplier;
             case LOCAL_GL_RGBA:
                 return 4 * multiplier;
+            case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+            case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+                return 4;
+            case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+            case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+                return 8;
             default:
                 break;
         }
     } else if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
                type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
                type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
     {
-        return 2;
+        return 16;
     }
 
     NS_ABORT();
     return 0;
 }
 
 bool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type, int jsArrayType,
                                               PRUint32 *texelSize, const char *info)
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/WebGLExtensionCompressedTextureS3TC.cpp
@@ -0,0 +1,33 @@
+/* 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 "WebGLContext.h"
+#include "WebGLExtensions.h"
+
+using namespace mozilla;
+
+WebGLExtensionCompressedTextureS3TC::WebGLExtensionCompressedTextureS3TC(WebGLContext* context)
+    : WebGLExtension(context)
+{
+    context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
+    context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
+    context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT);
+    context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
+}
+
+WebGLExtensionCompressedTextureS3TC::~WebGLExtensionCompressedTextureS3TC()
+{
+
+}
+
+NS_IMPL_ADDREF_INHERITED(WebGLExtensionCompressedTextureS3TC, WebGLExtension)
+NS_IMPL_RELEASE_INHERITED(WebGLExtensionCompressedTextureS3TC, WebGLExtension)
+
+DOMCI_DATA(WebGLExtensionCompressedTextureS3TC, WebGLExtensionCompressedTextureS3TC)
+
+NS_INTERFACE_MAP_BEGIN(WebGLExtensionCompressedTextureS3TC)
+  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionCompressedTextureS3TC)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionCompressedTextureS3TC)
+NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
--- a/content/canvas/src/WebGLExtensionLoseContext.cpp
+++ b/content/canvas/src/WebGLExtensionLoseContext.cpp
@@ -31,24 +31,19 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include <stdarg.h>
-
 #include "WebGLContext.h"
 #include "WebGLExtensions.h"
 
-#include "nsContentUtils.h"
-#include "mozilla/Preferences.h"
-
 using namespace mozilla;
 
 WebGLExtensionLoseContext::WebGLExtensionLoseContext(WebGLContext* context) :
     WebGLExtension(context)
 {
 
 }
 
--- a/content/canvas/src/WebGLExtensionStandardDerivatives.cpp
+++ b/content/canvas/src/WebGLExtensionStandardDerivatives.cpp
@@ -31,24 +31,19 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include <stdarg.h>
-
 #include "WebGLContext.h"
 #include "WebGLExtensions.h"
 
-#include "nsContentUtils.h"
-#include "mozilla/Preferences.h"
-
 using namespace mozilla;
 
 WebGLExtensionStandardDerivatives::WebGLExtensionStandardDerivatives(WebGLContext* context) :
     WebGLExtension(context)
 {
 
 }
 
--- a/content/canvas/src/WebGLExtensionTextureFilterAnisotropic.cpp
+++ b/content/canvas/src/WebGLExtensionTextureFilterAnisotropic.cpp
@@ -31,24 +31,19 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include <stdarg.h>
-
 #include "WebGLContext.h"
 #include "WebGLExtensions.h"
 
-#include "nsContentUtils.h"
-#include "mozilla/Preferences.h"
-
 using namespace mozilla;
 
 WebGLExtensionTextureFilterAnisotropic::WebGLExtensionTextureFilterAnisotropic(WebGLContext* context) :
     WebGLExtension(context)
 {
 
 }
 
--- a/content/canvas/src/WebGLExtensions.h
+++ b/content/canvas/src/WebGLExtensions.h
@@ -72,11 +72,23 @@ class WebGLExtensionTextureFilterAnisotr
 public:
     WebGLExtensionTextureFilterAnisotropic(WebGLContext* context);
     virtual ~WebGLExtensionTextureFilterAnisotropic();
 
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIWEBGLEXTENSION
 };
 
+class WebGLExtensionCompressedTextureS3TC :
+    public nsIWebGLExtensionCompressedTextureS3TC,
+    public WebGLExtension
+{
+public:
+    WebGLExtensionCompressedTextureS3TC(WebGLContext* context);
+    virtual ~WebGLExtensionCompressedTextureS3TC();
+
+    NS_DECL_ISUPPORTS_INHERITED
+    NS_DECL_NSIWEBGLEXTENSION
+};
+
 }
 
 #endif // WEBGLEXTENSIONS_H_
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1541,16 +1541,19 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_ADDPROPERTY)
   NS_DEFINE_CLASSINFO_DATA(WebGLExtensionTextureFilterAnisotropic, WebGLExtensionSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_ADDPROPERTY)
   NS_DEFINE_CLASSINFO_DATA(WebGLExtensionLoseContext, WebGLExtensionSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_ADDPROPERTY)
+  NS_DEFINE_CLASSINFO_DATA(WebGLExtensionCompressedTextureS3TC, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS |
+                           nsIXPCScriptable::WANT_ADDPROPERTY)
 
   NS_DEFINE_CLASSINFO_DATA(PaintRequest, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PaintRequestList, nsPaintRequestListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(ScrollAreaEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -4245,16 +4248,20 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionTextureFilterAnisotropic, nsIWebGLExtensionTextureFilterAnisotropic)
     DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionTextureFilterAnisotropic)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionLoseContext, nsIWebGLExtensionLoseContext)
     DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionLoseContext)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionCompressedTextureS3TC, nsIWebGLExtensionCompressedTextureS3TC)
+    DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionCompressedTextureS3TC)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(PaintRequest, nsIDOMPaintRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequest)
    DOM_CLASSINFO_MAP_END
  
   DOM_CLASSINFO_MAP_BEGIN(PaintRequestList, nsIDOMPaintRequestList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequestList)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -484,16 +484,17 @@ DOMCI_CLASS(WebGLFramebuffer)
 DOMCI_CLASS(WebGLRenderbuffer)
 DOMCI_CLASS(WebGLUniformLocation)
 DOMCI_CLASS(WebGLShaderPrecisionFormat)
 DOMCI_CLASS(WebGLActiveInfo)
 DOMCI_CLASS(WebGLExtension)
 DOMCI_CLASS(WebGLExtensionStandardDerivatives)
 DOMCI_CLASS(WebGLExtensionTextureFilterAnisotropic)
 DOMCI_CLASS(WebGLExtensionLoseContext)
+DOMCI_CLASS(WebGLExtensionCompressedTextureS3TC)
 
 DOMCI_CLASS(PaintRequest)
 DOMCI_CLASS(PaintRequestList)
 
 DOMCI_CLASS(ScrollAreaEvent)
 DOMCI_CLASS(PopStateEvent)
 DOMCI_CLASS(HashChangeEvent)
 
--- a/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
+++ b/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
@@ -173,16 +173,26 @@ interface nsIWebGLExtensionLoseContext :
 
 [scriptable, uuid(73bfb64d-94bd-4a7a-9eab-6b6d32e57aa0)]
 interface nsIWebGLExtensionTextureFilterAnisotropic : nsIWebGLExtension
 {
   const WebGLenum TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
   const WebGLenum MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
 };
 
+[scriptable, builtinclass, uuid(a1508b6f-f2ab-44cf-bbb4-3cfb339e1e8a)]
+interface nsIWebGLExtensionCompressedTextureS3TC : nsIWebGLExtension
+{
+    /* Compressed Texture Formats */
+    const WebGLenum COMPRESSED_RGB_S3TC_DXT1_EXT        = 0x83F0;
+    const WebGLenum COMPRESSED_RGBA_S3TC_DXT1_EXT       = 0x83F1;
+    const WebGLenum COMPRESSED_RGBA_S3TC_DXT3_EXT       = 0x83F2;
+    const WebGLenum COMPRESSED_RGBA_S3TC_DXT5_EXT       = 0x83F3;
+};
+
 [scriptable, builtinclass, uuid(a1fdfb76-6a08-4a1a-b0c9-d92ef3357cb9)]
 interface nsIDOMWebGLRenderingContext : nsISupports
 {
   //
   //  CONSTANTS
   //
 
   /* ClearBufferMask */
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -95,16 +95,17 @@ static const char *sExtensionNames[] = {
     "GL_ARB_texture_non_power_of_two",
     "GL_ARB_pixel_buffer_object",
     "GL_ARB_ES2_compatibility",
     "GL_OES_texture_float",
     "GL_ARB_texture_float",
     "GL_EXT_unpack_subimage",
     "GL_OES_standard_derivatives",
     "GL_EXT_texture_filter_anisotropic",
+    "GL_EXT_texture_compression_s3tc",
     "GL_EXT_framebuffer_blit",
     "GL_ANGLE_framebuffer_blit",
     "GL_EXT_framebuffer_multisample",
     "GL_ANGLE_framebuffer_multisample",
     "GL_OES_rgb8_rgba8",
     "GL_ARB_robustness",
     "GL_EXT_robustness",
     "GL_ARB_sync",
@@ -140,16 +141,18 @@ GLContext::InitWithPrefix(const char *pr
         { (PRFuncPtr*) &mSymbols.fBlendFunc, { "BlendFunc", NULL } },
         { (PRFuncPtr*) &mSymbols.fBlendFuncSeparate, { "BlendFuncSeparate", "BlendFuncSeparateEXT", NULL } },
         { (PRFuncPtr*) &mSymbols.fBufferData, { "BufferData", NULL } },
         { (PRFuncPtr*) &mSymbols.fBufferSubData, { "BufferSubData", NULL } },
         { (PRFuncPtr*) &mSymbols.fClear, { "Clear", NULL } },
         { (PRFuncPtr*) &mSymbols.fClearColor, { "ClearColor", NULL } },
         { (PRFuncPtr*) &mSymbols.fClearStencil, { "ClearStencil", NULL } },
         { (PRFuncPtr*) &mSymbols.fColorMask, { "ColorMask", NULL } },
+        { (PRFuncPtr*) &mSymbols.fCompressedTexImage2D, {"CompressedTexImage2D", NULL} },
+        { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage2D, {"CompressedTexSubImage2D", NULL} },
         { (PRFuncPtr*) &mSymbols.fCullFace, { "CullFace", NULL } },
         { (PRFuncPtr*) &mSymbols.fDetachShader, { "DetachShader", "DetachShaderARB", NULL } },
         { (PRFuncPtr*) &mSymbols.fDepthFunc, { "DepthFunc", NULL } },
         { (PRFuncPtr*) &mSymbols.fDepthMask, { "DepthMask", NULL } },
         { (PRFuncPtr*) &mSymbols.fDisable, { "Disable", NULL } },
         { (PRFuncPtr*) &mSymbols.fDisableVertexAttribArray, { "DisableVertexAttribArray", "DisableVertexAttribArrayARB", NULL } },
         { (PRFuncPtr*) &mSymbols.fDrawArrays, { "DrawArrays", NULL } },
         { (PRFuncPtr*) &mSymbols.fDrawElements, { "DrawElements", NULL } },
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -1615,16 +1615,17 @@ public:
         ARB_texture_non_power_of_two,
         ARB_pixel_buffer_object,
         ARB_ES2_compatibility,
         OES_texture_float,
         ARB_texture_float,
         EXT_unpack_subimage,
         OES_standard_derivatives,
         EXT_texture_filter_anisotropic,
+        EXT_texture_compression_s3tc,
         EXT_framebuffer_blit,
         ANGLE_framebuffer_blit,
         EXT_framebuffer_multisample,
         ANGLE_framebuffer_multisample,
         OES_rgb8_rgba8,
         ARB_robustness,
         EXT_robustness,
         ARB_sync,
@@ -2204,16 +2205,28 @@ public:
     }
 
     void fColorMask(realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha) {
         BEFORE_GL_CALL;
         mSymbols.fColorMask(red, green, blue, alpha);
         AFTER_GL_CALL;
     }
 
+    void fCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *pixels) {
+        BEFORE_GL_CALL;
+        mSymbols.fCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, pixels);
+        AFTER_GL_CALL;
+    }
+
+    void fCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *pixels) {
+        BEFORE_GL_CALL;
+        mSymbols.fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, pixels);
+        AFTER_GL_CALL;
+    }
+
     void fCullFace(GLenum mode) {
         BEFORE_GL_CALL;
         mSymbols.fCullFace(mode);
         AFTER_GL_CALL;
     }
 
     void fDetachShader(GLuint program, GLuint shader) {
         BEFORE_GL_CALL;
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -96,16 +96,20 @@ struct GLContextSymbols
     typedef void (GLAPIENTRY * PFNGLCLEARPROC) (GLbitfield);
     PFNGLCLEARPROC fClear;
     typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLclampf, GLclampf, GLclampf, GLclampf);
     PFNGLCLEARCOLORPROC fClearColor;
     typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint);
     PFNGLCLEARSTENCILPROC fClearStencil;
     typedef void (GLAPIENTRY * PFNGLCOLORMASKPROC) (realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha);
     PFNGLCOLORMASKPROC fColorMask;
+    typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *pixels);
+    PFNGLCOMPRESSEDTEXIMAGE2D fCompressedTexImage2D;
+    typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *pixels);
+    PFNGLCOMPRESSEDTEXSUBIMAGE2D fCompressedTexSubImage2D;
     typedef void (GLAPIENTRY * PFNGLCULLFACEPROC) (GLenum mode);
     PFNGLCULLFACEPROC fCullFace;
     typedef void (GLAPIENTRY * PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
     PFNGLDETACHSHADERPROC fDetachShader;
     typedef void (GLAPIENTRY * PFNGLDEPTHFUNCPROC) (GLenum);
     PFNGLDEPTHFUNCPROC fDepthFunc;
     typedef void (GLAPIENTRY * PFNGLDEPTHMASKPROC) (realGLboolean);
     PFNGLDEPTHMASKPROC fDepthMask;
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -503,16 +503,17 @@ irregularFilenames = {
     'nsIWebGLRenderbuffer': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLShaderPrecisionFormat' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLActiveInfo': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLUniformLocation': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtension': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionStandardDerivatives' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionTextureFilterAnisotropic' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionLoseContext' : 'nsIDOMWebGLRenderingContext',
+    'nsIWebGLExtensionCompressedTextureS3TC' : 'nsIDOMWebGLRenderingContext',
 
     'nsIIndexedDatabaseUsageCallback': 'nsIIndexedDatabaseManager',
 
     'nsIDOMTouch': 'nsIDOMTouchEvent',
     'nsIDOMTouchList': 'nsIDOMTouchEvent',
 
     'nsIDOMMutationRecord': 'nsIDOMMutationObserver',