Bug 728354 - Implement WebGL EXT_texture_filter_anisotropic extension *proposal* - r=bjacob
authorFlorian Boesch <pyalot@gmail.com>
Thu, 23 Feb 2012 08:43:57 -0500
changeset 87530 a6dfdf5a529d25fea881833bba7dbace7852980f
parent 87529 e65188cac8b57e4ff51d296c0c034035fdf96617
child 87531 1f3643b7de2d2325eda769e1520dcef0892f5f53
push id22130
push userrnewman@mozilla.com
push dateFri, 24 Feb 2012 02:35:54 +0000
treeherdermozilla-central@d23600a1d4a7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob
bugs728354
milestone13.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 728354 - Implement WebGL EXT_texture_filter_anisotropic extension *proposal* - r=bjacob The spec proposal for this extension is at https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/extensions/proposals/EXT_texture_filter_anisotropic/index.html This adds a conformance test as well, that will have to be merged upstream.
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/WebGLExtensionTextureFilterAnisotropic.cpp
content/canvas/src/WebGLExtensions.h
content/canvas/test/webgl/conformance/extensions/00_test_list.txt
content/canvas/test/webgl/conformance/extensions/ext-texture-filter-anisotropic.html
content/canvas/test/webgl/ext-texture-filter-anisotropic.patch
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
js/xpconnect/src/dom_quickstubs.qsconf
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -66,16 +66,17 @@ ifdef MOZ_WEBGL
 
 CPPSRCS += \
 	WebGLContext.cpp \
 	WebGLContextGL.cpp \
 	WebGLContextUtils.cpp \
 	WebGLContextReporter.cpp \
 	WebGLContextValidate.cpp \
 	WebGLExtensionStandardDerivatives.cpp \
+	WebGLExtensionTextureFilterAnisotropic.cpp \
 	WebGLExtensionLoseContext.cpp \
 	$(NULL)
 
 DEFINES += -DUSE_ANGLE
 USE_ANGLE=1
 
 else
 
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -815,24 +815,26 @@ WebGLContext::MozGetUnderlyingParamStrin
 }
 
 bool WebGLContext::IsExtensionSupported(WebGLExtensionID ei)
 {
     bool isSupported;
 
     switch (ei) {
         case WebGL_OES_texture_float:
-            MakeContextCurrent();
             isSupported = gl->IsExtensionSupported(gl->IsGLES2() ? GLContext::OES_texture_float 
                                                                  : GLContext::ARB_texture_float);
 	    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:
             // We always support this extension.
             isSupported = true;
             break;
         default:
             isSupported = false;
     }
 
@@ -855,27 +857,34 @@ WebGLContext::GetExtension(const nsAStri
     if (aName.EqualsLiteral("OES_texture_float")) {
         if (IsExtensionSupported(WebGL_OES_texture_float))
             ei = WebGL_OES_texture_float;
     }
     else if (aName.EqualsLiteral("OES_standard_derivatives")) {
         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 (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:
                     mEnabledExtensions[ei] = new WebGLExtensionLoseContext(this);
                     break;
                 // create an extension for any types that don't
                 // have any additional tokens or methods
                 default:
                     mEnabledExtensions[ei] = new WebGLExtension(this);
                     break;
@@ -1290,16 +1299,21 @@ NS_IMPL_RELEASE(WebGLExtensionStandardDe
 DOMCI_DATA(WebGLExtensionStandardDerivatives, WebGLExtensionStandardDerivatives)
 
 NS_INTERFACE_MAP_BEGIN(WebGLExtensionStandardDerivatives)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionStandardDerivatives)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionStandardDerivatives)
 NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
 
+NS_IMPL_ADDREF(WebGLExtensionTextureFilterAnisotropic)
+NS_IMPL_RELEASE(WebGLExtensionTextureFilterAnisotropic)
+
+DOMCI_DATA(WebGLExtensionTextureFilterAnisotropic, WebGLExtensionTextureFilterAnisotropic)
+
 NS_IMPL_ADDREF(WebGLExtensionLoseContext)
 NS_IMPL_RELEASE(WebGLExtensionLoseContext)
 
 DOMCI_DATA(WebGLExtensionLoseContext, WebGLExtensionLoseContext)
 
 NS_INTERFACE_MAP_BEGIN(WebGLExtensionLoseContext)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionLoseContext)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
@@ -1404,16 +1418,18 @@ WebGLContext::GetSupportedExtensions(nsI
     NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
 
     nsTArray<const char *> extList;
 
     if (IsExtensionSupported(WebGL_OES_texture_float))
         extList.InsertElementAt(extList.Length(), "OES_texture_float");
     if (IsExtensionSupported(WebGL_OES_standard_derivatives))
         extList.InsertElementAt(extList.Length(), "OES_standard_derivatives");
+    if (IsExtensionSupported(WebGL_EXT_texture_filter_anisotropic))
+        extList.InsertElementAt(extList.Length(), "MOZ_EXT_texture_filter_anisotropic");
     if (IsExtensionSupported(WebGL_MOZ_WEBGL_lose_context))
         extList.InsertElementAt(extList.Length(), "MOZ_WEBGL_lose_context");
 
     nsresult rv;
     if (extList.Length() > 0) {
         rv = wrval->SetAsArray(nsIDataType::VTYPE_CHAR_STR, nsnull,
                                extList.Length(), &extList[0]);
     } else {
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -740,16 +740,17 @@ protected:
         // be restored.
         ContextLostAwaitingRestore
     };
 
     // extensions
     enum WebGLExtensionID {
         WebGL_OES_texture_float,
         WebGL_OES_standard_derivatives,
+        WebGL_EXT_texture_filter_anisotropic,
         WebGL_MOZ_WEBGL_lose_context,
         WebGLExtensionID_Max
     };
     nsCOMPtr<WebGLExtension> mEnabledExtensions[WebGLExtensionID_Max];
     bool IsExtensionEnabled(WebGLExtensionID ext) const {
         NS_ABORT_IF_FALSE(ext >= 0 && ext < WebGLExtensionID_Max, "bogus index!");
         return mEnabledExtensions[ext] != nsnull;
     }
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -2205,16 +2205,25 @@ WebGLContext::GetParameter(PRUint32 pnam
             gl->fGetIntegerv(pname, &i);
             GLuint i_unsigned(i); // this is where -1 becomes 2^32-1
             double i_double(i_unsigned); // pass as FP value to allow large values such as 2^32-1.
             wrval->SetAsDouble(i_double);
         }
             break;
 
 // float
+        case LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
+            if (mEnabledExtensions[WebGL_EXT_texture_filter_anisotropic]) {
+                GLfloat f = 0.f;
+                gl->fGetFloatv(pname, &f);
+                wrval->SetAsFloat(f);
+            } else {
+                return ErrorInvalidEnum("getParameter: parameter", pname);
+            }
+            break;
         case LOCAL_GL_DEPTH_CLEAR_VALUE:
         case LOCAL_GL_LINE_WIDTH:
         case LOCAL_GL_POLYGON_OFFSET_FACTOR:
         case LOCAL_GL_POLYGON_OFFSET_UNITS:
         case LOCAL_GL_SAMPLE_COVERAGE_VALUE:
         {
             GLfloat f = 0.f;
             gl->fGetFloatv(pname, &f);
@@ -2674,16 +2683,17 @@ nsresult WebGLContext::TexParameter_base
     if (!ValidateTextureTargetEnum(target, "texParameter: target"))
         return NS_OK;
 
     WebGLTexture *tex = activeBoundTextureForTarget(target);
     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:
             switch (intParam) {
                 case LOCAL_GL_NEAREST:
                 case LOCAL_GL_LINEAR:
                 case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
                 case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
@@ -2722,28 +2732,43 @@ nsresult WebGLContext::TexParameter_base
                 case LOCAL_GL_MIRRORED_REPEAT:
                 case LOCAL_GL_REPEAT:
                     tex->SetWrapT(intParam);
                     break;
                 default:
                     pnameAndParamAreIncompatible = true;
             }
             break;
+        case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
+            if (mEnabledExtensions[WebGL_EXT_texture_filter_anisotropic]) {
+                if (floatParamPtr && floatParam < 1.f)
+                    paramValueInvalid = true;
+                else if (intParamPtr && intParam < 1)
+                    paramValueInvalid = true;
+            }
+            else
+                pnameAndParamAreIncompatible = true;
+            break;
         default:
             return ErrorInvalidEnumInfo("texParameter: pname", pname);
     }
 
     if (pnameAndParamAreIncompatible) {
-        // note that currently all params are enums, and the tex-input-validation test wants INVALID_ENUM errors
-        // even for texParameterf. why not.
         if (intParamPtr)
             return ErrorInvalidEnum("texParameteri: pname %x and param %x (decimal %d) are mutually incompatible",
                                     pname, intParam, intParam);
         else
-            return ErrorInvalidEnum("texParameterf: pname %x and floating-point param %e are mutually incompatible",
+            return ErrorInvalidEnum("texParameterf: pname %x and param %g are mutually incompatible",
+                                    pname, floatParam);
+    } else if (paramValueInvalid) {
+        if (intParamPtr)
+            return ErrorInvalidValue("texParameteri: pname %x and param %x (decimal %d) is invalid",
+                                    pname, intParam, intParam);
+        else
+            return ErrorInvalidValue("texParameterf: pname %x and param %g is invalid",
                                     pname, floatParam);
     }
 
     MakeContextCurrent();
     if (intParamPtr)
         gl->fTexParameteri(target, pname, intParam);
     else
         gl->fTexParameterf(target, pname, floatParam);
@@ -2794,16 +2819,25 @@ WebGLContext::GetTexParameter(WebGLenum 
         case LOCAL_GL_TEXTURE_WRAP_S:
         case LOCAL_GL_TEXTURE_WRAP_T:
         {
             GLint i = 0;
             gl->fGetTexParameteriv(target, pname, &i);
             wrval->SetAsInt32(i);
         }
             break;
+        case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
+            if (mEnabledExtensions[WebGL_EXT_texture_filter_anisotropic]) {
+                GLfloat f = 0.f;
+                gl->fGetTexParameterfv(target, pname, &f);
+                wrval->SetAsFloat(f);
+            }
+            else
+                return ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
+            break;
 
         default:
             return ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
     }
 
     *retval = wrval.forget().get();
 
     return NS_OK;
--- a/content/canvas/src/WebGLContextNotSupported.cpp
+++ b/content/canvas/src/WebGLContextNotSupported.cpp
@@ -50,9 +50,10 @@ DOMCI_DATA(WebGLProgram, void)
 DOMCI_DATA(WebGLShader, void)
 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)
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/WebGLExtensionTextureFilterAnisotropic.cpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Florian Boesch <pyalot@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * 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;
+
+NS_INTERFACE_MAP_BEGIN(WebGLExtensionTextureFilterAnisotropic)
+  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionTextureFilterAnisotropic)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionTextureFilterAnisotropic)
+NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
+
+WebGLExtensionTextureFilterAnisotropic::WebGLExtensionTextureFilterAnisotropic(WebGLContext* context) :
+    WebGLExtension(context)
+{
+
+}
+
+WebGLExtensionTextureFilterAnisotropic::~WebGLExtensionTextureFilterAnisotropic()
+{
+
+}
--- a/content/canvas/src/WebGLExtensions.h
+++ b/content/canvas/src/WebGLExtensions.h
@@ -36,19 +36,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef WEBGLEXTENSIONS_H_
 #define WEBGLEXTENSIONS_H_
 
 namespace mozilla {
 
-class WebGLExtensionLoseContext;
-class WebGLExtensionStandardDerivatives;
-
 class WebGLExtensionLoseContext :
     public nsIWebGLExtensionLoseContext,
     public WebGLExtension
 {
 public:
     WebGLExtensionLoseContext(WebGLContext*);
     virtual ~WebGLExtensionLoseContext();
 
@@ -63,11 +60,23 @@ class WebGLExtensionStandardDerivatives 
 public:
     WebGLExtensionStandardDerivatives(WebGLContext* context);
     virtual ~WebGLExtensionStandardDerivatives();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLEXTENSION
 };
 
+class WebGLExtensionTextureFilterAnisotropic :
+    public nsIWebGLExtensionTextureFilterAnisotropic,
+    public WebGLExtension
+{
+public:
+    WebGLExtensionTextureFilterAnisotropic(WebGLContext* context);
+    virtual ~WebGLExtensionTextureFilterAnisotropic();
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIWEBGLEXTENSION
+};
+
 }
 
 #endif // WEBGLEXTENSIONS_H_
--- a/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
+++ b/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
@@ -1,7 +1,8 @@
 oes-standard-derivatives.html
+ext-texture-filter-anisotropic.html
 oes-texture-float.html
 oes-vertex-array-object.html
 webgl-debug-renderer-info.html
 webgl-debug-shaders.html
 --min-version 1.0.2 webgl-experimental-compressed-textures.html
 
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/extensions/ext-texture-filter-anisotropic.html
@@ -0,0 +1,157 @@
+<!--
+Copyright (c) 2012 Florian Boesch <pyalot@gmail.com>. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_texture_filter_anisotropic Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../../resources/js-test-pre.js"></script>
+<script src="../resources/webgl-test.js"></script>
+<script src="../resources/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+
+<script>
+description("This test verifies the functionality of the EXT_texture_filter_anisotropic extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = create3DContext(canvas);
+var ext = null;
+
+if (!gl) {
+    testFailed("WebGL context does not exist");
+} else {
+    testPassed("WebGL context exists");
+
+    // Run tests with extension disabled
+    runHintTestDisabled();
+
+    // Query the extension and store globally so shouldBe can access it
+    ext = gl.getExtension("MOZ_EXT_texture_filter_anisotropic");
+    if (!ext) {
+        testPassed("No EXT_texture_filter_anisotropic support -- this is legal");
+
+        runSupportedTest(false);
+    } else {
+        testPassed("Successfully enabled EXT_texture_filter_anisotropic extension");
+
+        runSupportedTest(true);
+        runHintTestEnabled();
+    }
+}
+
+function runSupportedTest(extensionEnabled) {
+    var supported = gl.getSupportedExtensions();
+    if (supported.indexOf("MOZ_EXT_texture_filter_anisotropic") >= 0) {
+        if (extensionEnabled) {
+            testPassed("EXT_texture_filter_anisotropic listed as supported and getExtension succeeded");
+        } else {
+            testFailed("EXT_texture_filter_anisotropic listed as supported but getExtension failed");
+        }
+    } else {
+        if (extensionEnabled) {
+            testFailed("EXT_texture_filter_anisotropic not listed as supported but getExtension succeeded");
+        } else {
+            testPassed("EXt_texture_filter_anisotropic not listed as supported and getExtension failed -- this is legal");
+        }
+    }
+}
+
+function runHintTestDisabled() {
+    debug("Testing MAX_TEXTURE_MAX_ANISOTROPY with extension disabled");
+    
+    var MAX_TEXTURE_MAX_ANISOTROPY = 0x84FF;
+    gl.getParameter(MAX_TEXTURE_MAX_ANISOTROPY);
+    glErrorShouldBe(gl, gl.INVALID_ENUM, "MAX_TEXTURE_MAX_ANISOTROPY should not be queryable if extension is disabled");
+    
+    debug("Testing TEXTURE_MAX_ANISOTROPY with extension disabled");
+    var TEXTURE_MAX_ANISOTROPY = 0x84FE;
+    var texture = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, texture);
+   
+    gl.getTexParameter(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY);
+    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be queryable if extension is disabled");
+
+    gl.texParameterf(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY, 1);
+    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be settable if extension is disabled");
+    
+    gl.texParameteri(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY, 1);
+    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be settable if extension is disabled");
+
+    gl.deleteTexture(texture);
+}
+
+function runHintTestEnabled() {
+    debug("Testing MAX_TEXTURE_MAX_ANISOTROPY with extension enabled");
+
+    shouldBe("ext.MAX_TEXTURE_MAX_ANISOTROPY", "0x84FF");
+
+    var max_anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY);
+    glErrorShouldBe(gl, gl.NO_ERROR, "MAX_TEXTURE_MAX_ANISOTROPY query should succeed if extension is enabled");
+
+    if(max_anisotropy >= 2){
+        testPassed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY is 2.0");
+    }
+    else{
+        testFailed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY is 2.0, returned values was: " + max_anisotropy);
+    }
+    
+    // TODO make a texture and verify initial value == 1 and setting to less than 1 is invalid value
+
+    debug("Testing TEXTURE_MAX_ANISOTROPY with extension disabled");
+    shouldBe("ext.TEXTURE_MAX_ANISOTROPY", "0x84FE");
+
+    var texture = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, texture);
+   
+    var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY);
+    glErrorShouldBe(gl, gl.NO_ERROR, "TEXTURE_MAX_ANISOTROPY query should succeed if extension is enabled");
+
+    if(queried_value == 1){
+        testPassed("Initial value of TEXTURE_MAX_ANISOTROPY is 1.0");
+    }
+    else{
+        testFailed("Initial value of TEXTURE_MAX_ANISOTROPY should be 1.0, returned value was: " + queried_value);
+    }
+
+    gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, 0);
+    glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameterf TEXTURE_MAX_ANISOTROPY set to < 1 should be an invalid value");
+    
+    gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, 0);
+    glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameteri TEXTURE_MAX_ANISOTROPY set to < 1 should be an invalid value");
+    
+    gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, max_anisotropy);
+    glErrorShouldBe(gl, gl.NO_ERROR, "texParameterf TEXTURE_MAX_ANISOTROPY set to >= 2 should should succeed");
+    
+    gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, max_anisotropy);
+    glErrorShouldBe(gl, gl.NO_ERROR, "texParameteri TEXTURE_MAX_ANISOTROPY set to >= 2 should should succeed");
+
+    var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY);
+    if(queried_value == max_anisotropy){
+        testPassed("Set value of TEXTURE_MAX_ANISOTROPY matches expecation");
+    }
+    else{
+        testFailed("Set value of TEXTURE_MAX_ANISOTROPY should be: " + max_anisotropy + " , returned value was: " + queried_value);
+    }
+
+    gl.deleteTexture(texture);
+}
+
+debug("");
+successfullyParsed = true;
+</script>
+<script src="../../resources/js-test-post.js"></script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/ext-texture-filter-anisotropic.patch
@@ -0,0 +1,174 @@
+diff --git a/content/canvas/test/webgl/conformance/extensions/00_test_list.txt b/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
+--- a/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
++++ b/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
+@@ -1,7 +1,8 @@
+ oes-standard-derivatives.html
++ext-texture-filter-anisotropic.html
+ oes-texture-float.html
+ oes-vertex-array-object.html
+ webgl-debug-renderer-info.html
+ webgl-debug-shaders.html
+ --min-version 1.0.2 webgl-experimental-compressed-textures.html
+ 
+diff --git a/content/canvas/test/webgl/conformance/extensions/ext-texture-filter-anisotropic.html b/content/canvas/test/webgl/conformance/extensions/ext-texture-filter-anisotropic.html
+new file mode 100644
+--- /dev/null
++++ b/content/canvas/test/webgl/conformance/extensions/ext-texture-filter-anisotropic.html
+@@ -0,0 +1,157 @@
++<!--
++Copyright (c) 2012 Florian Boesch <pyalot@gmail.com>. All rights reserved.
++Use of this source code is governed by a BSD-style license that can be
++found in the LICENSE file.
++ -->
++<!DOCTYPE html>
++<html>
++<head>
++<meta charset="utf-8">
++<title>WebGL EXT_texture_filter_anisotropic Conformance Tests</title>
++<link rel="stylesheet" href="../../resources/js-test-style.css"/>
++<script src="../../resources/desktop-gl-constants.js" type="text/javascript"></script>
++<script src="../../resources/js-test-pre.js"></script>
++<script src="../resources/webgl-test.js"></script>
++<script src="../resources/webgl-test-utils.js"></script>
++</head>
++<body>
++<div id="description"></div>
++<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
++<div id="console"></div>
++
++<script>
++description("This test verifies the functionality of the EXT_texture_filter_anisotropic extension, if it is available.");
++
++debug("");
++
++var wtu = WebGLTestUtils;
++var canvas = document.getElementById("canvas");
++var gl = create3DContext(canvas);
++var ext = null;
++
++if (!gl) {
++    testFailed("WebGL context does not exist");
++} else {
++    testPassed("WebGL context exists");
++
++    // Run tests with extension disabled
++    runHintTestDisabled();
++
++    // Query the extension and store globally so shouldBe can access it
++    ext = gl.getExtension("MOZ_EXT_texture_filter_anisotropic");
++    if (!ext) {
++        testPassed("No EXT_texture_filter_anisotropic support -- this is legal");
++
++        runSupportedTest(false);
++    } else {
++        testPassed("Successfully enabled EXT_texture_filter_anisotropic extension");
++
++        runSupportedTest(true);
++        runHintTestEnabled();
++    }
++}
++
++function runSupportedTest(extensionEnabled) {
++    var supported = gl.getSupportedExtensions();
++    if (supported.indexOf("MOZ_EXT_texture_filter_anisotropic") >= 0) {
++        if (extensionEnabled) {
++            testPassed("EXT_texture_filter_anisotropic listed as supported and getExtension succeeded");
++        } else {
++            testFailed("EXT_texture_filter_anisotropic listed as supported but getExtension failed");
++        }
++    } else {
++        if (extensionEnabled) {
++            testFailed("EXT_texture_filter_anisotropic not listed as supported but getExtension succeeded");
++        } else {
++            testPassed("EXt_texture_filter_anisotropic not listed as supported and getExtension failed -- this is legal");
++        }
++    }
++}
++
++function runHintTestDisabled() {
++    debug("Testing MAX_TEXTURE_MAX_ANISOTROPY with extension disabled");
++    
++    var MAX_TEXTURE_MAX_ANISOTROPY = 0x84FF;
++    gl.getParameter(MAX_TEXTURE_MAX_ANISOTROPY);
++    glErrorShouldBe(gl, gl.INVALID_ENUM, "MAX_TEXTURE_MAX_ANISOTROPY should not be queryable if extension is disabled");
++    
++    debug("Testing TEXTURE_MAX_ANISOTROPY with extension disabled");
++    var TEXTURE_MAX_ANISOTROPY = 0x84FE;
++    var texture = gl.createTexture();
++    gl.bindTexture(gl.TEXTURE_2D, texture);
++   
++    gl.getTexParameter(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY);
++    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be queryable if extension is disabled");
++
++    gl.texParameterf(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY, 1);
++    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be settable if extension is disabled");
++    
++    gl.texParameteri(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY, 1);
++    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be settable if extension is disabled");
++
++    gl.deleteTexture(texture);
++}
++
++function runHintTestEnabled() {
++    debug("Testing MAX_TEXTURE_MAX_ANISOTROPY with extension enabled");
++
++    shouldBe("ext.MAX_TEXTURE_MAX_ANISOTROPY", "0x84FF");
++
++    var max_anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY);
++    glErrorShouldBe(gl, gl.NO_ERROR, "MAX_TEXTURE_MAX_ANISOTROPY query should succeed if extension is enabled");
++
++    if(max_anisotropy >= 2){
++        testPassed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY is 2.0");
++    }
++    else{
++        testFailed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY is 2.0, returned values was: " + max_anisotropy);
++    }
++    
++    // TODO make a texture and verify initial value == 1 and setting to less than 1 is invalid value
++
++    debug("Testing TEXTURE_MAX_ANISOTROPY with extension disabled");
++    shouldBe("ext.TEXTURE_MAX_ANISOTROPY", "0x84FE");
++
++    var texture = gl.createTexture();
++    gl.bindTexture(gl.TEXTURE_2D, texture);
++   
++    var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY);
++    glErrorShouldBe(gl, gl.NO_ERROR, "TEXTURE_MAX_ANISOTROPY query should succeed if extension is enabled");
++
++    if(queried_value == 1){
++        testPassed("Initial value of TEXTURE_MAX_ANISOTROPY is 1.0");
++    }
++    else{
++        testFailed("Initial value of TEXTURE_MAX_ANISOTROPY should be 1.0, returned value was: " + queried_value);
++    }
++
++    gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, 0);
++    glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameterf TEXTURE_MAX_ANISOTROPY set to < 1 should be an invalid value");
++    
++    gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, 0);
++    glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameteri TEXTURE_MAX_ANISOTROPY set to < 1 should be an invalid value");
++    
++    gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, max_anisotropy);
++    glErrorShouldBe(gl, gl.NO_ERROR, "texParameterf TEXTURE_MAX_ANISOTROPY set to >= 2 should should succeed");
++    
++    gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, max_anisotropy);
++    glErrorShouldBe(gl, gl.NO_ERROR, "texParameteri TEXTURE_MAX_ANISOTROPY set to >= 2 should should succeed");
++
++    var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY);
++    if(queried_value == max_anisotropy){
++        testPassed("Set value of TEXTURE_MAX_ANISOTROPY matches expecation");
++    }
++    else{
++        testFailed("Set value of TEXTURE_MAX_ANISOTROPY should be: " + max_anisotropy + " , returned value was: " + queried_value);
++    }
++
++    gl.deleteTexture(texture);
++}
++
++debug("");
++successfullyParsed = true;
++</script>
++<script src="../../resources/js-test-post.js"></script>
++
++</body>
++</html>
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1538,16 +1538,18 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(WebGLShaderPrecisionFormat, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(WebGLActiveInfo, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(WebGLExtension, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(WebGLExtensionStandardDerivatives, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(WebGLExtensionTextureFilterAnisotropic, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(WebGLExtensionLoseContext, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(PaintRequest, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PaintRequestList, nsPaintRequestListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
 
@@ -4199,16 +4201,20 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(WebGLExtension, nsIWebGLExtension)
     DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtension)
   DOM_CLASSINFO_MAP_END
   
   DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionStandardDerivatives, nsIWebGLExtensionStandardDerivatives)
     DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionStandardDerivatives)
   DOM_CLASSINFO_MAP_END
+  
+  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(PaintRequest, nsIDOMPaintRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequest)
    DOM_CLASSINFO_MAP_END
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -481,16 +481,17 @@ DOMCI_CLASS(WebGLProgram)
 DOMCI_CLASS(WebGLShader)
 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(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
@@ -163,16 +163,23 @@ interface nsIWebGLExtensionStandardDeriv
 
 [scriptable, uuid(b0afc2eb-0895-4509-98de-5c383d160694)]
 interface nsIWebGLExtensionLoseContext : nsIWebGLExtension
 {
   void loseContext();
   void restoreContext();
 };
 
+[scriptable, uuid(73bfb64d-94bd-4a7a-9eab-6b6d32e57aa0)]
+interface nsIWebGLExtensionTextureFilterAnisotropic : nsIWebGLExtension
+{
+  const WebGLenum TEXTURE_MAX_ANISOTROPY = 0x84FE;
+  const WebGLenum MAX_TEXTURE_MAX_ANISOTROPY = 0x84FF;
+};
+
 [scriptable, builtinclass, uuid(f000afac-11b3-4c06-a35f-8db411f1cf54)]
 interface nsIDOMWebGLRenderingContext : nsISupports
 {
   //
   //  CONSTANTS
   //
 
   /* ClearBufferMask */
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -91,16 +91,17 @@ static const char *sExtensionNames[] = {
     "GL_APPLE_client_storage",
     "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_framebuffer_blit",
     "GL_ANGLE_framebuffer_blit",
     "GL_EXT_framebuffer_multisample",
     "GL_ANGLE_framebuffer_multisample",
     "GL_OES_rgb8_rgba8",
     "GL_ARB_robustness",
     "GL_EXT_robustness",
     NULL
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -1403,16 +1403,17 @@ public:
         APPLE_client_storage,
         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_framebuffer_blit,
         ANGLE_framebuffer_blit,
         EXT_framebuffer_multisample,
         ANGLE_framebuffer_multisample,
         OES_rgb8_rgba8,
         ARB_robustness,
         EXT_robustness,
         Extensions_Max
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -495,16 +495,17 @@ irregularFilenames = {
     'nsIWebGLShaderArray': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLFramebuffer': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLRenderbuffer': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLShaderPrecisionFormat' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLActiveInfo': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLUniformLocation': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtension': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionStandardDerivatives' : 'nsIDOMWebGLRenderingContext',
+    'nsIWebGLExtensionTextureFilterAnisotropic' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionLoseContext' : 'nsIDOMWebGLRenderingContext',
 
     'nsIIndexedDatabaseUsageCallback': 'nsIIndexedDatabaseManager',
 
     'nsIDOMTouch': 'nsIDOMTouchEvent',
     'nsIDOMTouchList': 'nsIDOMTouchEvent',
 
     'nsITelephoneCallback': 'nsITelephone',