Merge inbound to mozilla-central. a=merge
authorBogdan Tara <btara@mozilla.com>
Thu, 08 Nov 2018 20:48:31 +0200
changeset 445165 12cc80a0e9968ade961879ee07effb815da691f0
parent 445143 c812e3810b9451c4080a39c6d0fa1c06dfad7d7e (current diff)
parent 445164 f9da71cf79f8e693e13520397d63f3ad930e5d02 (diff)
child 445185 e25a3e518eb1f1451000d30e97d75cfd0f27cf67
child 445265 17b387054b05e3b3231108ece6f0b6111fc39df0
push id35011
push userbtara@mozilla.com
push dateThu, 08 Nov 2018 18:49:03 +0000
treeherdermozilla-central@12cc80a0e996 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.0a1
first release with
nightly linux32
12cc80a0e996 / 65.0a1 / 20181108220756 / files
nightly linux64
12cc80a0e996 / 65.0a1 / 20181108220756 / files
nightly mac
12cc80a0e996 / 65.0a1 / 20181108220756 / files
nightly win32
12cc80a0e996 / 65.0a1 / 20181108220756 / files
nightly win64
12cc80a0e996 / 65.0a1 / 20181108220756 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
devtools/client/framework/toolbox.js
layout/painting/nsDisplayList.cpp
--- a/accessible/atk/moz.build
+++ b/accessible/atk/moz.build
@@ -54,11 +54,12 @@ if CONFIG['MOZ_ENABLE_DBUS']:
     CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     # Used in G_DEFINE_TYPE_EXTENDED macro, probably fixed in newer glib /
     # gobject headers. See bug 1243331 comment 3.
     CXXFLAGS += [
+        '-Wno-error=unused-function',
         '-Wno-error=shadow',
         '-Wno-unused-local-typedefs',
     ]
--- a/browser/components/aboutconfig/content/aboutconfig.js
+++ b/browser/components/aboutconfig/content/aboutconfig.js
@@ -3,21 +3,34 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/Preferences.jsm");
 
 let gPrefArray;
 
 function onLoad() {
-  gPrefArray = Services.prefs.getChildList("").map(name => ({
-    name,
-    value: Preferences.get(name),
-    hasUserValue: Services.prefs.prefHasUserValue(name),
-  }));
+  gPrefArray = Services.prefs.getChildList("").map(function(name) {
+    let pref = {
+      name,
+      value: Preferences.get(name),
+      hasUserValue: Services.prefs.prefHasUserValue(name),
+    };
+    // Try in case it's a localized string.
+    // Throws an exception if there is no equivalent value in the localized files for the pref.
+    // If an execption is thrown the pref value is set to the empty string.
+    try {
+      if (!pref.hasUserValue && /^chrome:\/\/.+\/locale\/.+\.properties/.test(pref.value)) {
+        pref.value = Services.prefs.getComplexValue(name, Ci.nsIPrefLocalizedString).data;
+      }
+    } catch (ex) {
+      pref.value = "";
+    }
+    return pref;
+  });
 
   gPrefArray.sort((a, b) => a.name > b.name);
 
   let fragment = document.createDocumentFragment();
 
   for (let pref of gPrefArray) {
     let listItem = document.createElement("li");
     listItem.textContent = pref.name + " || " +
--- a/browser/components/aboutconfig/test/browser/browser_basic.js
+++ b/browser/components/aboutconfig/test/browser/browser_basic.js
@@ -1,13 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const PAGE_URL = "chrome://browser/content/aboutconfig/aboutconfig.html";
 
+add_task(async function setup() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["random.user.pref", "chrome://test/locale/testing.properties"],
+    ],
+  });
+});
+
 add_task(async function test_load_title() {
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: PAGE_URL,
   }, browser => {
     info("about:config loaded");
     return ContentTask.spawn(browser, null, async () => {
       await content.document.l10n.ready;
@@ -22,14 +30,29 @@ add_task(async function test_load_settin
     url: PAGE_URL,
   }, browser => {
     return ContentTask.spawn(browser, null, () => {
       let list = [...content.document.getElementById("list")
                                      .getElementsByTagName("li")];
       function findPref(name) {
         return list.some(e => e.textContent.trim().startsWith(name + " "));
       }
+
+      // Test if page contains elements.
       Assert.ok(findPref("plugins.testmode"));
       Assert.ok(findPref("dom.vr.enabled"));
       Assert.ok(findPref("accessibility.AOM.enabled"));
+
+      function containsLocalizedValue(value) {
+        return list.some(e => e.textContent.trim() == value);
+      }
+      // Test to see if values are localized.
+      Assert.ok(containsLocalizedValue("font.language.group || Default || String || x-western"));
+      Assert.ok(containsLocalizedValue("intl.ellipsis || Default || String || \u2026"));
+      Assert.ok(containsLocalizedValue("gecko.handlerService.schemes.mailto.1.uriTemplate || Default || String || https://mail.google.com/mail/?extsrc=mailto&url=%s"));
+
+      // Test to see if user created value is not empty string when it matches /^chrome:\/\/.+\/locale\/.+\.properties/.
+      Assert.ok(containsLocalizedValue("random.user.pref || Modified || String || chrome://test/locale/testing.properties"));
+      // Test to see if empty string when value matches /^chrome:\/\/.+\/locale\/.+\.properties/ and an exception is thrown.
+      Assert.ok(containsLocalizedValue("gecko.handlerService.schemes.irc.1.name || Default || String ||"));
     });
   });
 });
new file mode 100644
--- /dev/null
+++ b/build/debian-packages/glib-wheezy.diff
@@ -0,0 +1,26 @@
+diff -Nru glib2.0-2.38.2/debian/changelog glib2.0-2.38.2/debian/changelog
+--- glib2.0-2.38.2/debian/changelog	2014-02-15 21:47:00.000000000 +0900
++++ glib2.0-2.38.2/debian/changelog	2018-11-02 09:47:49.000000000 +0900
+@@ -1,3 +1,10 @@
++glib2.0 (2.38.2-5.deb7moz1) wheezy; urgency=medium
++
++  * Mozilla backport for Wheezy.
++  * debian/control: Remove :any from dependencies because it's not supported.
++
++ -- Mike Hommey <glandium@mozilla.com>  Fri, 02 Nov 2018 09:47:49 +0900
++
+ glib2.0 (2.38.2-5) unstable; urgency=medium
+ 
+   * Upload to unstable.
+diff -Nru glib2.0-2.38.2/debian/control glib2.0-2.38.2/debian/control
+--- glib2.0-2.38.2/debian/control	2014-02-15 21:50:26.000000000 +0900
++++ glib2.0-2.38.2/debian/control	2018-11-02 09:47:24.000000000 +0900
+@@ -24,7 +24,7 @@
+                dbus-x11,
+                shared-mime-info,
+                xterm,
+-               python:any (>= 2.6.6-3~),
++               python (>= 2.6.6-3~),
+                python-dbus,
+                python-gi,
+                libxml2-utils,
new file mode 100644
--- /dev/null
+++ b/build/debian-packages/gtk-wheezy.diff
@@ -0,0 +1,38 @@
+diff -Nru gtk+3.0-3.10.7/debian/changelog gtk+3.0-3.10.7/debian/changelog
+--- gtk+3.0-3.10.7/debian/changelog	2014-02-15 22:20:29.000000000 +0900
++++ gtk+3.0-3.10.7/debian/changelog	2018-11-02 12:04:23.000000000 +0900
+@@ -1,3 +1,11 @@
++gtk+3.0 (3.10.7-1.deb7moz1) wheezy; urgency=medium
++
++  * Mozilla backport for Wheezy.
++  * gtk/Makefile.am: Filter-out -fvisibility=hidden from the flags passed
++    to g-ir-scanner.
++
++ -- Mike Hommey <glandium@mozilla.com>  Fri, 02 Nov 2018 12:04:23 +0900
++
+ gtk+3.0 (3.10.7-1) unstable; urgency=low
+ 
+   * debian/libgtk-3-bin.install:
+diff -Nru gtk+3.0-3.10.7/debian/patches/deb7moz1 gtk+3.0-3.10.7/debian/patches/deb7moz1
+--- gtk+3.0-3.10.7/debian/patches/deb7moz1	1970-01-01 09:00:00.000000000 +0900
++++ gtk+3.0-3.10.7/debian/patches/deb7moz1	2018-11-02 12:04:23.000000000 +0900
+@@ -0,0 +1,11 @@
++--- gtk+3.0-3.10.7.orig/gtk/Makefile.am
+++++ gtk+3.0-3.10.7/gtk/Makefile.am
++@@ -1352,7 +1352,7 @@ Gtk_3_0_gir_INCLUDES += xlib-2.0
++ endif
++ Gtk_3_0_gir_SCANNERFLAGS += --c-include="gtk/gtkx.h"
++ Gtk_3_0_gir_CFLAGS = \
++-		$(AM_CPPFLAGS) \
+++		$(filter-out -fvisibility=hidden,$(AM_CPPFLAGS)) \
++ 		-DGTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
++ Gtk_3_0_gir_LIBS = libgtk-3.la $(top_builddir)/gdk/libgdk-3.la
++ Gtk_3_0_gir_FILES = $(introspection_files)
+diff -Nru gtk+3.0-3.10.7/debian/patches/series gtk+3.0-3.10.7/debian/patches/series
+--- gtk+3.0-3.10.7/debian/patches/series	2014-02-15 22:14:46.000000000 +0900
++++ gtk+3.0-3.10.7/debian/patches/series	2018-11-02 12:04:23.000000000 +0900
+@@ -12,3 +12,4 @@
+ 061_multiarch_module_fallback.patch
+ 071_fix-installation-of-HTML-images.patch
+ 080_disable-parallel-docs-build.patch
++deb7moz1
new file mode 100644
--- /dev/null
+++ b/build/debian-packages/python-defaults-wheezy.diff
@@ -0,0 +1,65 @@
+diff -Nru python-defaults-2.7.3/debian/changelog python-defaults-2.7.3/debian/changelog
+--- python-defaults-2.7.3/debian/changelog	2013-09-29 04:36:47.000000000 +0900
++++ python-defaults-2.7.3/debian/changelog	2018-11-06 18:06:20.000000000 +0900
+@@ -1,3 +1,10 @@
++python-defaults (2.7.3-4.deb7moz1) wheezy; urgency=medium
++
++  * Mozilla backport for Wheezy.
++  * debian/control: Set "Multi-Arch: foreign" on various packages.
++
++ -- Mike Hommey <glandium@debian.org>  Tue, 06 Nov 2018 18:06:20 +0900
++
+ python-defaults (2.7.3-4+deb7u1) stable; urgency=low
+ 
+   * Add symlink for /usr/bin/python2 (Closes: #723182)
+diff -Nru python-defaults-2.7.3/debian/control.in python-defaults-2.7.3/debian/control.in
+--- python-defaults-2.7.3/debian/control.in	2012-07-01 03:36:04.000000000 +0900
++++ python-defaults-2.7.3/debian/control.in	2018-11-06 18:06:20.000000000 +0900
+@@ -12,6 +12,7 @@
+ 
+ Package: python
+ Architecture: all
++Multi-Arch: foreign
+ Priority: standard
+ Depends: ${misc:Depends}, @PVER@ (>= @PREVVER@), python-minimal (= ${binary:Version})
+ Suggests: python-doc (= ${binary:Version}), python-tk (= ${binary:Version})
+@@ -29,6 +30,7 @@
+ 
+ Package: python-minimal
+ Architecture: all
++Multi-Arch: foreign
+ Priority: standard
+ Depends: ${misc:Depends}, @PVER@-minimal (>= @PREVVER@), dpkg (>= 1.13.20)
+ Recommends: python
+@@ -102,6 +104,7 @@
+ 
+ Package: python-dbg
+ Architecture: all
++Multi-Arch: foreign
+ Section: debug
+ Priority: extra
+ Depends: ${misc:Depends}, python (= ${binary:Version}), python@VER@-dbg (>= @PREVVER@)
+@@ -112,6 +115,7 @@
+ 
+ Package: python-all
+ Architecture: all
++Multi-Arch: foreign
+ Depends: ${misc:Depends}, python (= ${binary:Version}), python2.6 (>= 2.6.7-3), python2.7 (>= 2.7.2-3)
+ Description: package depending on all supported Python runtime versions
+  The package currently depends on python2.6 and python2.7, in the future,
+@@ -123,6 +127,7 @@
+ 
+ Package: python-all-dev
+ Architecture: all
++Multi-Arch: foreign
+ Depends: ${misc:Depends}, python (= ${binary:Version}), python-all (= ${binary:Version}), python-dev (= ${binary:Version}), python2.6-dev (>= 2.6.5-2), python2.7-dev (>= 2.7-7)
+ Description: package depending on all supported Python development packages
+  The package currently depends on python2.6-dev and python2.7-dev, in the
+@@ -134,6 +139,7 @@
+ 
+ Package: python-all-dbg
+ Architecture: all
++Multi-Arch: foreign
+ Section: debug
+ Priority: extra
+ Depends: ${misc:Depends}, python (= ${binary:Version}), python-all (= ${binary:Version}), python-dbg (= ${binary:Version}), python2.6-dbg (>= 2.6.5-2), python2.7-dbg (>= 2.7-7)
new file mode 100644
--- /dev/null
+++ b/build/debian-packages/xkeyboard-config-wheezy.diff
@@ -0,0 +1,25 @@
+diff -u xkeyboard-config-2.5.1/debian/control xkeyboard-config-2.5.1/debian/control
+--- xkeyboard-config-2.5.1/debian/control
++++ xkeyboard-config-2.5.1/debian/control
+@@ -23,6 +23,7 @@
+ Depends: ${misc:Depends}
+ Breaks: libx11-6 (<< 2:1.4.3)
+ Architecture: all
++Multi-Arch: foreign
+ Description: X Keyboard Extension (XKB) configuration data
+  This package contains configuration data used by the X Keyboard
+  Extension (XKB), which allows selection of keyboard layouts when
+diff -u xkeyboard-config-2.5.1/debian/changelog xkeyboard-config-2.5.1/debian/changelog
+--- xkeyboard-config-2.5.1/debian/changelog
++++ xkeyboard-config-2.5.1/debian/changelog
+@@ -1,3 +1,10 @@
++xkeyboard-config (2.5.1-3.deb7moz1) wheezy; urgency=medium
++
++  * Mozilla backport for Wheezy.
++  * Mark xkb-data as "Multi-Arch: foreign".
++
++ -- Mike Hommey <glandium@mozilla.com>  Tue, 06 Nov 2018 17:13:52 +0900
++
+ xkeyboard-config (2.5.1-3) unstable; urgency=low
+ 
+   * Cherry-picks from upstream:
--- a/devtools/client/debugger/new/build/copy-module.js
+++ b/devtools/client/debugger/new/build/copy-module.js
@@ -207,18 +207,18 @@ Babel.registerPlugin("transform-mc", tra
 function transform(filePath) {
   const doc = fs.readFileSync(filePath, "utf8");
   const out = Babel.transform(doc, {
     plugins: [
 			"transform-flow-strip-types",
 			"syntax-trailing-function-commas",
 			"transform-class-properties",
 			"transform-es2015-modules-commonjs",
-			"transform-object-rest-spread",
 			"transform-react-jsx",
+      			"syntax-object-rest-spread",
       ["transform-mc", { mappings, vendors: VENDORS, filePath }]
     ]
   });
 
   return out.code;
 }
 
 const deps = [
--- a/devtools/client/debugger/new/dist/vendors.js
+++ b/devtools/client/debugger/new/dist/vendors.js
@@ -2659,28 +2659,30 @@ class SplitBox extends Component {
    */
   onStartMove() {
     const splitBox = ReactDOM.findDOMNode(this);
     const doc = splitBox.ownerDocument;
     let defaultCursor = doc.documentElement.style.cursor;
     doc.documentElement.style.cursor = this.state.vert ? "ew-resize" : "ns-resize";
 
     splitBox.classList.add("dragging");
+    document.dispatchEvent(new CustomEvent("drag:start"));
 
     this.setState({
       defaultCursor: defaultCursor
     });
   }
 
   onStopMove() {
     const splitBox = ReactDOM.findDOMNode(this);
     const doc = splitBox.ownerDocument;
     doc.documentElement.style.cursor = this.state.defaultCursor;
 
     splitBox.classList.remove("dragging");
+    document.dispatchEvent(new CustomEvent("drag:end"));
 
     if (this.props.onResizeEnd) {
       this.props.onResizeEnd(this.state.vert ? this.state.width : this.state.height);
     }
   }
 
   /**
    * Adjust size of the controlled panel. Depending on the current
@@ -2848,16 +2850,22 @@ class Draggable extends Component {
     const doc = ReactDOM.findDOMNode(this).ownerDocument;
     doc.addEventListener("mousemove", this.onMove);
     doc.addEventListener("mouseup", this.onUp);
     this.props.onStart && this.props.onStart();
   }
 
   onMove(ev) {
     ev.preventDefault();
+
+    // When the target is outside of the document, its tagName is undefined
+    if (!ev.target.tagName) {
+      return
+    }
+
     // We pass the whole event because we don't know which properties
     // the callee needs.
     this.props.onMove(ev);
   }
 
   onUp(ev) {
     ev.preventDefault();
     const doc = ReactDOM.findDOMNode(this).ownerDocument;
@@ -9315,66 +9323,66 @@ function hashClear() {
 module.exports = hashClear;
 
 
 /***/ }),
 
 /***/ 792:
 /***/ (function(module, exports) {
 
-var g;
-
-// This works in non-strict mode
-g = (function() {
-	return this;
-})();
-
-try {
-	// This works if eval is allowed (see CSP)
-	g = g || Function("return this")() || (1,eval)("this");
-} catch(e) {
-	// This works if the window reference is available
-	if(typeof window === "object")
-		g = window;
-}
-
-// g can still be undefined, but nothing to do about it...
-// We return undefined, instead of nothing here, so it's
-// easier to handle this case. if(!global) { ...}
-
-module.exports = g;
+var g;
+
+// This works in non-strict mode
+g = (function() {
+	return this;
+})();
+
+try {
+	// This works if eval is allowed (see CSP)
+	g = g || Function("return this")() || (1,eval)("this");
+} catch(e) {
+	// This works if the window reference is available
+	if(typeof window === "object")
+		g = window;
+}
+
+// g can still be undefined, but nothing to do about it...
+// We return undefined, instead of nothing here, so it's
+// easier to handle this case. if(!global) { ...}
+
+module.exports = g;
 
 
 /***/ }),
 
 /***/ 793:
 /***/ (function(module, exports) {
 
-module.exports = function(module) {
-	if(!module.webpackPolyfill) {
-		module.deprecate = function() {};
-		module.paths = [];
-		// module.parent = undefined by default
-		if(!module.children) module.children = [];
-		Object.defineProperty(module, "loaded", {
-			enumerable: true,
-			get: function() {
-				return module.l;
-			}
-		});
-		Object.defineProperty(module, "id", {
-			enumerable: true,
-			get: function() {
-				return module.i;
-			}
-		});
-		module.webpackPolyfill = 1;
-	}
-	return module;
-};
+module.exports = function(module) {
+   if(!module.webpackPolyfill) {
+           module.deprecate = function() {};
+           module.paths = [];
+           // module.parent = undefined by default
+           if(!module.children) module.children = [];
+           Object.defineProperty(module, "loaded", {
+                   enumerable: true,
+                   get: function() {
+                           return module.l;
+                   }
+           });
+           Object.defineProperty(module, "id", {
+                   enumerable: true,
+                   get: function() {
+                           return module.i;
+                   }
+           });
+           module.webpackPolyfill = 1;
+   }
+   return module;
+};
 
 
 /***/ }),
 
 /***/ 8:
 /***/ (function(module, exports, __webpack_require__) {
 
 var freeGlobal = __webpack_require__(9);
--- a/devtools/client/debugger/new/panel.js
+++ b/devtools/client/debugger/new/panel.js
@@ -38,16 +38,20 @@ DebuggerPanel.prototype = {
       }
     });
 
     this._actions = actions;
     this._store = store;
     this._selectors = selectors;
     this._client = client;
     this.isReady = true;
+
+    this.panelWin.document.addEventListener("drag:start", this.toolbox.toggleDragging);
+    this.panelWin.document.addEventListener("drag:end", this.toolbox.toggleDragging);
+
     return this;
   },
 
   getVarsForTests() {
     return {
       store: this._store,
       selectors: this._selectors,
       actions: this._actions,
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -153,16 +153,17 @@ function Toolbox(target, selectedTool, h
   this._onToolSelected = this._onToolSelected.bind(this);
   this.updateToolboxButtonsVisibility = this.updateToolboxButtonsVisibility.bind(this);
   this.updateToolboxButtons = this.updateToolboxButtons.bind(this);
   this.selectTool = this.selectTool.bind(this);
   this._pingTelemetrySelectTool = this._pingTelemetrySelectTool.bind(this);
   this.toggleSplitConsole = this.toggleSplitConsole.bind(this);
   this.toggleOptions = this.toggleOptions.bind(this);
   this.togglePaintFlashing = this.togglePaintFlashing.bind(this);
+  this.toggleDragging = this.toggleDragging.bind(this);
   this.isPaintFlashing = false;
 
   this._target.on("close", this.destroy);
 
   if (!selectedTool) {
     selectedTool = Services.prefs.getCharPref(this._prefs.LAST_TOOL);
   }
   this._defaultToolId = selectedTool;
@@ -321,16 +322,20 @@ Toolbox.prototype = {
    * This is a shortcut for getPanel(currentToolId) because it is much more
    * likely that we're going to want to get the panel that we've just made
    * visible
    */
   getCurrentPanel: function() {
     return this._toolPanels.get(this.currentToolId);
   },
 
+  toggleDragging: function() {
+    this.doc.querySelector("window").classList.toggle("dragging");
+  },
+
   /**
    * Get/alter the target of a Toolbox so we're debugging something different.
    * See Target.jsm for more details.
    * TODO: Do we allow |toolbox.target = null;| ?
    */
   get target() {
     return this._target;
   },
--- a/devtools/client/themes/toolbox.css
+++ b/devtools/client/themes/toolbox.css
@@ -42,16 +42,20 @@
   display: grid;
   grid-template-columns: auto minmax(26px, 1fr) auto max-content;
   background: var(--theme-tab-toolbar-background);
   border-bottom: 1px solid var(--theme-splitter-color);
   box-sizing: border-box;
   min-height: 29px;
 }
 
+.dragging #toolbox-panel-iframe-webconsole {
+  pointer-events: none;
+}
+
 .toolbox-tabs-wrapper {
   position: relative;
   display: flex;
   flex: 1;
 }
 
 /* These classes use to stretch the tool tabs wrapper width if toolbox does'n
   have start buttons or end buttons element. */
--- a/gfx/src/FilterSupport.cpp
+++ b/gfx/src/FilterSupport.cpp
@@ -392,18 +392,18 @@ InterpolateFromIdentityMatrix(const floa
 
   aOutMatrix[10] = aAmount * aToMatrix[10];
   aOutMatrix[11] = aAmount * aToMatrix[11];
   aOutMatrix[12] = aAmount * aToMatrix[12] + oneMinusAmount;
 }
 
 // Create a 4x5 color matrix for the different ways to specify color matrices
 // in SVG.
-static nsresult
-ComputeColorMatrix(uint32_t aColorMatrixType, const nsTArray<float>& aValues,
+bool
+ComputeColorMatrix(const ColorMatrixAttributes& aMatrixAttributes,
                    float aOutMatrix[20])
 {
   // Luminance coefficients.
   static const float lumR = 0.2126f;
   static const float lumG = 0.7152f;
   static const float lumB = 0.0722f;
 
   static const float oneMinusLumR = 1 - lumR;
@@ -428,50 +428,50 @@ ComputeColorMatrix(uint32_t aColorMatrix
       0.272f, 0.534f, 0.131f, 0, 0,
       0,      0,      0,      1, 0 };
 
   // Hue rotate specific coefficients.
   static const float hueRotateR = 0.143f;
   static const float hueRotateG = 0.140f;
   static const float hueRotateB = 0.283f;
 
-  switch (aColorMatrixType) {
+  switch (aMatrixAttributes.mType) {
 
-    case SVG_FECOLORMATRIX_TYPE_MATRIX:
-    {
-      if (aValues.Length() != 20) {
-        return NS_ERROR_FAILURE;
+    case SVG_FECOLORMATRIX_TYPE_MATRIX: {
+      if (aMatrixAttributes.mValues.Length() != 20) {
+        return false;
       }
 
-      PodCopy(aOutMatrix, aValues.Elements(), 20);
+      PodCopy(aOutMatrix, aMatrixAttributes.mValues.Elements(), 20);
       break;
     }
 
-    case SVG_FECOLORMATRIX_TYPE_SATURATE:
-    {
-      if (aValues.Length() != 1)
-        return NS_ERROR_FAILURE;
+    case SVG_FECOLORMATRIX_TYPE_SATURATE: {
+      if (aMatrixAttributes.mValues.Length() != 1) {
+        return false;
+      }
 
-      float s = aValues[0];
+      float s = aMatrixAttributes.mValues[0];
 
-      if (s < 0)
-        return NS_ERROR_FAILURE;
+      if (s < 0) {
+        return false;
+      }
 
       InterpolateFromIdentityMatrix(saturateMatrix, 1 - s, aOutMatrix);
       break;
     }
 
-    case SVG_FECOLORMATRIX_TYPE_HUE_ROTATE:
-    {
-      if (aValues.Length() != 1)
-        return NS_ERROR_FAILURE;
+    case SVG_FECOLORMATRIX_TYPE_HUE_ROTATE: {
+      if (aMatrixAttributes.mValues.Length() != 1) {
+        return false;
+      }
 
       PodCopy(aOutMatrix, identityMatrix, 20);
 
-      float hueRotateValue = aValues[0];
+      float hueRotateValue = aMatrixAttributes.mValues[0];
 
       float c = static_cast<float>(cos(hueRotateValue * M_PI / 180));
       float s = static_cast<float>(sin(hueRotateValue * M_PI / 180));
 
       aOutMatrix[0] = lumR + oneMinusLumR * c - lumR * s;
       aOutMatrix[1] = lumG - lumG * c - lumG * s;
       aOutMatrix[2] = lumB - lumB * c + oneMinusLumB * s;
 
@@ -481,42 +481,43 @@ ComputeColorMatrix(uint32_t aColorMatrix
 
       aOutMatrix[10] = lumR - lumR * c - oneMinusLumR * s;
       aOutMatrix[11] = lumG - lumG * c + lumG * s;
       aOutMatrix[12] = lumB + oneMinusLumB * c + lumB * s;
 
       break;
     }
 
-    case SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA:
-    {
+    case SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA: {
       PodCopy(aOutMatrix, luminanceToAlphaMatrix, 20);
       break;
     }
 
-    case SVG_FECOLORMATRIX_TYPE_SEPIA:
-    {
-      if (aValues.Length() != 1)
-        return NS_ERROR_FAILURE;
+    case SVG_FECOLORMATRIX_TYPE_SEPIA: {
+      if (aMatrixAttributes.mValues.Length() != 1){
+        return false;
+      }
 
-      float amount = aValues[0];
+      float amount = aMatrixAttributes.mValues[0];
 
-      if (amount < 0 || amount > 1)
-        return NS_ERROR_FAILURE;
+      if (amount < 0 || amount > 1){
+        return false;
+      }
 
       InterpolateFromIdentityMatrix(sepiaMatrix, amount, aOutMatrix);
       break;
     }
 
-    default:
-      return NS_ERROR_FAILURE;
+    default: {
+      return false;
+    }
 
   }
 
-  return NS_OK;
+  return !ArrayEqual(aOutMatrix, identityMatrix, 20);
 }
 
 static void
 DisableAllTransfers(FilterNode* aTransferFilterNode)
 {
   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_R, true);
   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_G, true);
   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_B, true);
@@ -774,30 +775,32 @@ FilterNodeFromPrimitiveDescription(const
         // The correct input order for both software and D2D filters is flipped
         // from our source order, so flip here.
         filter->SetInput(IN_BLEND_IN, mSources[1]);
         filter->SetInput(IN_BLEND_IN2, mSources[0]);
       }
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(const ColorMatrixAttributes& aColorMatrix)
+    already_AddRefed<FilterNode> match(const ColorMatrixAttributes& aMatrixAttributes)
     {
-      uint32_t type = aColorMatrix.mType;
       float colorMatrix[20];
-      if (NS_FAILED(ComputeColorMatrix(type, aColorMatrix.mValues, colorMatrix)) ||
-          ArrayEqual(colorMatrix, identityMatrix)) {
+      if (!ComputeColorMatrix(aMatrixAttributes, colorMatrix)) {
         RefPtr<FilterNode> filter(mSources[0]);
         return filter.forget();
       }
-      Matrix5x4 matrix(colorMatrix[0], colorMatrix[5], colorMatrix[10],  colorMatrix[15],
-                       colorMatrix[1], colorMatrix[6], colorMatrix[11],  colorMatrix[16],
-                       colorMatrix[2], colorMatrix[7], colorMatrix[12],  colorMatrix[17],
-                       colorMatrix[3], colorMatrix[8], colorMatrix[13],  colorMatrix[18],
-                       colorMatrix[4], colorMatrix[9], colorMatrix[14],  colorMatrix[19]);
+
+      Matrix5x4 matrix(
+        colorMatrix[0], colorMatrix[5], colorMatrix[10],  colorMatrix[15],
+        colorMatrix[1], colorMatrix[6], colorMatrix[11],  colorMatrix[16],
+        colorMatrix[2], colorMatrix[7], colorMatrix[12],  colorMatrix[17],
+        colorMatrix[3], colorMatrix[8], colorMatrix[13],  colorMatrix[18],
+        colorMatrix[4], colorMatrix[9], colorMatrix[14],  colorMatrix[19]
+      );
+
       RefPtr<FilterNode> filter = mDT->CreateFilter(FilterType::COLOR_MATRIX);
       if (!filter) {
         return nullptr;
       }
       filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, matrix);
       filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE, (uint32_t)ALPHA_MODE_STRAIGHT);
       filter->SetInput(IN_COLOR_MATRIX_IN, mSources[0]);
       return filter.forget();
--- a/gfx/src/FilterSupport.h
+++ b/gfx/src/FilterSupport.h
@@ -605,12 +605,23 @@ public:
    * Computes the size of a single FilterPrimitiveDescription's output given a
    * set of input extents.
    */
   static nsIntRegion
   PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription,
                                 const nsTArray<nsIntRegion>& aInputExtents);
 };
 
+/**
+ * Create a 4x5 color matrix for the different ways to specify color matrices
+ * in SVG.
+ *
+ * Return false if the input is invalid or if the resulting matrix is the
+ * identity.
+ */
+bool
+ComputeColorMatrix(const ColorMatrixAttributes& aMatrixAttributes,
+                   float aOutMatrix[20]);
+
 } // namespace gfx
 } // namespace mozilla
 
 #endif // __FilterSupport_h
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -430,16 +430,18 @@ pub enum WrFilterOpType {
   Grayscale = 3,
   HueRotate = 4,
   Invert = 5,
   Opacity = 6,
   Saturate = 7,
   Sepia = 8,
   DropShadow = 9,
   ColorMatrix = 10,
+  SrgbToLinear = 11,
+  LinearToSrgb = 12,
 }
 
 #[repr(C)]
 #[derive(Copy, Clone)]
 pub struct WrFilterOp {
     filter_type: WrFilterOpType,
     argument: c_float, // holds radius for DropShadow; value for other filters
     offset: LayoutVector2D, // only used for DropShadow
@@ -1827,16 +1829,18 @@ pub extern "C" fn wr_dp_push_stacking_co
             WrFilterOpType::Invert => FilterOp::Invert(c_filter.argument),
             WrFilterOpType::Opacity => FilterOp::Opacity(PropertyBinding::Value(c_filter.argument), c_filter.argument),
             WrFilterOpType::Saturate => FilterOp::Saturate(c_filter.argument),
             WrFilterOpType::Sepia => FilterOp::Sepia(c_filter.argument),
             WrFilterOpType::DropShadow => FilterOp::DropShadow(c_filter.offset,
                                                                c_filter.argument,
                                                                c_filter.color),
             WrFilterOpType::ColorMatrix => FilterOp::ColorMatrix(c_filter.matrix),
+            WrFilterOpType::SrgbToLinear => FilterOp::SrgbToLinear,
+            WrFilterOpType::LinearToSrgb => FilterOp::LinearToSrgb,
         }
     }).collect();
 
     let clip_node_id_ref = unsafe { clip_node_id.as_ref() };
     let clip_node_id = match clip_node_id_ref {
         Some(clip_node_id) => Some(unpack_clip_id(*clip_node_id, state.pipeline_id)),
         None => None,
     };
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -248,16 +248,18 @@ enum class WrFilterOpType : uint32_t {
   Grayscale = 3,
   HueRotate = 4,
   Invert = 5,
   Opacity = 6,
   Saturate = 7,
   Sepia = 8,
   DropShadow = 9,
   ColorMatrix = 10,
+  SrgbToLinear = 11,
+  LinearToSrgb = 12,
 
   Sentinel /* this must be last for serialization purposes. */
 };
 
 enum class YuvColorSpace : uint32_t {
   Rec601 = 0,
   Rec709 = 1,
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/baseline-builtin-abi.js
@@ -0,0 +1,20 @@
+// Bug 1488515 - ABI issues on Android because both the baseline compiler and
+// the builtin thunks converted between hardFP and softFP.
+
+var prog = wasmEvalText(
+    `(module
+       (func $f64div (export "test") (param $a f64) (param $b f64) (result f64)
+         (local $dummy0 i32)
+         (local $dummy1 i32)
+         (local $dummy2 i32)
+         (local $dummy3 i32)
+         (local $dummy4 i32)
+         (local $x f64)
+         (local $y f64)
+         (local $z f64)
+         (set_local $x (get_local $a))
+         (set_local $y (get_local $b))
+         (set_local $z (f64.floor (f64.div (get_local $x) (get_local $y))))
+         (get_local $z)))`);
+
+assertEq(prog.exports.test(16096, 32), 503);
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -2286,17 +2286,17 @@ RangeAnalysis::analyzeLoopPhi(LoopIterat
 
     MOZ_ASSERT(phi->numOperands() == 2);
 
     MDefinition* initial = phi->getLoopPredecessorOperand();
     if (initial->block()->isMarked()) {
         return;
     }
 
-    SimpleLinearSum modified = ExtractLinearSum(phi->getLoopBackedgeOperand());
+    SimpleLinearSum modified = ExtractLinearSum(phi->getLoopBackedgeOperand(), MathSpace::Infinite);
 
     if (modified.term != phi || modified.constant == 0) {
         return;
     }
 
     if (!phi->range()) {
         phi->setRange(new(alloc()) Range(phi));
     }
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -162,32 +162,38 @@ using IsKnownNotZero = bool;
 using IsUnsigned = bool;
 using NeedsBoundsCheck = bool;
 using PopStack = bool;
 using WantResult = bool;
 using ZeroOnOverflow = bool;
 
 class BaseStackFrame;
 
+// Two flags, useABI and interModule, control how calls are made.
+//
 // UseABI::Wasm implies that the Tls/Heap/Global registers are nonvolatile,
 // except when InterModule::True is also set, when they are volatile.
 //
+// UseABI::Builtin implies that the Tls/Heap/Global registers are volatile.
+// In this case, we require InterModule::False.  The calling convention
+// is otherwise like UseABI::Wasm.
+//
 // UseABI::System implies that the Tls/Heap/Global registers are volatile.
 // Additionally, the parameter passing mechanism may be slightly different from
 // the UseABI::Wasm convention.
 //
 // When the Tls/Heap/Global registers are not volatile, the baseline compiler
 // will restore the Tls register from its save slot before the call, since the
 // baseline compiler uses the Tls register for other things.
 //
 // When those registers are volatile, the baseline compiler will reload them
 // after the call (it will restore the Tls register from the save slot and load
 // the other two from the Tls data).
 
-enum class UseABI { Wasm, System };
+enum class UseABI { Wasm, Builtin, System };
 enum class InterModule { False = false, True = true };
 
 #if defined(JS_CODEGEN_NONE)
 # define RABALDR_SCRATCH_I32
 # define RABALDR_SCRATCH_F32
 # define RABALDR_SCRATCH_F64
 
 static const Register RabaldrScratchI32 = Register::Invalid();
@@ -3637,33 +3643,34 @@ class BaseCompiler final : public BaseCo
         bool hardFP;
 #endif
         size_t frameAlignAdjustment;
         size_t stackArgAreaSize;
     };
 
     void beginCall(FunctionCall& call, UseABI useABI, InterModule interModule)
     {
+        MOZ_ASSERT_IF(useABI == UseABI::Builtin, interModule == InterModule::False);
+
         call.isInterModule = interModule == InterModule::True;
         call.usesSystemAbi = useABI == UseABI::System;
 
         if (call.usesSystemAbi) {
             // Call-outs need to use the appropriate system ABI.
 #if defined(JS_CODEGEN_ARM)
-# if defined(JS_SIMULATOR_ARM)
             call.hardFP = UseHardFpABI();
-# elif defined(JS_CODEGEN_ARM_HARDFP)
-            call.hardFP = true;
-# else
-            call.hardFP = false;
-# endif
             call.abi.setUseHardFp(call.hardFP);
 #elif defined(JS_CODEGEN_MIPS32)
             call.abi.enforceO32ABI();
 #endif
+        } else {
+#if defined(JS_CODEGEN_ARM)
+            MOZ_ASSERT(call.hardFP,
+                       "All private ABIs pass FP arguments in registers");
+#endif
         }
 
         // Use masm.framePushed() because the value we want here does not depend
         // on the height of the frame's stack area, but the actual size of the
         // allocated frame.
         call.frameAlignAdjustment = ComputeByteAlignment(masm.framePushed() + sizeof(Frame),
                                                          JitStackAlignment);
     }
@@ -8256,17 +8263,17 @@ BaseCompiler::emitUnaryMathBuiltinCall(S
     sync();
 
     ValTypeVector& signature = operandType == ValType::F32 ? SigF_ : SigD_;
     ExprType retType = operandType == ValType::F32 ? ExprType::F32 : ExprType::F64;
     uint32_t numArgs = signature.length();
     size_t stackSpace = stackConsumed(numArgs);
 
     FunctionCall baselineCall(lineOrBytecode);
-    beginCall(baselineCall, UseABI::System, InterModule::False);
+    beginCall(baselineCall, UseABI::Builtin, InterModule::False);
 
     if (!emitCallArgs(signature, &baselineCall)) {
         return false;
     }
 
     builtinCall(callee, baselineCall);
 
     endCall(baselineCall, stackSpace);
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -10367,26 +10367,20 @@ nsDisplayFilters::PaintAsLayer(nsDisplay
 static float
 ClampStdDeviation(float aStdDeviation)
 {
   // Cap software blur radius for performance reasons.
   return std::min(std::max(0.0f, aStdDeviation), 100.0f);
 }
 
 bool
-nsDisplayFilters::CreateWebRenderCommands(
-  mozilla::wr::DisplayListBuilder& aBuilder,
-  mozilla::wr::IpcResourceUpdateQueue& aResources,
-  const StackingContextHelper& aSc,
-  mozilla::layers::WebRenderLayerManager* aManager,
-  nsDisplayListBuilder* aDisplayListBuilder)
-{
-  // All CSS filters are supported by WebRender. SVG filters are not supported,
-  // those use NS_STYLE_FILTER_URL.
-  nsTArray<mozilla::wr::WrFilterOp> wrFilters;
+nsDisplayFilters::CreateWebRenderCSSFilters(nsTArray<mozilla::wr::WrFilterOp>& wrFilters)
+{
+  // All CSS filters are supported by WebRender. SVG filters are not fully supported,
+  // those use NS_STYLE_FILTER_URL and are handled separately.
   const nsTArray<nsStyleFilter>& filters = mFrame->StyleEffects()->mFilters;
   for (const nsStyleFilter& filter : filters) {
     switch (filter.GetType()) {
       case NS_STYLE_FILTER_BRIGHTNESS:
       case NS_STYLE_FILTER_CONTRAST:
       case NS_STYLE_FILTER_GRAYSCALE:
       case NS_STYLE_FILTER_INVERT:
       case NS_STYLE_FILTER_OPACITY:
@@ -10449,26 +10443,48 @@ nsDisplayFilters::CreateWebRenderCommand
         wrFilters.AppendElement(filterOp);
         break;
       }
       default:
         return false;
     }
   }
 
+  return true;
+}
+
+bool
+nsDisplayFilters::CreateWebRenderCommands(
+  mozilla::wr::DisplayListBuilder& aBuilder,
+  mozilla::wr::IpcResourceUpdateQueue& aResources,
+  const StackingContextHelper& aSc,
+  mozilla::layers::WebRenderLayerManager* aManager,
+  nsDisplayListBuilder* aDisplayListBuilder)
+{
   bool snap;
   float auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   nsRect displayBounds = GetBounds(aDisplayListBuilder, &snap);
-  auto bounds = LayoutDeviceRect::FromAppUnits(displayBounds, auPerDevPixel);
-  // NOTE(emilio): this clip is going to be intersected with the clip that's
-  // currently on the clip stack for this item.
-  //
-  // FIXME(emilio, bug 1486557): clipping to "bounds" isn't really necessary.
+  auto postFilterBounds = LayoutDeviceIntRect::Round(
+    LayoutDeviceRect::FromAppUnits(displayBounds, auPerDevPixel)
+  );
+  auto preFilterBounds = LayoutDeviceIntRect::Round(
+    LayoutDeviceRect::FromAppUnits(mBounds, auPerDevPixel)
+  );
+
+  nsTArray<mozilla::wr::WrFilterOp> wrFilters;
+  if (!CreateWebRenderCSSFilters(wrFilters) &&
+      !nsSVGIntegrationUtils::BuildWebRenderFilters(mFrame,
+                                                    preFilterBounds,
+                                                    wrFilters,
+                                                    postFilterBounds)) {
+    return false;
+  }
+
   wr::WrClipId clipId =
-    aBuilder.DefineClip(Nothing(), wr::ToRoundedLayoutRect(bounds));
+    aBuilder.DefineClip(Nothing(), wr::ToLayoutRect(postFilterBounds));
 
   float opacity = mFrame->StyleEffects()->mOpacity;
   StackingContextHelper sc(aSc,
                            GetActiveScrolledRoot(),
                            aBuilder,
                            wrFilters,
                            LayoutDeviceRect(),
                            nullptr,
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -7008,16 +7008,18 @@ public:
 
   bool CreateWebRenderCommands(
     mozilla::wr::DisplayListBuilder& aBuilder,
     mozilla::wr::IpcResourceUpdateQueue& aResources,
     const StackingContextHelper& aSc,
     mozilla::layers::WebRenderLayerManager* aManager,
     nsDisplayListBuilder* aDisplayListBuilder) override;
 
+  bool CreateWebRenderCSSFilters(nsTArray<mozilla::wr::WrFilterOp>& wrFilters);
+
 private:
   // relative to mFrame
   nsRect mEffectsBounds;
 };
 
 /* A display item that applies a transformation to all of its descendant
  * elements.  This wrapper should only be used if there is a transform applied
  * to the root element.
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1853,19 +1853,19 @@ pref(layout.css.moz-document.content.ena
 == 1043537-1.html 1043537-1-ref.html
 == 1044198-1.html 1044198-1-ref.html
 == 1049499-1.html 1049499-1-ref.html
 == 1050493-1.html 1050493-1-ref.html
 == 1050788-1.html about:blank
 == 1053035-1-flex.html 1053035-1-ref.html
 == 1053035-1-grid.html 1053035-1-ref.html
 == 1059167-1.html 1059167-1-ref.html
-== 1059498-1.html 1059498-1-ref.html
-== 1059498-2.html 1059498-1-ref.html
-== 1059498-3.html 1059498-1-ref.html
+fails-if(webrender) == 1059498-1.html 1059498-1-ref.html # WebRender: see bug 1504290
+fails-if(webrender) == 1059498-2.html 1059498-1-ref.html # WebRender: see bug 1504290
+fails-if(webrender) == 1059498-3.html 1059498-1-ref.html # WebRender: see bug 1499113
 == 1062108-1.html 1062108-1-ref.html
 == 1062792-1.html 1062792-1-ref.html
 == 1062963-floatmanager-reflow.html 1062963-floatmanager-reflow-ref.html
 test-pref(dom.webcomponents.shadowdom.enabled,true) == 1066554-1.html 1066554-1-ref.html
 == 1069716-1.html 1069716-1-ref.html
 == 1078262-1.html about:blank
 test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html
 fuzzy-if(webrender,64-64,485-486) == 1081185-1.html 1081185-1-ref.html
--- a/layout/reftests/css-blending/reftest.list
+++ b/layout/reftests/css-blending/reftest.list
@@ -1,13 +1,13 @@
 pref(layout.css.mix-blend-mode.enabled,true) == blend-canvas.html blend-canvas-ref.html
 pref(layout.css.mix-blend-mode.enabled,true) == blend-constant-background-color.html blend-constant-background-color-ref.html
 pref(layout.css.mix-blend-mode.enabled,true) fuzzy-if(webrender,1-1,1411-7888) == blend-gradient-background-color.html blend-gradient-background-color-ref.html
 pref(layout.css.mix-blend-mode.enabled,true) == blend-image.html blend-image-ref.html
-pref(layout.css.mix-blend-mode.enabled,true) fuzzy-if(webrender&&winWidget,27-27,2-2) == blend-difference-stacking.html blend-difference-stacking-ref.html
+pref(layout.css.mix-blend-mode.enabled,true) == blend-difference-stacking.html blend-difference-stacking-ref.html
 
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-10000) fuzzy-if(skiaContent,0-1,0-30000) pref(layout.css.background-blend-mode.enabled,true) == background-blending-alpha.html background-blending-alpha-ref.html
 pref(layout.css.background-blend-mode.enabled,true) fuzzy-if(webrender,1-1,1411-7888) == background-blending-gradient-color.html background-blending-gradient-color-ref.html
 fuzzy-if(azureSkiaGL,0-3,0-7597) fuzzy-if(cocoaWidget,0-3,0-7597) fuzzy-if(d2d,0-1,0-3800) fuzzy-if(d3d11,0-1,0-4200) fuzzy-if(skiaContent,0-2,0-9450) fuzzy-if(webrender,1-1,3938-23663) pref(layout.css.background-blend-mode.enabled,true) == background-blending-gradient-gradient.html background-blending-gradient-gradient-ref.html
 fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-1,1312-7887) pref(layout.css.background-blend-mode.enabled,true) == background-blending-gradient-image.html background-blending-gradient-color-ref.html
 fuzzy-if(azureSkia||d2d||gtkWidget,0-1,0-10000) pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-jpg.html background-blending-image-color-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-png.html background-blending-image-color-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-svg.html background-blending-image-color-ref.html
--- a/layout/reftests/svg/filters/css-filter-chains/reftest.list
+++ b/layout/reftests/svg/filters/css-filter-chains/reftest.list
@@ -1,7 +1,7 @@
 # These tests verify that CSS filter chains behave properly.
 # e.g. filter: blur(3px) grayscale(0.5) invert(0.2);
 
 # Some platforms render this complex filter chain a little differently, and that's ok.
-fuzzy(0-5,0-13638) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&layersGPUAccelerated,0-35,0-13638) fuzzy-if(webrender,5-6,17922-18853) == long-chain.html long-chain-ref.html # Win10: Bug 1258241
+fuzzy(0-5,0-13638) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&layersGPUAccelerated,0-35,0-13638) fuzzy-if(webrender,4-6,12004-18853) == long-chain.html long-chain-ref.html # Win10: Bug 1258241
 == moz-element.html moz-element-ref.html
-fuzzy-if(webrender,15-15,7678-8262) == same-filter.html same-filter-ref.html
+== same-filter.html same-filter-ref.html
--- a/layout/reftests/svg/filters/css-filters/reftest.list
+++ b/layout/reftests/svg/filters/css-filters/reftest.list
@@ -1,37 +1,37 @@
 # These tests verify that CSS filters behave properly.
 # e.g. filter: blur(3px)
 
-fuzzy-if(webrender,9-9,4780-5120) == blur.html blur-ref.html
+== blur.html blur-ref.html
 == blur.svg blur-ref.svg
 == blur-calc.html blur-calc-ref.html
 == blur-calc-negative.html blur-calc-negative-ref.html
 fuzzy-if(cocoaWidget&&webrender,0-1,0-1) skip-if(d2d) == blur-cap-large-radius-on-software.html blur-cap-large-radius-on-software-ref.html
-fuzzy-if(webrender,9-9,4780-5120) == blur-em-radius.html blur-em-radius-ref.html
+== blur-em-radius.html blur-em-radius-ref.html
 == blur-invalid-radius.html blur-invalid-radius-ref.html
-fuzzy-if(webrender,9-9,4780-5120) == blur-rem-radius.html blur-rem-radius-ref.html
+== blur-rem-radius.html blur-rem-radius-ref.html
 == blur-zero-radius.html blur-zero-radius-ref.html
-fuzzy-if(webrender,5-7,19040-22652) == blur-zoomed-page.html blur-zoomed-page-ref.html
+== blur-zoomed-page.html blur-zoomed-page-ref.html
 == brightness.html brightness-ref.html
 == brightness-darken.html brightness-darken-ref.html
 == brightness-extreme.html brightness-extreme-ref.html
 == brightness-one.html brightness-one-ref.html
 == brightness-percent.html brightness-percent-ref.html
 == brightness-zero.html brightness-zero-ref.html
 == containing-block-1.html containing-block-1-ref.html
 == contrast.html contrast-ref.html
 == contrast-extreme.html contrast-extreme-ref.html
 == contrast-one.html contrast-one-ref.html
 == contrast-percent.html contrast-percent-ref.html
 == contrast-reduce.html contrast-reduce-ref.html
 == contrast-zero.html contrast-zero-ref.html
-fuzzy-if(webrender,9-9,2625-3002) == drop-shadow.html drop-shadow-ref.html
-fuzzy-if(webrender,9-9,2625-3002) == drop-shadow-default-color.html drop-shadow-default-color-ref.html
-fuzzy-if(webrender,9-9,2625-3002) == drop-shadow-negative-offset.html drop-shadow-negative-offset-ref.html
+== drop-shadow.html drop-shadow-ref.html
+== drop-shadow-default-color.html drop-shadow-default-color-ref.html
+== drop-shadow-negative-offset.html drop-shadow-negative-offset-ref.html
 == filter-on-huge-bbox.html pass.svg
 == filter-on-outer-svg.html pass.svg
 fuzzy-if(webrender,0-1,0-10000) fuzzy-if(d2d,0-1,0-10000) == grayscale.html grayscale-ref.html
 fuzzy-if(webrender,0-1,0-10000) fuzzy-if(d2d,0-1,0-10000) == grayscale-one.html grayscale-one-ref.html
 fuzzy-if(webrender,0-1,0-10000) fuzzy-if(d2d,0-1,0-10000) == grayscale-over-one.html grayscale-over-one-ref.html
 fuzzy-if(webrender,0-1,0-10000) fuzzy-if(d2d,0-1,0-10000) == grayscale-percent.html grayscale-percent-ref.html
 fuzzy-if(webrender,0-1,0-10000) == grayscale-zero.html grayscale-zero-ref.html
 == hue-rotate.html hue-rotate-ref.html
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -21,16 +21,17 @@
 #include "nsSVGDisplayableFrame.h"
 #include "nsCSSFilterInstance.h"
 #include "nsSVGFilterInstance.h"
 #include "nsSVGFilterPaintCallback.h"
 #include "nsSVGUtils.h"
 #include "SVGContentUtils.h"
 #include "FilterSupport.h"
 #include "gfx2DGlue.h"
+#include "mozilla/Unused.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::image;
 
 FilterDescription
 nsFilterInstance::GetFilterDescription(nsIContent* aFilteredElement,
@@ -97,16 +98,219 @@ nsFilterInstance::PaintFilteredFrame(nsI
                             *metrics, filterChain, /* InputIsTainted */ true,
                             aPaintCallback, scaleMatrixInDevUnits,
                             aDirtyArea, nullptr, nullptr, nullptr);
   if (instance.IsInitialized()) {
     instance.Render(aCtx, aImgParams, aOpacity);
   }
 }
 
+bool
+nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
+                                        const LayoutDeviceIntRect& aPreFilterBounds,
+                                        nsTArray<wr::WrFilterOp>& aWrFilters,
+                                        LayoutDeviceIntRect& aPostFilterBounds)
+{
+  aWrFilters.Clear();
+
+  auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
+  UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
+
+  // TODO: simply using an identity matrix here, was pulling the scale from a
+  // gfx context for the non-wr path.
+  gfxMatrix scaleMatrix;
+  gfxMatrix scaleMatrixInDevUnits =
+    scaleMatrix * nsSVGUtils::GetCSSPxToDevPxMatrix(aFilteredFrame);
+
+  // Hardcode inputIsTainted to true because we don't want JS to be able to
+  // read the rendered contents of aFilteredFrame.
+  bool inputIsTainted = true;
+  nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
+                            *metrics, filterChain, inputIsTainted,
+                            nullptr, scaleMatrixInDevUnits,
+                            nullptr, nullptr, nullptr, nullptr);
+
+  if (!instance.IsInitialized()) {
+    return false;
+  }
+
+  Maybe<LayoutDeviceIntRect> finalClip;
+  bool srgb = true;
+  // We currently apply the clip on the stacking context after applying filters,
+  // but primitive subregions imply clipping after each filter and not just the
+  // end of the chain. For some types of filter it doesn't matter, but for those
+  // which sample outside of the location of the destination pixel like blurs,
+  // only clipping after could produce incorrect results, so we bail out in this
+  // case.
+  // We can lift this restriction once we have added support for primitive
+  // subregions to WebRender's filters.
+
+  // During the loop this tracks whether any of the previous filters in the chain
+  // affected by the primitive subregion.
+  bool chainIsAffectedByPrimSubregion = false;
+  // During the loop this tracks whether the current filter is affected by the
+  // primitive subregion.
+  bool filterIsAffectedByPrimSubregion = false;
+
+  for (const auto& primitive : instance.mFilterDescription.mPrimitives) {
+    chainIsAffectedByPrimSubregion |= filterIsAffectedByPrimSubregion;
+    filterIsAffectedByPrimSubregion = false;
+
+    bool primIsSrgb = primitive.OutputColorSpace() == gfx::ColorSpace::SRGB;
+    if (srgb && !primIsSrgb) {
+      wr::WrFilterOp filterOp = { wr::WrFilterOpType::SrgbToLinear };
+      aWrFilters.AppendElement(filterOp);
+      srgb = false;
+    } else if (!srgb && primIsSrgb) {
+      wr::WrFilterOp filterOp = { wr::WrFilterOpType::LinearToSrgb };
+      aWrFilters.AppendElement(filterOp);
+      srgb = true;
+    }
+
+    const PrimitiveAttributes& attr = primitive.Attributes();
+    auto subregion = LayoutDeviceIntRect::FromUnknownRect(
+      primitive.PrimitiveSubregion() + aPreFilterBounds.TopLeft().ToUnknownPoint()
+    );
+
+    if (!subregion.Contains(aPreFilterBounds)) {
+      if (!aPostFilterBounds.Contains(subregion)) {
+        filterIsAffectedByPrimSubregion = true;
+      }
+
+      subregion = subregion.Intersect(aPostFilterBounds);
+
+      if (finalClip.isNothing()) {
+        finalClip = Some(subregion);
+      } else if (!subregion.IsEqualEdges(finalClip.value())) {
+        // We don't currently support rendering a chain of filters with different
+        // primitive subregions in WebRender so bail out in that situation.
+        return false;
+      }
+    }
+
+    bool filterIsNoop = false;
+
+    if (attr.is<OpacityAttributes>()) {
+      float opacity = attr.as<OpacityAttributes>().mOpacity;
+      wr::WrFilterOp filterOp = { wr::WrFilterOpType::Opacity, opacity };
+      aWrFilters.AppendElement(filterOp);
+    } else if (attr.is<ColorMatrixAttributes>()) {
+      const ColorMatrixAttributes& attributes = attr.as<ColorMatrixAttributes>();
+
+      float transposed[20];
+      if (!gfx::ComputeColorMatrix(attributes, transposed)) {
+        filterIsNoop = true;
+        continue;
+      }
+
+      auto almostEq = [](float a, float b) -> bool { return fabs(a - b) < 0.00001; };
+
+      if (!almostEq(transposed[15], 0.0) ||
+          !almostEq(transposed[16], 0.0) ||
+          !almostEq(transposed[17], 0.0) ||
+          !almostEq(transposed[18], 1.0) ||
+          !almostEq(transposed[3], 0.0) ||
+          !almostEq(transposed[8], 0.0) ||
+          !almostEq(transposed[13], 0.0)) {
+        // WebRender currently pretends to take the full 4x5 matrix but discards
+        // the components related to alpha. So bail out in this case until
+        // it is fixed.
+        return false;
+      }
+
+      float matrix[20] = {
+        transposed[0], transposed[5], transposed[10], transposed[15],
+        transposed[1], transposed[6], transposed[11], transposed[16],
+        transposed[2], transposed[7], transposed[12], transposed[17],
+        transposed[3], transposed[8], transposed[13], transposed[18],
+        transposed[4], transposed[9], transposed[14], transposed[19]
+      };
+
+      wr::WrFilterOp filterOp = { wr::WrFilterOpType::ColorMatrix };
+      PodCopy(filterOp.matrix, matrix, 20);
+      aWrFilters.AppendElement(filterOp);
+    } else if (attr.is<GaussianBlurAttributes>()) {
+      if (chainIsAffectedByPrimSubregion) {
+        // There's a clip that needs to apply before the blur filter, but
+        // WebRender only lets us apply the clip at the end of the filter
+        // chain. Clipping after a blur is not equivalent to clipping before
+        // a blur, so bail out.
+        return false;
+      }
+
+      const GaussianBlurAttributes& blur = attr.as<GaussianBlurAttributes>();
+
+      const Size& stdDev = blur.mStdDeviation;
+      if (stdDev.width != stdDev.height) {
+        return false;
+      }
+
+      float radius = stdDev.width;
+      if (radius != 0.0) {
+        wr::WrFilterOp filterOp = { wr::WrFilterOpType::Blur, radius };
+        aWrFilters.AppendElement(filterOp);
+      } else {
+        filterIsNoop = true;
+      }
+    } else if (attr.is<DropShadowAttributes>()) {
+      if (chainIsAffectedByPrimSubregion) {
+        // We have to bail out for the same reason we would with a blur filter.
+        return false;
+      }
+
+      const DropShadowAttributes& shadow = attr.as<DropShadowAttributes>();
+
+      const Size& stdDev = shadow.mStdDeviation;
+      if (stdDev.width != stdDev.height) {
+        return false;
+      }
+
+      float radius = stdDev.width;
+      wr::WrFilterOp filterOp = {
+        wr::WrFilterOpType::DropShadow,
+        radius,
+        {(float)shadow.mOffset.x, (float)shadow.mOffset.y},
+        wr::ToColorF(shadow.mColor)
+      };
+
+      aWrFilters.AppendElement(filterOp);
+    } else {
+      return false;
+    }
+
+    if (filterIsNoop &&
+        aWrFilters.Length() > 0 &&
+        (aWrFilters.LastElement().filter_type == wr::WrFilterOpType::SrgbToLinear ||
+         aWrFilters.LastElement().filter_type == wr::WrFilterOpType::LinearToSrgb)) {
+      // We pushed a color space conversion filter in prevision of applying
+      // another filter which turned out to be a no-op, so the conversion is
+      // unnecessary. Remove it from the filter list.
+      // This is both an optimization and a way to pass the wptest
+      // css/filter-effects/filter-scale-001.html for which the needless
+      // sRGB->linear->no-op->sRGB roundtrip introduces a slight error and we
+      // cannot add fuzziness to the test.
+      Unused << aWrFilters.PopLastElement();
+      srgb = !srgb;
+    }
+  }
+
+  if (!srgb) {
+    wr::WrFilterOp filterOp = { wr::WrFilterOpType::LinearToSrgb };
+    aWrFilters.AppendElement(filterOp);
+  }
+
+  // Only adjust the post filter clip if we are able to render this without
+  // fallback.
+  if (finalClip.isSome()) {
+    aPostFilterBounds = finalClip.value();
+  }
+
+  return true;
+}
+
 nsRegion
 nsFilterInstance::GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
                                          const nsRegion& aPreFilterDirtyRegion)
 {
   if (aPreFilterDirtyRegion.IsEmpty()) {
     return nsRegion();
   }
 
--- a/layout/svg/nsFilterInstance.h
+++ b/layout/svg/nsFilterInstance.h
@@ -16,16 +16,17 @@
 #include "nsRect.h"
 #include "nsSize.h"
 #include "nsSVGFilters.h"
 #include "nsSVGNumber2.h"
 #include "nsSVGNumberPair.h"
 #include "nsTArray.h"
 #include "nsIFrame.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/webrender/WebRenderTypes.h"
 
 class gfxContext;
 class nsIFrame;
 class nsSVGFilterPaintCallback;
 
 namespace mozilla {
 namespace dom {
 class UserSpaceMetrics;
@@ -116,16 +117,25 @@ public:
    *   as aFilteredFrame's bbox ('bbox' is a specific SVG term), if non-null.
    * @param aPreFilterBounds The pre-filter visual overflow rect of
    *   aFilteredFrame, if non-null.
    */
   static nsRect GetPostFilterBounds(nsIFrame *aFilteredFrame,
                                     const gfxRect *aOverrideBBox = nullptr,
                                     const nsRect *aPreFilterBounds = nullptr);
 
+  /**
+   * Try to build WebRender filters for a frame if the filters applied to it are supported.
+   */
+  static bool
+  BuildWebRenderFilters(nsIFrame* aFilteredFrame,
+                        const mozilla::LayoutDeviceIntRect& aPreFilterBounds,
+                        nsTArray<mozilla::wr::WrFilterOp>& aWrFilters,
+                        mozilla::LayoutDeviceIntRect& aPostFilterBounds);
+
 private:
   /**
    * @param aTargetFrame The frame of the filtered element under consideration,
    *   may be null.
    * @param aTargetContent The filtered element itself.
    * @param aMetrics The metrics to resolve SVG lengths against.
    * @param aFilterChain The list of filters to apply.
    * @param aFilterInputIsTainted Describes whether the SourceImage / SourceAlpha
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -1146,16 +1146,28 @@ nsSVGIntegrationUtils::PaintFilter(const
   RegularFramePaintCallback callback(aParams.builder, aParams.layerManager,
                                      offsets.offsetToUserSpaceInDevPx);
   nsRegion dirtyRegion = aParams.dirtyRect - offsets.offsetToBoundingBox;
 
   nsFilterInstance::PaintFilteredFrame(frame, &context, &callback,
                                        &dirtyRegion, aParams.imgParams, opacity);
 }
 
+bool
+nsSVGIntegrationUtils::BuildWebRenderFilters(nsIFrame *aFilteredFrame,
+                                             const mozilla::LayoutDeviceIntRect& aPreFilterBounds,
+                                             nsTArray<mozilla::wr::WrFilterOp>& aWrFilters,
+                                             mozilla::LayoutDeviceIntRect& aPostFilterBounds)
+{
+  return nsFilterInstance::BuildWebRenderFilters(aFilteredFrame,
+                                                 aPreFilterBounds,
+                                                 aWrFilters,
+                                                 aPostFilterBounds);
+}
+
 class PaintFrameCallback : public gfxDrawingCallback {
 public:
   PaintFrameCallback(nsIFrame* aFrame,
                      const nsSize aPaintServerSize,
                      const IntSize aRenderSize,
                      uint32_t aFlags)
    : mFrame(aFrame)
    , mPaintServerSize(aPaintServerSize)
--- a/layout/svg/nsSVGIntegrationUtils.h
+++ b/layout/svg/nsSVGIntegrationUtils.h
@@ -7,16 +7,17 @@
 #ifndef NSSVGINTEGRATIONUTILS_H_
 #define NSSVGINTEGRATIONUTILS_H_
 
 #include "ImgDrawResult.h"
 #include "gfxMatrix.h"
 #include "gfxRect.h"
 #include "nsRegionFwd.h"
 #include "mozilla/gfx/Rect.h"
+#include "mozilla/webrender/WebRenderTypes.h"
 
 class gfxContext;
 class gfxDrawable;
 class nsDisplayList;
 class nsDisplayListBuilder;
 class nsIFrame;
 
 struct nsRect;
@@ -194,16 +195,25 @@ public:
 
   /**
    * Paint non-SVG frame with filter and opacity effect.
    */
   static void
   PaintFilter(const PaintFramesParams& aParams);
 
   /**
+   * Try to build WebRender filters for a frame if the filters applied to it are supported.
+   */
+  static bool
+  BuildWebRenderFilters(nsIFrame *aFilteredFrame,
+                        const mozilla::LayoutDeviceIntRect& aPreFilterBounds,
+                        nsTArray<mozilla::wr::WrFilterOp>& aWrFilters,
+                        mozilla::LayoutDeviceIntRect& aPostFilterBounds);
+
+  /**
    * @param aRenderingContext the target rendering context in which the paint
    * server will be rendered
    * @param aTarget the target frame onto which the paint server will be
    * rendered
    * @param aPaintServer a first-continuation frame to use as the source
    * @param aFilter a filter to be applied when scaling
    * @param aDest the area the paint server image should be mapped to
    * @param aFill the area to be filled with copies of the paint server image
--- a/taskcluster/ci/build/linux.yml
+++ b/taskcluster/ci/build/linux.yml
@@ -244,16 +244,17 @@ linux64-base-toolchains/opt:
     index:
         product: firefox
         job-name: linux64-base-toolchains-opt
     treeherder:
         platform: linux64/opt
         symbol: Bb
     worker-type: aws-provisioner-v1/gecko-{level}-b-linux
     worker:
+        docker-image: {in-tree: debian7-amd64-build-base}
         max-run-time: 7200
         env:
             PERFHERDER_EXTRA_OPTIONS: base-toolchains
             FORCE_GCC: '1'
     run:
         using: mozharness
         actions: [get-secrets, build, check-test]
         config:
--- a/taskcluster/ci/config.yml
+++ b/taskcluster/ci/config.yml
@@ -56,16 +56,17 @@ treeherder:
         'cs': 'Checksum signing'
         'css': 'Checksum signing for source'
         'rs': 'Repackage signing'
         'BMcs': 'Beetmover checksums'
         'BMcslang': 'Beetmover checksums for language packs'
         'BMcss': 'Beetmover checksums for source'
         'Aries': 'Aries Device Image'
         'Deb7': 'Packages for Debian 7'
+        'Deb7-32': 'Packages for Debian 7 32-bits'
         'Deb9': 'Packages for Debian 9'
         'Nexus 5-L': 'Nexus 5-L Device Image'
         'I': 'Docker Image Builds'
         'TL': 'Toolchain builds for Linux 64-bits'
         'TM': 'Toolchain builds for OSX'
         'TMW': 'Toolchain builds for Windows MinGW'
         'TW32': 'Toolchain builds for Windows 32-bits'
         'TW64': 'Toolchain builds for Windows 64-bits'
--- a/taskcluster/ci/docker-image/kind.yml
+++ b/taskcluster/ci/docker-image/kind.yml
@@ -39,29 +39,62 @@ jobs:
       - deb7-python-zstandard
       - deb7-xz-utils
   toolchain-build:
     symbol: I(toolchain)
     parent: debian7-base
     packages:
       - deb7-cmake
       - deb7-ninja
+  debian7-amd64-build-base:
+    symbol: I(deb7-bb)
+    parent: debian7-base
+    definition: debian7-build
+    packages:
+      - deb7-valgrind
+    args:
+      ARCH: amd64
   debian7-amd64-build:
     symbol: I(deb7)
     parent: debian7-base
     definition: debian7-build
     packages:
+      - deb7-atk
+      - deb7-glib
+      - deb7-gdk-pixbuf
+      - deb7-gtk3
+      - deb7-harfbuzz
+      - deb7-libxkbcommon
+      - deb7-pango
+      - deb7-pcre3
       - deb7-valgrind
+      - deb7-wayland
     args:
       ARCH: amd64
   debian7-i386-build:
     symbol: I(deb7-32)
     parent: debian7-base
     definition: debian7-build
     packages:
+      - deb7-32-atk
+      - deb7-32-glib
+      - deb7-32-gdk-pixbuf
+      - deb7-32-gtk3
+      - deb7-32-harfbuzz
+      - deb7-32-libxkbcommon
+      - deb7-32-pango
+      - deb7-32-pcre3
+      - deb7-32-xkeyboard-config
+      - deb7-32-wayland
+      - deb7-atk
+      - deb7-glib
+      - deb7-gtk3
+      - deb7-harfbuzz
+      - deb7-python-defaults
+      - deb7-pcre3
       - deb7-valgrind
     args:
       ARCH: i386
   debian7-mozjs-rust-build:
     symbol: I(deb7jsrs)
     parent: debian7-amd64-build
     packages:
       - deb7-cmake
--- a/taskcluster/ci/packages/kind.yml
+++ b/taskcluster/ci/packages/kind.yml
@@ -56,16 +56,28 @@ jobs:
       dsc:
         url: http://snapshot.debian.org/archive/debian/20170120T212942Z/pool/main/p/python3-defaults/python3-defaults_3.5.3-1.dsc
         sha256: 2bec1dd8a5836d5a19fbbd48d7c49aec40642669036297a34bbfd8b0b2d61439
       packages:
         - deb7-python3.5
       patch: python3-defaults-wheezy.diff
       pre-build-command: debian/rules control-file
 
+  deb7-python-defaults:
+    description: "multiarch python-defaults for Debian wheezy"
+    treeherder:
+      symbol: Deb7(python-defaults)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20130930T035642Z/pool/main/p/python-defaults/python-defaults_2.7.3-4+deb7u1.dsc
+        sha256: e12fa64899a025b7ac3bdccd5611ae6f3d23327b695b2938473b1cf68ecc9ae5
+      patch: python-defaults-wheezy.diff
+      pre-build-command: debian/rules control-file
+
   deb7-cmake:
     description: "Cmake backport for Debian wheezy"
     treeherder:
       symbol: Deb7(cmake)
     run:
       using: debian-package
       dsc:
         url: http://snapshot.debian.org/archive/debian/20161204T034107Z/pool/main/c/cmake/cmake_3.7.1-1.dsc
@@ -260,8 +272,251 @@ jobs:
     treeherder:
       symbol: Deb9(python-zstandard)
     run:
       using: debian-package
       dist: stretch
       tarball:
         url: https://github.com/indygreg/python-zstandard/releases/download/0.9.1/python-zstandard-0.9.1.tar.gz
         sha256: 59c7d6f1f85cebb5124abb50d8ec281c5311e0812e18785e28b197cf1515dd3b
+
+  deb7-pcre3:
+    description: "pcre3 8.31 for Debian Wheezy"
+    treeherder:
+      symbol: Deb7(pcre3)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20140424T055217Z/pool/main/p/pcre3/pcre3_8.31-5.dsc
+        sha256: e6e92af1e9f4b1d286ce9e7fdb6cb2f0972a341a94f5631e0b8c31b9f79633a4
+
+  deb7-atk:
+    description: "atk 2.8 for Debian Wheezy"
+    treeherder:
+      symbol: Deb7(atk)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20130510T040301Z/pool/main/a/atk1.0/atk1.0_2.8.0-2.dsc
+        sha256: cae824b2a5ef47704fb820c04b5b7ee234329d9ddda1086bf487e12d58b9f70c
+
+  deb7-glib:
+    description: "glib 2.38 for Debian Wheezy"
+    treeherder:
+      symbol: Deb7(glib)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20140215T160944Z/pool/main/g/glib2.0/glib2.0_2.38.2-5.dsc
+        sha256: 1d81952a9a46a935d35d723f7528bf8d5264ef8a59491bad335d134dbeaa2404
+      patch: glib-wheezy.diff
+      packages:
+        - deb7-pcre3
+
+  deb7-harfbuzz:
+    description: "harfbuzz for Debian Wheezy"
+    treeherder:
+      symbol: Deb7(harfbuzz)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20121211T033951Z/pool/main/h/harfbuzz/harfbuzz_0.9.9-1.dsc
+        sha256: 622677a2757a739fb59c8bcd8cde9c1722fac82808248e19ce1cae46620d92bd
+
+  deb7-gdk-pixbuf:
+    description: "gdk-pixbuf 2.28 for Debian Wheezy"
+    treeherder:
+      symbol: Deb7(gdkpixbuf)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20130608T215552Z/pool/main/g/gdk-pixbuf/gdk-pixbuf_2.28.2-1.dsc
+        sha256: f5057beb54c37293de352c6f253cedd8b144d25289f1fdf1a958f17b51565bcb
+      packages:
+        - deb7-glib
+        - deb7-pcre3
+
+  deb7-pango:
+    description: "pango 1.32 for Debian Wheezy"
+    treeherder:
+      symbol: Deb7(pango)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20130224T223605Z/pool/main/p/pango1.0/pango1.0_1.32.5-1.dsc
+        sha256: d9d9b1f797c5dbe70bfe9c7931d63b28437476aa1a737c424c7f072ca6e22914
+      packages:
+        - deb7-glib
+        - deb7-harfbuzz
+        - deb7-pcre3
+
+  deb7-libxkbcommon:
+    description: "libxkbcommon for Debian Wheezy"
+    treeherder:
+      symbol: Deb7(xkbc)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20140723T102555Z/pool/main/libx/libxkbcommon/libxkbcommon_0.4.1-2.dsc
+        sha256: 9046dbceda207ed7163b7c12c98399e6d119491a480dc908ae451d7fff0fb77c
+
+  deb7-wayland:
+    description: "wayland 1.2 for Debian wheezy"
+    treeherder:
+      symbol: Deb7(wayland)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20130908T214400Z/pool/main/w/wayland/wayland_1.2.1-1.dsc
+        sha256: 964619747c00c697c95f2739c7980a0a360d79d03eaa3d9a342fed81d86e9466
+
+  deb7-gtk3:
+    description: "gtk+ 3.10 for Debian wheezy"
+    treeherder:
+      symbol: Deb7(gtk3)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20140215T220417Z/pool/main/g/gtk+3.0/gtk+3.0_3.10.7-1.dsc
+        sha256: 2a6810d44517806940063bb488e49e7177732d8059c798cf0ef94103fefaf0b3
+      patch: gtk-wheezy.diff
+      packages:
+        - deb7-atk
+        - deb7-glib
+        - deb7-gdk-pixbuf
+        - deb7-harfbuzz
+        - deb7-libxkbcommon
+        - deb7-make
+        - deb7-pango
+        - deb7-pcre3
+        - deb7-wayland
+
+  deb7-32-pcre3:
+    description: "pcre3 8.31 for Debian Wheezy"
+    treeherder:
+      symbol: Deb7-32(pcre3)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20140424T055217Z/pool/main/p/pcre3/pcre3_8.31-5.dsc
+        sha256: e6e92af1e9f4b1d286ce9e7fdb6cb2f0972a341a94f5631e0b8c31b9f79633a4
+      arch: i386
+
+  deb7-32-atk:
+    description: "atk 2.8 for Debian Wheezy"
+    treeherder:
+      symbol: Deb7-32(atk)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20130510T040301Z/pool/main/a/atk1.0/atk1.0_2.8.0-2.dsc
+        sha256: cae824b2a5ef47704fb820c04b5b7ee234329d9ddda1086bf487e12d58b9f70c
+      arch: i386
+
+  deb7-32-glib:
+    description: "glib 2.38 for Debian Wheezy"
+    treeherder:
+      symbol: Deb7-32(glib)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20140215T160944Z/pool/main/g/glib2.0/glib2.0_2.38.2-5.dsc
+        sha256: 1d81952a9a46a935d35d723f7528bf8d5264ef8a59491bad335d134dbeaa2404
+      arch: i386
+      patch: glib-wheezy.diff
+      packages:
+        - deb7-32-pcre3
+
+  deb7-32-harfbuzz:
+    description: "harfbuzz for Debian Wheezy"
+    treeherder:
+      symbol: Deb7-32(harfbuzz)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20121211T033951Z/pool/main/h/harfbuzz/harfbuzz_0.9.9-1.dsc
+        sha256: 622677a2757a739fb59c8bcd8cde9c1722fac82808248e19ce1cae46620d92bd
+      arch: i386
+
+  deb7-32-gdk-pixbuf:
+    description: "gdk-pixbuf 2.28 for Debian Wheezy"
+    treeherder:
+      symbol: Deb7-32(gdkpixbuf)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20130608T215552Z/pool/main/g/gdk-pixbuf/gdk-pixbuf_2.28.2-1.dsc
+        sha256: f5057beb54c37293de352c6f253cedd8b144d25289f1fdf1a958f17b51565bcb
+      arch: i386
+      packages:
+        - deb7-32-glib
+        - deb7-32-pcre3
+
+  deb7-32-pango:
+    description: "pango 1.32 for Debian Wheezy"
+    treeherder:
+      symbol: Deb7-32(pango)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20130224T223605Z/pool/main/p/pango1.0/pango1.0_1.32.5-1.dsc
+        sha256: d9d9b1f797c5dbe70bfe9c7931d63b28437476aa1a737c424c7f072ca6e22914
+      arch: i386
+      packages:
+        - deb7-32-glib
+        - deb7-32-harfbuzz
+        - deb7-32-pcre3
+
+  deb7-32-xkeyboard-config:
+    description: "xkeyboard-config for Debian Wheezy"
+    treeherder:
+      symbol: Deb7-32(xkbdconfig)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20121225T153644Z/pool/main/x/xkeyboard-config/xkeyboard-config_2.5.1-3.dsc
+        sha256: 327d53dfca4288c7f75471bb01e6d1f161811706b1d8daa01bf9abc269016dc1
+      arch: i386
+      patch: xkeyboard-config-wheezy.diff
+
+  deb7-32-libxkbcommon:
+    description: "libxkbcommon for Debian Wheezy"
+    treeherder:
+      symbol: Deb7-32(xkbc)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20140723T102555Z/pool/main/libx/libxkbcommon/libxkbcommon_0.4.1-2.dsc
+        sha256: 9046dbceda207ed7163b7c12c98399e6d119491a480dc908ae451d7fff0fb77c
+      arch: i386
+
+  deb7-32-wayland:
+    description: "wayland 1.2 for Debian wheezy"
+    treeherder:
+      symbol: Deb7-32(wayland)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20130908T214400Z/pool/main/w/wayland/wayland_1.2.1-1.dsc
+        sha256: 964619747c00c697c95f2739c7980a0a360d79d03eaa3d9a342fed81d86e9466
+      arch: i386
+
+  deb7-32-gtk3:
+    description: "gtk+ 3.10 for Debian wheezy"
+    treeherder:
+      symbol: Deb7-32(gtk3)
+    run:
+      using: debian-package
+      dsc:
+        url: http://snapshot.debian.org/archive/debian/20140215T220417Z/pool/main/g/gtk+3.0/gtk+3.0_3.10.7-1.dsc
+        sha256: 2a6810d44517806940063bb488e49e7177732d8059c798cf0ef94103fefaf0b3
+      arch: i386
+      patch: gtk-wheezy.diff
+      packages:
+        - deb7-32-atk
+        - deb7-32-glib
+        - deb7-32-gdk-pixbuf
+        - deb7-32-harfbuzz
+        - deb7-32-libxkbcommon
+        - deb7-make
+        - deb7-32-pango
+        - deb7-32-pcre3
+        - deb7-32-wayland
--- a/taskcluster/docker/debian-base/setup_packages.sh
+++ b/taskcluster/docker/debian-base/setup_packages.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
 
 for task in "$@"; do
-  echo "deb [trusted=yes] https://queue.taskcluster.net/v1/task/$task/runs/0/artifacts/public/build/ debian/" > "/etc/apt/sources.list.d/99$task.list"
+  echo "deb [trusted=yes] https://queue.taskcluster.net/v1/task/$task/artifacts/public/build/ debian/" > "/etc/apt/sources.list.d/99$task.list"
 done
--- a/taskcluster/docker/debian7-build/Dockerfile
+++ b/taskcluster/docker/debian7-build/Dockerfile
@@ -12,17 +12,22 @@ ENV XZ_OPT=-T0
 RUN /usr/local/sbin/setup_packages.sh $DOCKER_IMAGE_PACKAGES
 
 # %ARG ARCH
 RUN dpkg --add-architecture $ARCH
 
 # Ideally, we wouldn't need gcc-multilib and the extra linux-libc-dev,
 # but the latter is required to make the former installable, and the former
 # because of bug 1409276.
+# We exclude /usr/share/doc/*/changelog.Debian* files because they might differ
+# between i386 and amd64 variants of the packages we build on automation
+# because of dates stored in them by debchange (and both might end up installed
+# in some cases).
 RUN apt-get update && \
+    echo path-exclude=/usr/share/doc/*/changelog.Debian* > /etc/dpkg/dpkg.cfg.d/excludes && \
     apt-get install \
       autoconf2.13 \
       automake \
       bzip2 \
       curl \
       file \
       gawk \
       gcc-multilib \
--- a/taskcluster/taskgraph/transforms/job/debian_package.py
+++ b/taskcluster/taskgraph/transforms/job/debian_package.py
@@ -165,17 +165,17 @@ def docker_worker_debian_package(config,
         '/{snapshot}/ {dist}-backports main" >> /etc/apt/sources.list && '
         'echo "deb http://snapshot.debian.org/archive/debian-security'
         '/{snapshot}/ {dist}/updates main" >> /etc/apt/sources.list && '
         'apt-get update -o Acquire::Check-Valid-Until=false -q && '
         # Add sources for packages coming from other package tasks.
         'apt-get install -yyq apt-transport-https ca-certificates && '
         'for task in $PACKAGES; do '
         '  echo "deb [trusted=yes] https://queue.taskcluster.net/v1/task'
-        '/$task/runs/0/artifacts/public/build/ debian/" '
+        '/$task/artifacts/public/build/ debian/" '
         '>> /etc/apt/sources.list; '
         'done && '
         # Install the base utilities required to build debian packages.
         'apt-get update -o Acquire::Check-Valid-Until=false -q && '
         'apt-get install -yyq {base_deps} && '
         'cd /tmp && '
         # Get, validate and extract the package source.
         'dget -d -u {src_url} && '
--- a/testing/web-platform/meta/css/filter-effects/filter-external-001-test.html.ini
+++ b/testing/web-platform/meta/css/filter-effects/filter-external-001-test.html.ini
@@ -1,2 +1,4 @@
 [filter-external-001-test.html]
-  expected: FAIL
+  expected:
+    if webrender: PASS
+    FAIL