merge autoland to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Sat, 14 Oct 2017 11:39:35 +0200
changeset 386249 0dd64d5842e80da586e0c3bb3f9ed04e2b1b338e
parent 386248 7192c463079726af269fcb0a41916a30a0276ace (current diff)
parent 386232 6d8203bb08166d32c1e73b52e1d0bac4e5bf1702 (diff)
child 386267 d43c1c0fa038fbd5aa71f09a07a3ed4fb00b8c97
push id53313
push userarchaeopteryx@coole-files.de
push dateSat, 14 Oct 2017 10:39:31 +0000
treeherderautoland@169bde8f9f3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone58.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
merge autoland to mozilla-central. r=merge a=merge MozReview-Commit-ID: HTrntJV5Dve
dom/interfaces/html/nsIDOMHTMLImageElement.idl
layout/style/nsICSSPseudoComparator.h
taskcluster/scripts/builder/build-android-dependencies/repackage-jdk-centos.sh
--- a/accessible/generic/ImageAccessible.cpp
+++ b/accessible/generic/ImageAccessible.cpp
@@ -12,17 +12,16 @@
 
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDocument.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIPresShell.h"
 #include "nsIServiceManager.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "nsIPersistentProperties2.h"
 #include "nsPIDOMWindow.h"
 #include "nsIURI.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // ImageAccessible
--- a/browser/components/search/test/browser.ini
+++ b/browser/components/search/test/browser.ini
@@ -18,16 +18,17 @@ support-files =
 [browser_483086.js]
 [browser_addEngine.js]
 [browser_amazon.js]
 [browser_bing.js]
 [browser_contextmenu.js]
 [browser_contextSearchTabPosition.js]
 skip-if = os == "mac" # bug 967013
 [browser_ddg.js]
+[browser_eBay.js]
 [browser_google.js]
 skip-if = artifact # bug 1315953
 [browser_google_codes.js]
 skip-if = artifact # bug 1315953
 [browser_google_nocodes.js]
 skip-if = artifact # bug 1315953
 [browser_google_behavior.js]
 skip-if = artifact # bug 1315953
new file mode 100644
--- /dev/null
+++ b/browser/components/search/test/browser_eBay.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * Test eBay search plugin URLs
+ */
+
+"use strict";
+
+const BROWSER_SEARCH_PREF = "browser.search.";
+
+function test() {
+  let engine = Services.search.getEngineByName("eBay");
+  ok(engine, "eBay");
+
+  let base = "https://rover.ebay.com/rover/1/711-53200-19255-0/1?ff3=4&toolid=20004&campid=5338192028&customid=&mpre=https://www.ebay.com/sch/foo";
+  let url;
+
+  // Test search URLs (including purposes).
+  url = engine.getSubmission("foo").uri.spec;
+  is(url, base, "Check search URL for 'foo'");
+
+  // Check all other engine properties.
+  const EXPECTED_ENGINE = {
+    name: "eBay",
+    alias: null,
+    description: "eBay - Online auctions",
+    searchForm: "https://www.ebay.com/",
+    hidden: false,
+    wrappedJSObject: {
+      "_iconURL": "resource://search-plugins/images/ebay.ico",
+      _urls: [
+        {
+          type: "text/html",
+          method: "GET",
+          template: "https://rover.ebay.com/rover/1/711-53200-19255-0/1",
+          params: [
+            {
+              name: "ff3",
+              value: "4",
+              purpose: undefined,
+            },
+            {
+              name: "toolid",
+              value: "20004",
+              purpose: undefined,
+            },
+            {
+              name: "campid",
+              value: "5338192028",
+              purpose: undefined,
+            },
+            {
+              name: "customid",
+              value: "",
+              purpose: undefined,
+            },
+            {
+              name: "mpre",
+              value: "https://www.ebay.com/sch/{searchTerms}",
+              purpose: undefined,
+            },
+          ],
+          mozparams: {},
+        },
+      ],
+    },
+  };
+
+  isSubObjectOf(EXPECTED_ENGINE, engine, "eBay");
+}
--- a/browser/components/search/test/browser_searchEngine_behaviors.js
+++ b/browser/components/search/test/browser_searchEngine_behaviors.js
@@ -33,16 +33,26 @@ const SEARCH_ENGINE_DETAILS = [{
   codes: {
     context: "&t=ffcm",
     keyword: "&t=ffab",
     newTab: "&t=ffnt",
     submission: "&t=ffsb",
   },
   name: "DuckDuckGo",
 }, {
+  alias: "e",
+  baseURL: "https://rover.ebay.com/rover/1/711-53200-19255-0/1?ff3=4&toolid=20004&campid=5338192028&customid=&mpre=https://www.ebay.com/sch/foo",
+  codes: {
+    context: "",
+    keyword: "",
+    newTab: "",
+    submission: "",
+  },
+  name: "eBay",
+}, {
 // TODO: Google is tested in browser_google_behaviors.js - we can't test it here
 // yet because of bug 1315953.
 //   alias: "g",
 //   baseURL: "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8",
 //   codes: {
 //     context: "",
 //     keyword: "",
 //     newTab: "",
--- a/browser/components/shell/nsGNOMEShellService.cpp
+++ b/browser/components/shell/nsGNOMEShellService.cpp
@@ -18,17 +18,17 @@
 #include "nsIGConfService.h"
 #include "nsIGIOService.h"
 #include "nsIGSettingsService.h"
 #include "nsIStringBundle.h"
 #include "nsIOutputStream.h"
 #include "nsIProcess.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
-#include "nsIDOMHTMLImageElement.h"
+#include "nsIDOMElement.h"
 #include "nsIImageLoadingContent.h"
 #include "imgIRequest.h"
 #include "imgIContainer.h"
 #include "mozilla/Sprintf.h"
 #if defined(MOZ_WIDGET_GTK)
 #include "nsIImageToPixbuf.h"
 #endif
 #include "nsXULAppAPI.h"
--- a/browser/components/shell/nsMacShellService.cpp
+++ b/browser/components/shell/nsMacShellService.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsDirectoryServiceDefs.h"
 #include "nsIDOMElement.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIDocument.h"
 #include "nsIContent.h"
 #include "nsILocalFileMac.h"
 #include "nsIObserverService.h"
 #include "nsIPrefService.h"
 #include "nsIServiceManager.h"
 #include "nsIStringBundle.h"
--- a/browser/components/shell/nsWindowsShellService.cpp
+++ b/browser/components/shell/nsWindowsShellService.cpp
@@ -6,18 +6,18 @@
 #include "nsWindowsShellService.h"
 
 #include "BinaryPath.h"
 #include "city.h"
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
+#include "nsIContent.h"
 #include "nsIDOMElement.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIOutputStream.h"
 #include "nsIPrefService.h"
 #include "nsIPrefLocalizedString.h"
 #include "nsIServiceManager.h"
 #include "nsIStringBundle.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
@@ -574,40 +574,39 @@ WriteBitmap(nsIFile* aFile, imgIContaine
   return rv;
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::SetDesktopBackground(nsIDOMElement* aElement,
                                             int32_t aPosition,
                                             const nsACString& aImageName)
 {
-  nsresult rv;
-
-  nsCOMPtr<imgIContainer> container;
-  nsCOMPtr<nsIDOMHTMLImageElement> imgElement(do_QueryInterface(aElement));
-  if (!imgElement) {
+  nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
+  if (!content || !content->IsHTMLElement(nsGkAtoms::img)) {
     // XXX write background loading stuff!
     return NS_ERROR_NOT_AVAILABLE;
   }
-  else {
-    nsCOMPtr<nsIImageLoadingContent> imageContent =
-      do_QueryInterface(aElement, &rv);
-    if (!imageContent)
-      return rv;
+
+  nsresult rv;
+  nsCOMPtr<nsIImageLoadingContent> imageContent =
+    do_QueryInterface(aElement, &rv);
+  if (!imageContent)
+    return rv;
 
-    // get the image container
-    nsCOMPtr<imgIRequest> request;
-    rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
-                                  getter_AddRefs(request));
-    if (!request)
-      return rv;
-    rv = request->GetImage(getter_AddRefs(container));
-    if (!container)
-      return NS_ERROR_FAILURE;
-  }
+  // get the image container
+  nsCOMPtr<imgIRequest> request;
+  rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
+                                getter_AddRefs(request));
+  if (!request)
+    return rv;
+
+  nsCOMPtr<imgIContainer> container;
+  rv = request->GetImage(getter_AddRefs(container));
+  if (!container)
+    return NS_ERROR_FAILURE;
 
   // get the file name from localized strings
   nsCOMPtr<nsIStringBundleService>
     bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIStringBundle> shellBundle;
   rv = bundleService->CreateBundle(SHELLSERVICE_PROPERTIES,
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -93,16 +93,17 @@
 #if BUILD_FASTER
     locale/browser/searchplugins/               (searchplugins/*.xml)
     locale/browser/searchplugins/list.json      (search/list.json)
 #else
     locale/browser/searchplugins/               (.deps/generated_@AB_CD@/*.xml)
     locale/browser/searchplugins/list.json      (.deps/generated_@AB_CD@/list.json)
 #endif
     locale/browser/searchplugins/images/amazon.ico     (searchplugins/images/amazon.ico)
+    locale/browser/searchplugins/images/ebay.ico       (searchplugins/images/ebay.ico)
     locale/browser/searchplugins/images/wikipedia.ico  (searchplugins/images/wikipedia.ico)
     locale/browser/searchplugins/images/yahoo.ico      (searchplugins/images/yahoo.ico)
     locale/browser/searchplugins/images/yandex-en.ico  (searchplugins/images/yandex-en.ico)
     locale/browser/searchplugins/images/yandex-ru.ico  (searchplugins/images/yandex-ru.ico)
 % locale browser-region @AB_CD@ %locale/browser-region/
     locale/browser-region/region.properties        (%chrome/browser-region/region.properties)
 # the following files are browser-specific overrides
     locale/browser/netError.dtd                (%chrome/overrides/netError.dtd)
--- a/browser/locales/search/list.json
+++ b/browser/locales/search/list.json
@@ -4,17 +4,19 @@
       "google", "yahoo", "amazondotcom", "bing", "ddg", "twitter", "wikipedia"
     ]
   },
   "regionOverrides": {
     "US": {
       "google": "google-nocodes"
     },
     "CA": {
-      "google": "google-nocodes"
+      "google": "google-nocodes",
+      "ebay": "ebay-ca",
+      "ebay-fr": "ebay-ca"
     },
     "KZ": {
       "google": "google-nocodes"
     },
     "BY": {
       "google": "google-nocodes"
     },
     "RU": {
@@ -26,23 +28,50 @@
     "CN": {
       "google": "google-nocodes"
     },
     "TW": {
       "google": "google-nocodes"
     },
     "HK": {
       "google": "google-nocodes"
+    },
+    "AT": {
+      "ebay-de": "ebay-at"
+    },
+    "AU": {
+      "ebay": "ebay-au",
+      "ebay-uk": "ebay-au"
+    },
+    "BE": {
+      "ebay": "ebay-be",
+      "ebay-nl": "ebay-be",
+      "ebay-fr": "ebay-be"
+    },
+    "CH": {
+      "ebay": "ebay-ch",
+      "ebay-de": "ebay-ch",
+      "ebay-fr": "ebay-ch"
+    },
+    "IE": {
+      "ebay": "ebay-ie",
+      "ebay-uk": "ebay-ie"
+    },
+    "NL": {
+      "ebay": "ebay-nl"
+    },
+    "GB": {
+      "ebay": "ebay-uk"
     }
   },
   "locales": {
     "en-US": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo", "amazondotcom", "bing", "ddg", "twitter", "wikipedia"
+          "google", "yahoo", "amazondotcom", "bing", "ddg", "ebay", "twitter", "wikipedia"
         ]
       },
       "experimental-hidden": {
         "visibleDefaultEngines": [
           "yahoo-en-CA", "yandex-en"
         ]
       }
     },
@@ -58,17 +87,17 @@
         "visibleDefaultEngines": [
           "google", "yahoo", "bing", "amazondotcom", "ddg", "wikipedia-af"
         ]
       }
     },
     "an": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-es", "bing", "wikipedia-an", "ddg", "twitter"
+          "google", "yahoo-es", "bing", "ebay-es", "wikipedia-an", "ddg", "twitter"
         ]
       }
     },
     "ar": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "bing", "amazondotcom", "ddg", "wikipedia-ar"
         ]
@@ -79,17 +108,17 @@
         "visibleDefaultEngines": [
           "google", "yahoo-in", "amazondotcom", "ddg", "wikipedia-as"
         ]
       }
     },
     "ast": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-es", "bing", "diccionariu-alla", "ddg", "wikipedia-ast"
+          "google", "yahoo-es", "bing", "diccionariu-alla", "ddg", "ebay-es", "wikipedia-ast"
         ]
       }
     },
     "az": {
       "default": {
         "visibleDefaultEngines": [
           "google", "amazondotcom", "azerdict", "bing", "ddg", "wikipedia-az", "yandex-az"
         ]
@@ -121,31 +150,31 @@
         "visibleDefaultEngines": [
           "google", "yahoo-in", "amazondotcom", "bing", "ddg", "rediff", "wikipedia-bn"
         ]
       }
     },
     "br": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-france", "amazon-france", "ddg", "freelang", "klask", "wikipedia-br"
+          "google", "yahoo-france", "amazon-france", "ddg", "ebay-fr", "freelang", "klask", "wikipedia-br"
         ]
       }
     },
     "bs": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "ddg", "olx", "twitter", "wikipedia-bs"
         ]
       }
     },
     "ca": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "bing", "diec2", "ddg", "twitter", "wikipedia-ca"
+          "google", "bing", "diec2", "ddg", "ebay-es", "twitter", "wikipedia-ca"
         ]
       }
     },
     "cak": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo-espanol", "bing", "amazondotcom", "ddg", "wikipedia-es"
         ]
@@ -156,52 +185,52 @@
         "visibleDefaultEngines": [
           "google", "seznam-cz", "ddg", "heureka-cz", "mapy-cz", "wikipedia-cz"
         ]
       }
     },
     "cy": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-en-GB", "amazon-en-GB", "ddg", "palasprint", "termau", "wikipedia-cy"
+          "google", "yahoo-en-GB", "amazon-en-GB", "ddg", "ebay-uk", "palasprint", "termau", "wikipedia-cy"
         ]
       }
     },
     "da": {
       "default": {
         "visibleDefaultEngines": [
           "google", "bing", "amazon-en-GB", "ddg", "wikipedia-da"
         ]
       }
     },
     "de": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-de", "amazondotcom-de", "bing", "ddg", "leo_ende_de", "wikipedia-de"
+          "google", "yahoo-de", "amazondotcom-de", "bing", "ddg", "ebay-de", "leo_ende_de", "wikipedia-de"
         ]
       }
     },
     "dsb": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-de", "bing", "amazondotcom-de", "ddg", "leo_ende_de", "wikipedia-dsb"
+          "google", "yahoo-de", "bing", "amazondotcom-de", "ddg", "ebay-de", "leo_ende_de", "wikipedia-dsb"
         ]
       }
     },
     "el": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "amazon-en-GB", "bing", "ddg", "wikipedia-el"
         ]
       }
     },
     "en-GB": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-en-GB", "bing", "amazon-en-GB", "chambers-en-GB", "ddg", "twitter", "wikipedia"
+          "google", "yahoo-en-GB", "bing", "amazon-en-GB", "chambers-en-GB", "ddg", "ebay-uk", "twitter", "wikipedia"
         ]
       },
       "experimental-hidden": {
         "visibleDefaultEngines": [
           "yandex-en"
         ]
       }
     },
@@ -231,17 +260,17 @@
         "visibleDefaultEngines": [
           "google", "yahoo-cl", "bing", "drae", "ddg", "mercadolibre-cl", "wikipedia-es"
         ]
       }
     },
     "es-ES": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-es", "bing", "drae", "ddg", "twitter", "wikipedia-es"
+          "google", "yahoo-es", "bing", "drae", "ddg", "ebay-es", "twitter", "wikipedia-es"
         ]
       }
     },
     "es-MX": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo-mx", "bing", "ddg", "mercadolibre-mx", "wikipedia-es"
         ]
@@ -252,17 +281,17 @@
         "visibleDefaultEngines": [
           "google", "neti-ee", "ddg", "osta-ee", "wikipedia-et", "eki-ee"
         ]
       }
     },
     "eu": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo", "bing", "amazon-en-GB", "ddg", "elebila", "wikipedia-eu"
+          "google", "yahoo", "bing", "amazon-en-GB", "ddg", "ebay-es", "elebila", "wikipedia-eu"
         ]
       }
     },
     "fa": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "amazondotcom", "bing", "ddg", "wikipedia-fa"
         ]
@@ -280,45 +309,45 @@
         "visibleDefaultEngines": [
           "google", "yahoo-fi", "bing", "bookplus-fi", "ddg", "wikipedia-fi"
         ]
       }
     },
     "fr": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-france", "bing", "amazon-france", "ddg", "cnrtl-tlfi-fr", "wikipedia-fr"
+          "google", "yahoo-france", "bing", "amazon-france", "ddg", "ebay-fr", "cnrtl-tlfi-fr", "wikipedia-fr"
         ]
       }
     },
     "fy-NL": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-fy-NL", "bing", "bolcom-fy-NL", "ddg", "marktplaats-fy-NL", "wikipedia-fy-NL"
+          "google", "yahoo-fy-NL", "bing", "bolcom-fy-NL", "ddg", "ebay-nl", "marktplaats-fy-NL", "wikipedia-fy-NL"
         ]
       }
     },
     "ga-IE": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-en-GB", "amazon-en-GB", "ddg", "tearma", "twitter", "wikipedia-ga-IE"
+          "google", "yahoo-en-GB", "amazon-en-GB", "ddg", "ebay-ie", "tearma", "twitter", "wikipedia-ga-IE"
         ]
       }
     },
     "gd": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-en-GB", "faclair-beag", "amazon-en-GB", "bbc-alba", "ddg", "wikipedia-gd"
+          "google", "yahoo-en-GB", "amazon-en-GB", "bbc-alba", "ddg", "ebay-uk", "faclair-beag", "wikipedia-gd"
         ]
       }
     },
     "gl": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-es", "amazon-en-GB", "ddg", "wikipedia-gl"
+          "google", "yahoo-es", "amazon-en-GB", "ddg", "ebay-es", "wikipedia-gl"
         ]
       }
     },
     "gn": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo-es", "bing", "amazondotcom", "ddg", "twitter", "wikipedia-gn"
         ]
@@ -350,17 +379,17 @@
         "visibleDefaultEngines": [
           "google", "yahoo", "amazon-en-GB", "bing", "ddg", "eudict", "twitter", "wikipedia-hr"
         ]
       }
     },
     "hsb": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-de", "bing", "amazondotcom-de", "ddg", "leo_ende_de", "wikipedia-hsb"
+          "google", "yahoo-de", "bing", "amazondotcom-de", "ddg", "ebay-de", "leo_ende_de", "wikipedia-hsb"
         ]
       }
     },
     "hu": {
       "default": {
         "visibleDefaultEngines": [
           "google", "ddg", "sztaki-en-hu", "vatera", "wikipedia-hu"
         ]
@@ -392,17 +421,17 @@
         "visibleDefaultEngines": [
           "google", "yahoo", "bing", "amazondotcom", "ddg", "leit-is", "wikipedia-is"
         ]
       }
     },
     "it": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-it", "bing", "amazon-it", "ddg", "hoepli", "wikipedia-it"
+          "google", "yahoo-it", "bing", "amazon-it", "ddg", "ebay-it", "hoepli", "wikipedia-it"
         ]
       }
     },
     "ja-JP-mac": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo-jp", "bing", "amazon-jp", "rakuten", "yahoo-jp-auctions", "oshiete-goo", "twitter-ja", "wikipedia-ja", "ddg"
         ]
@@ -455,17 +484,17 @@
         "visibleDefaultEngines": [
           "google", "ddg", "naver-kr", "danawa-kr", "daum-kr", "wikipedia-kr"
         ]
       }
     },
     "lij": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-it", "bing", "amazon-it", "ddg", "paroledigenova-lij", "wikipedia-lij"
+          "google", "yahoo-it", "bing", "amazon-it", "ddg", "ebay-it", "paroledigenova-lij", "wikipedia-lij"
         ]
       }
     },
     "lo": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "bing", "ddg", "wikipedia-lo", "twitter"
         ]
@@ -546,17 +575,17 @@
         "visibleDefaultEngines": [
           "google", "yahoo", "bing", "ddg", "twitter", "wikipedia-ne"
         ]
       }
     },
     "nl": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "bing", "bolcom-nl", "ddg", "marktplaats-nl", "wikipedia-nl"
+          "google", "bing", "bolcom-nl", "ddg", "ebay-nl", "marktplaats-nl", "wikipedia-nl"
         ]
       }
     },
     "nn-NO": {
       "default": {
         "visibleDefaultEngines": [
           "google", "bing", "amazon-en-GB", "ddg", "gulesider-NO", "bok-NO", "qxl-NO", "wikipedia-NN"
         ]
@@ -595,17 +624,17 @@
         "visibleDefaultEngines": [
           "google", "amazon-en-GB", "ddg", "priberam", "sapo", "wikipedia-pt"
         ]
       }
     },
     "rm": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "yahoo-ch", "bing", "ddg", "leo_ende_de-rm", "pledarigrond", "wikipedia-rm"
+          "google", "yahoo-ch", "bing", "ddg", "ebay-ch", "leo_ende_de-rm", "pledarigrond", "wikipedia-rm"
         ]
       }
     },
     "ro": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "bing", "amazondotcom", "ddg", "wikipediaro"
         ]
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-at.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/5221-53469-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.at/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.at/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-au.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/705-53470-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.com.au/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.com.au/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-be.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/1553-53471-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.befr.ebay.be/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.at/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-ca.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/706-53473-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.ca/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.ca/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-ch.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/5222-53480-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.ch/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.ch/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-de.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/707-53477-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.de/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.de/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-es.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/1185-53479-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.es/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.es/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-fr.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/709-53476-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.fr/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.fr/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-ie.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/5282-53468-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.ie/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.ie/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-it.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/724-53478-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.it/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.it/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-nl.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/1346-53482-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.nl/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.nl/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay-uk.xml
@@ -0,0 +1,19 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/710-53481-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.co.uk/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.co.uk/</SearchForm>
+</SearchPlugin>
+
+
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/ebay.xml
@@ -0,0 +1,17 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>eBay</ShortName>
+<Description>eBay - Online auctions</Description>
+<Image width="16" height="16">resource://search-plugins/images/ebay.ico</Image>
+<Url type="text/html" method="GET" template="https://rover.ebay.com/rover/1/711-53200-19255-0/1" resultdomain="ebay.com">
+  <Param name="ff3" value="4"/>
+  <Param name="toolid" value="20004"/>
+  <Param name="campid" value="5338192028"/>
+  <Param name="customid" value=""/>
+  <Param name="mpre" value="https://www.ebay.com/sch/{searchTerms}" />
+</Url>
+<SearchForm>https://www.ebay.com/</SearchForm>
+</SearchPlugin>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..92d0d46e60c8eb3742277512594a6def0019d08d
GIT binary patch
literal 1128
zc$@)f1ef~&0096301yxW009690ILB2044wc03aX$009690G9#)0MP*e0EtjeM-2)Z
z3IG5A4M|8uQUCw|5C8xG5C{eU001BJ|6u?C0dh%1K~y-6m69=X6G0F~U(d9(5|r`U
zc+0Rvs2re#ghWLtRY<0kbEwdbd<S2`Hz0(9l5AYwlF{rm!N``^tc>|l_w=9Nzk3FD
zU_2gMp68b5xs666+r?`|S(Y}R&l{JDqIjCfbUL-!Y}QJiOeX&p84ia#NrS=QubR9)
zIk`K$34!n5zH+!%v<fV)esFyFhJM!H3iP0%y6QY{T-wv?MqWMeAm{Ht7=Sn9()aoF
z?h6auhZ^>?Uz~mXOqneR(QzYi+B=}a-3jQcPB#Ts)6)$9tN=Yo)lSCim!2{Mh*UW8
zo}l7!8z&lU6PXaqAcmCJ0r7!#fLb9$$6ACsK(t8QIM{l*4@)BEw6%O6?E<$8x^?pi
zR7FxiL`A?Uh=NZJ)Pwf`5p@o);Kbo#8bX&Lb@3LtV2!OVVB_5COO{tge+_kXtVFo}
zZB!VL8q1N>#>@WfzGzrH>MjwtrBqIuWAfl5{VyI};#2Sk%dUCo_ZIT;00000NkvXX
zu0mjfiBL{Q4GJ0x0000DNk~Le0000W0000W2nGNE0CReJ^Z)<?UP(kjR9J=Wma$UX
zKoEw%y*oK)T*OI+Ny3aWLqWPU>C#a70n$;ygwiw2(52EN<qh%-c?Rk*q#zCqSf|?*
zLbhWh%NQIQ{^oRZtKEP9+g%A(z;HO!?d@#^6wowH_3-deSMhZxWLc)YUT+fEd#~R6
z$=*4q$H&L(A+oo(Hwjdi?Ql3$=bQpM7z`ekM3!X=XuscYb)2SYBgvKFoU5{13NzQ#
z3e#qgWtoN$*x%n@Ha<s3M*tig9Nb@p-QC@#vzbHHDfh!nyWI)>e!uFFg^-<{okpV&
z0w*UY0Bmh-VXdVoipg4Geh+YZdP)d^G)?i|Hxpnrc^?d|MYwLb4UvTgm!`Y$d?UG}
z&O;?@Xdxg!K76db0;iFY^?ZK+m9ymKjn^A@;sEH{KYai6g|vIdIQ}c90mcH~IxjdE
zgKHq*($2G*;AKILtjG1<fZv1|Z%7m%7L37~-=v$4cU_1zX<Q4u@)j!=+fZsQ*Xcnb
zLas`VArYZK%B+ignti2&Iv_9(5Y=#1qjfGq$RmXqAfnbF#dNKdn!YeYMyrgW%y<Ec
zS=$Auf>!G-0=FFNjO;7G+4c@!Ya51Qafhv)K%(nZpswuakhjd3`w^IdHT7=(TMaaI
z!K2r}GFTgd#4I-(T+&b|j))ag&i%SUWGonmwUAhVh&6_50aujI4lT{3Ia7CD)PJv>
zDkE|<9|0X;ZWyT{78i^zlyik~oc*;B49c|_E`x9-imm--g1mK!#+pNe5)poOo;PqW
u@!J2wa$D{KgC%m&(uz-iL{9`BoxoqgO7D9`o)|;`0000<MNUMnLSTXdh59W3
--- a/browser/modules/ContextMenu.jsm
+++ b/browser/modules/ContextMenu.jsm
@@ -654,17 +654,17 @@ class ContextMenu {
       // used for nsContextMenu.initLeaveDOMFullScreenItems and
       // nsContextMenu.initMediaPlayerItems
       fullscreen: context.target.ownerDocument.fullscreen,
 
       // used for nsContextMenu.initMiscItems
       contentType: context.target.ownerDocument.contentType,
 
       // used for nsContextMenu.saveLink
-      isPrivate: context.target.ownerDocument.isPrivate,
+      isPrivate: PrivateBrowsingUtils.isBrowserPrivate(context.target.ownerDocument),
     };
 
     // used for nsContextMenu.initMediaPlayerItems
     Object.assign(cleanTarget, {
       ended: context.target.ended,
       muted: context.target.muted,
       paused: context.target.paused,
       controls: context.target.controls,
new file mode 100644
--- /dev/null
+++ b/build/build-clang/clang-5-linux64.json
@@ -0,0 +1,21 @@
+{
+    "llvm_revision": "312553",
+    "stages": "3",
+    "build_libcxx": true,
+    "build_type": "Release",
+    "assertions": false,
+    "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_500/final",
+    "clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_500/final",
+    "compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_500/final",
+    "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_500/final",
+    "libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_500/final",
+    "python_path": "/usr/bin/python2.7",
+    "gcc_dir": "/builds/worker/workspace/build/src/gcc",
+    "cc": "/builds/worker/workspace/build/src/gcc/bin/gcc",
+    "cxx": "/builds/worker/workspace/build/src/gcc/bin/g++",
+    "as": "/builds/worker/workspace/build/src/gcc/bin/gcc",
+    "patches": [
+      "llvm-debug-frame-for-5.patch",
+      "r313872.patch"
+    ]
+}
new file mode 100644
--- /dev/null
+++ b/build/build-clang/llvm-debug-frame-for-5.patch
@@ -0,0 +1,13 @@
+Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+===================================================================
+--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp	(revision 226419)
++++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp	(working copy)
+@@ -210,6 +210,8 @@
+     OutStreamer->EmitFileDirective(M.getSourceFileName());
+   }
+
++  OutStreamer->EmitCFISections(true, true);
++
+   GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
+   assert(MI && "AsmPrinter didn't require GCModuleInfo?");
+   for (auto &I : *MI)
new file mode 100644
--- /dev/null
+++ b/build/build-clang/r313872.patch
@@ -0,0 +1,19 @@
+Index: tools/dsymutil/DwarfLinker.cpp
+===================================================================
+--- a/llvm/tools/dsymutil/DwarfLinker.cpp	(revision 313871)
++++ b/llvm/tools/dsymutil/DwarfLinker.cpp	(revision 313872)
+@@ -1495,8 +1495,12 @@
+   uint64_t RefOffset = *RefValue.getAsReference();
+ 
+   if ((RefCU = getUnitForOffset(Units, RefOffset)))
+-    if (const auto RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset))
+-      return RefDie;
++    if (const auto RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset)) {
++      // In a file with broken references, an attribute might point to a NULL
++      // DIE.
++      if(!RefDie.isNULL())
++        return RefDie;
++    }
+ 
+   Linker.reportWarning("could not find referenced DIE", &DIE);
+   return DWARFDie();
--- a/build/moz.configure/java.configure
+++ b/build/moz.configure/java.configure
@@ -39,17 +39,17 @@ def check_java_tool(tool):
             die("The program %s was not found.  Set $JAVA_HOME to your Java "
                 "SDK directory or use '--with-java-bin-path={java-bin-dir}'"
                 % tool)
         return result
 
     return require_tool
 
 
-check_java_tool('java')
+java = check_java_tool('java')
 check_java_tool('javah')
 check_java_tool('jar')
 check_java_tool('jarsigner')
 check_java_tool('keytool')
 javac = check_java_tool('javac')
 
 
 @depends(javac)
@@ -61,8 +61,63 @@ def javac_version(javac):
                                          stderr=subprocess.STDOUT).rstrip()
         version = Version(output.split(' ')[-1])
         if version < '1.8':
             die('javac 1.8 or higher is required (found %s). '
                 'Check the JAVA_HOME environment variable.' % version)
         return version
     except subprocess.CalledProcessError as e:
         die('Failed to get javac version: %s', e.output)
+
+
+# Proguard detection
+# ========================================================
+@depends('--help')
+@imports('os')
+def proguard_jar_default(_):
+    # By default, look for proguard.jar in the location to which `mach
+    # bootstrap` or `mach artifact toolchain` will install Proguard.
+    default = os.path.expanduser(os.path.join('~', '.mozbuild'))
+    mozbuild_state_dir = os.environ.get('MOZBUILD_STATE_PATH', default)
+    return os.path.join(mozbuild_state_dir, 'proguard', 'lib', 'proguard.jar')
+
+
+# Proguard is really required; we provide a good error message when
+# validating.
+option(env='PROGUARD_JAR', nargs=1, default=proguard_jar_default,
+       help='Path to proguard.jar')
+
+
+@depends(java, 'PROGUARD_JAR')
+@checking('for proguard.jar version')
+# Do not change, this is fragile!  This form works with the test
+# configure sandbox.
+@imports(_from='os', _import='path')
+@imports('subprocess')
+def valid_proguard(java, proguard_jar):
+    if not proguard_jar or not path.isfile(proguard_jar[0]):
+        die('proguard.jar 5.3.3 or higher is required (looked for {}). '
+            'Run |mach artifact install --from-build proguard-jar| or add '
+            '`export PROGUARD_JAR=/path/to/proguard.jar` to your mozconfig.'
+            .format(proguard_jar[0]))
+
+    try:
+        output = subprocess.check_output([java, '-jar', proguard_jar[0]])
+        # Exit code zero shouldn't happen.
+        die('Expected `java -jar {}` to fail (with version in output) '
+            'but got exit code 0'
+            .format(proguard_jar[0]))
+
+    except subprocess.CalledProcessError as e:
+        # Exit code is non zero and output is like
+        # ProGuard, version 5.3.3
+        # Usage: java proguard.ProGuard [options ...]
+        output = e.output
+
+    version = Version(output.splitlines()[0].split(' ')[-1])
+    if version < '5.3.3':
+        die('proguard.jar 5.3.3 or higher is required (found %s). '
+            'Run |mach bootstrap| to upgrade. ' % version)
+
+    return proguard_jar[0]
+
+
+set_config('PROGUARD_JAR', valid_proguard)
--- a/build/moz.configure/rust.configure
+++ b/build/moz.configure/rust.configure
@@ -106,31 +106,32 @@ def rust_supported_targets(rustc):
     out = check_cmd_output(rustc, '--print', 'target-list').splitlines()
     # The os in the triplets used by rust may match the same OSes, in which
     # case we need to check the raw_os instead.
     per_os = {}
     ambiguous = set()
     per_raw_os = {}
     for t in out:
         t = split_triplet(t, allow_unknown=True)
-        key = (t.cpu, t.os)
+        key = (t.cpu, t.endianness, t.os)
         if key in per_os:
             previous = per_os[key]
-            per_raw_os[(previous.cpu, previous.raw_os)] = previous
+            per_raw_os[(previous.cpu, previous.endianness,
+                        previous.raw_os)] = previous
             del per_os[key]
             ambiguous.add(key)
         if key in ambiguous:
             raw_os = t.raw_os
             # split_triplet will return a raw_os of 'androideabi' for
             # rust targets in the form cpu-linux-androideabi, but what
             # we get from the build system is linux-androideabi, so
             # normalize.
             if raw_os == 'androideabi':
                 raw_os = 'linux-androideabi'
-            per_raw_os[(t.cpu, raw_os)] = t
+            per_raw_os[(t.cpu, t.endianness, raw_os)] = t
         else:
             per_os[key] = t
     return namespace(per_os=per_os, per_raw_os=per_raw_os)
 
 
 @template
 def rust_triple_alias(host_or_target):
     """Template defining the alias used for rustc's --target flag.
@@ -164,21 +165,22 @@ def rust_triple_alias(host_or_target):
             else:
                 host_or_target_os = 'windows-msvc'
             host_or_target_raw_os = host_or_target_os
         else:
             host_or_target_os = host_or_target.os
             host_or_target_raw_os = host_or_target.raw_os
 
         rustc_target = rust_supported_targets.per_os.get(
-            (host_or_target.cpu, host_or_target_os))
+            (host_or_target.cpu, host_or_target.endianness, host_or_target_os))
 
         if rustc_target is None:
             rustc_target = rust_supported_targets.per_raw_os.get(
-                (host_or_target.cpu, host_or_target_raw_os))
+                (host_or_target.cpu, host_or_target.endianness,
+                 host_or_target_raw_os))
 
         if rustc_target is None:
             die("Don't know how to translate {} for rustc".format(
                 host_or_target.alias))
 
         # Check to see whether our rustc has a reasonably functional stdlib
         # for our chosen target.
         target_arg = '--target=' + rustc_target.alias
--- a/devtools/client/shared/test/test-actor.js
+++ b/devtools/client/shared/test/test-actor.js
@@ -9,17 +9,20 @@
 // A helper actor for inspector and markupview tests.
 
 const { Cc, Ci, Cu } = require("chrome");
 const {
   getRect, getElementFromPoint, getAdjustedQuads, getWindowDimensions
 } = require("devtools/shared/layout/utils");
 const defer = require("devtools/shared/defer");
 const {Task} = require("devtools/shared/task");
-const {isContentStylesheet} = require("devtools/shared/inspector/css-logic");
+const {
+  isContentStylesheet,
+  getCSSStyleRules
+} = require("devtools/shared/inspector/css-logic");
 const DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 const loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
                  .getService(Ci.mozIJSSubScriptLoader);
 
 // Set up a dummy environment so that EventUtils works. We need to be careful to
 // pass a window object into each EventUtils method we call rather than having
 // it rely on the |window| global.
 let EventUtils = {};
@@ -772,17 +775,17 @@ var TestActor = exports.TestActor = prot
    * @param {String} selector The CSS selector to get the node (can be an array
    * of selectors to get elements in an iframe).
    * @return {Array} A list of stylesheet objects, each having the following properties:
    * - {String} href.
    * - {Boolean} isContentSheet.
    */
   getStyleSheetsInfoForNode: function (selector) {
     let node = this._querySelector(selector);
-    let domRules = DOMUtils.getCSSStyleRules(node);
+    let domRules = getCSSStyleRules(node);
 
     let sheets = [];
 
     for (let i = 0, n = domRules.Count(); i < n; i++) {
       let sheet = domRules.GetElementAt(i).parentStyleSheet;
       sheets.push({
         href: sheet.href,
         isContentSheet: isContentStylesheet(sheet)
--- a/devtools/server/actors/highlighters/geometry-editor.js
+++ b/devtools/server/actors/highlighters/geometry-editor.js
@@ -1,18 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { AutoRefreshHighlighter } = require("./auto-refresh");
-const { CanvasFrameAnonymousContentHelper, getCSSStyleRules, getComputedStyle,
+const { CanvasFrameAnonymousContentHelper, getComputedStyle,
         createSVGNode, createNode } = require("./utils/markup");
 const { setIgnoreLayoutChanges, getAdjustedQuads } = require("devtools/shared/layout/utils");
+const { getCSSStyleRules } = require("devtools/shared/inspector/css-logic");
 
 const GEOMETRY_LABEL_SIZE = 6;
 
 // List of all DOM Events subscribed directly to the document from the
 // Geometry Editor highlighter
 const DOM_EVENTS = ["mousemove", "mouseup", "pagehide"];
 
 const _dragging = Symbol("geometry/dragging");
--- a/devtools/server/actors/highlighters/shapes.js
+++ b/devtools/server/actors/highlighters/shapes.js
@@ -1,27 +1,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const { CanvasFrameAnonymousContentHelper, getCSSStyleRules,
+const { CanvasFrameAnonymousContentHelper,
         createSVGNode, createNode, getComputedStyle } = require("./utils/markup");
 const { setIgnoreLayoutChanges, getCurrentZoom,
         getAdjustedQuads } = require("devtools/shared/layout/utils");
 const { AutoRefreshHighlighter } = require("./auto-refresh");
 const {
   getDistance,
   clickedOnEllipseEdge,
   distanceToLine,
   projection,
   clickedOnPoint
 } = require("devtools/server/actors/utils/shapes-geometry-utils");
 const EventEmitter = require("devtools/shared/old-event-emitter");
+const { getCSSStyleRules } = require("devtools/shared/inspector/css-logic");
 
 const BASE_MARKER_SIZE = 5;
 // the width of the area around highlighter lines that can be clicked, in px
 const LINE_CLICK_WIDTH = 5;
 const DOM_EVENTS = ["mousedown", "mousemove", "mouseup", "dblclick"];
 const _dragging = Symbol("shapes/dragging");
 
 /**
--- a/devtools/server/actors/highlighters/utils/markup.js
+++ b/devtools/server/actors/highlighters/utils/markup.js
@@ -25,19 +25,16 @@ exports.hasPseudoClassLock = (...args) =
   lazyContainer.DOMUtils.hasPseudoClassLock(...args);
 
 exports.addPseudoClassLock = (...args) =>
   lazyContainer.DOMUtils.addPseudoClassLock(...args);
 
 exports.removePseudoClassLock = (...args) =>
   lazyContainer.DOMUtils.removePseudoClassLock(...args);
 
-exports.getCSSStyleRules = (...args) =>
-  lazyContainer.DOMUtils.getCSSStyleRules(...args);
-
 const SVG_NS = "http://www.w3.org/2000/svg";
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const STYLESHEET_URI = "resource://devtools/server/actors/" +
                        "highlighters.css";
 
 const _tokens = Symbol("classList/tokens");
 
--- a/devtools/server/css-logic.js
+++ b/devtools/server/css-logic.js
@@ -27,17 +27,25 @@
  *   reference to the selected element.
  */
 
 "use strict";
 
 const { Cc, Ci, Cu } = require("chrome");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const nodeConstants = require("devtools/shared/dom-node-constants");
-const {l10n, isContentStylesheet, shortSource, FILTER, STATUS} = require("devtools/shared/inspector/css-logic");
+const {
+  getBindingElementAndPseudo,
+  getCSSStyleRules,
+  l10n,
+  isContentStylesheet,
+  shortSource,
+  FILTER,
+  STATUS
+} = require("devtools/shared/inspector/css-logic");
 
 /**
  * @param {function} isInherited A function that determines if the CSS property
  *                   is inherited.
  */
 function CssLogic(isInherited) {
   // The cache of examined CSS properties.
   this._isInherited = isInherited;
@@ -532,21 +540,17 @@ CssLogic.prototype = {
       return;
     }
 
     do {
       let status = this.viewedElement === element ?
                    STATUS.MATCHED : STATUS.PARENT_MATCH;
 
       try {
-        // Handle finding rules on pseudo by reading style rules
-        // on the parent node with proper pseudo arg to getCSSStyleRules.
-        let {bindingElement, pseudo} =
-            CssLogic.getBindingElementAndPseudo(element);
-        domRules = domUtils.getCSSStyleRules(bindingElement, pseudo);
+        domRules = getCSSStyleRules(element);
       } catch (ex) {
         console.log("CL__buildMatchedRules error: " + ex);
         continue;
       }
 
       // getCSSStyleRules can return null with a shadow DOM element.
       let numDomRules = domRules ? domRules.Count() : 0;
       for (let i = 0; i < numDomRules; i++) {
@@ -649,31 +653,17 @@ CssLogic.getSelectors = function (domRul
  * If so, return the node that is accessible from within the document
  * (the parent of the anonymous node), along with which pseudo element
  * it was.  Otherwise, return the node itself.
  *
  * @returns {Object}
  *            - {DOMNode} node The non-anonymous node
  *            - {string} pseudo One of ':before', ':after', or null.
  */
-CssLogic.getBindingElementAndPseudo = function (node) {
-  let bindingElement = node;
-  let pseudo = null;
-  if (node.nodeName == "_moz_generated_content_before") {
-    bindingElement = node.parentNode;
-    pseudo = ":before";
-  } else if (node.nodeName == "_moz_generated_content_after") {
-    bindingElement = node.parentNode;
-    pseudo = ":after";
-  }
-  return {
-    bindingElement: bindingElement,
-    pseudo: pseudo
-  };
-};
+CssLogic.getBindingElementAndPseudo = getBindingElementAndPseudo;
 
 /**
  * Get the computed style on a node.  Automatically handles reading
  * computed styles on a ::before/::after element by reading on the
  * parent node with the proper pseudo argument.
  *
  * @param {Node}
  * @returns {CSSStyleDeclaration}
--- a/devtools/shared/inspector/css-logic.js
+++ b/devtools/shared/inspector/css-logic.js
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { getRootBindingParent } = require("devtools/shared/layout/utils");
 const { getTabPrefs } = require("devtools/shared/indentation");
+const { Ci, Cc } = require("chrome");
 
 const MAX_DATA_URL_LENGTH = 40;
 
 /*
  * About the objects defined in this file:
  * - CssLogic contains style information about a view context. It provides
  *   access to 2 sets of objects: Css[Sheet|Rule|Selector] provide access to
  *   information that does not change when the selected element changes while
@@ -466,8 +467,48 @@ function getXPath(ele) {
     parts.push(prefix + ele.localName + nth);
 
     ele = ele.parentNode;
   }
 
   return parts.length ? "/" + parts.reverse().join("/") : "";
 }
 exports.getXPath = getXPath;
+
+/**
+ * Given a node, check to see if it is a ::before or ::after element.
+ * If so, return the node that is accessible from within the document
+ * (the parent of the anonymous node), along with which pseudo element
+ * it was.  Otherwise, return the node itself.
+ *
+ * @returns {Object}
+ *            - {DOMNode} node The non-anonymous node
+ *            - {string} pseudo One of ':before', ':after', or null.
+ */
+function getBindingElementAndPseudo(node) {
+  let bindingElement = node;
+  let pseudo = null;
+  if (node.nodeName == "_moz_generated_content_before") {
+    bindingElement = node.parentNode;
+    pseudo = ":before";
+  } else if (node.nodeName == "_moz_generated_content_after") {
+    bindingElement = node.parentNode;
+    pseudo = ":after";
+  }
+  return {
+    bindingElement: bindingElement,
+    pseudo: pseudo
+  };
+}
+exports.getBindingElementAndPseudo = getBindingElementAndPseudo;
+
+/**
+ * Returns css style rules for a given a node.
+ * This function can handle ::before or ::after pseudo element as well as
+ * normal element.
+ */
+function getCSSStyleRules(node) {
+  const DOMUtils =
+    Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
+  let { bindingElement, pseudo } = getBindingElementAndPseudo(node);
+  return DOMUtils.getCSSStyleRules(bindingElement, pseudo);
+}
+exports.getCSSStyleRules = getCSSStyleRules;
--- a/docshell/base/nsContextMenuInfo.cpp
+++ b/docshell/base/nsContextMenuInfo.cpp
@@ -7,17 +7,16 @@
 #include "nsContextMenuInfo.h"
 
 #include "nsIImageLoadingContent.h"
 #include "imgLoader.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMHTMLHtmlElement.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "nsIDOMWindow.h"
 #include "nsICSSDeclaration.h"
 #include "nsIDOMCSSValue.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsNetUtil.h"
 #include "nsUnicharUtils.h"
 #include "nsIDocument.h"
 #include "nsIPrincipal.h"
--- a/dom/base/nsAttrValue.h
+++ b/dom/base/nsAttrValue.h
@@ -20,16 +20,17 @@
 #include "nsColor.h"
 #include "nsCaseTreatment.h"
 #include "nsMargin.h"
 #include "nsCOMPtr.h"
 #include "nsStringFwd.h"
 #include "SVGAttrValueWrapper.h"
 #include "nsTArrayForwardDeclare.h"
 #include "nsAtom.h"
+#include "mozilla/AtomArray.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/EnumTypeTraits.h"
 
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 
 class nsIDocument;
@@ -79,18 +80,16 @@ public:
     if (aBuf)
       aBuf->ToString(aBuf->StorageSize()/sizeof(char16_t) - 1, *this);
   }
 };
 
 class nsAttrValue {
   friend struct MiscContainer;
 public:
-  typedef nsTArray< RefPtr<nsAtom> > AtomArray;
-
   // This has to be the same as in ValueBaseType
   enum ValueType {
     eString =       0x00, //   00
                           //   01  this value indicates a 'misc' struct
     eAtom =         0x02, //   10
     eInteger =      0x03, // 0011
     eColor =        0x07, // 0111
     eEnum =         0x0B, // 1011  This should eventually die
@@ -195,17 +194,17 @@ public:
   // to retrieve the datatype that this nsAttrValue has.
   inline bool IsEmptyString() const;
   const nsCheapString GetStringValue() const;
   inline nsAtom* GetAtomValue() const;
   inline int32_t GetIntegerValue() const;
   bool GetColorValue(nscolor& aColor) const;
   inline int16_t GetEnumValue() const;
   inline float GetPercentValue() const;
-  inline AtomArray* GetAtomArrayValue() const;
+  inline mozilla::AtomArray* GetAtomArrayValue() const;
   inline mozilla::DeclarationBlock* GetCSSDeclarationValue() const;
   inline mozilla::css::URLValue* GetURLValue() const;
   inline mozilla::css::ImageValue* GetImageValue() const;
   inline double GetDoubleValue() const;
   bool GetIntMarginValue(nsIntMargin& aMargin) const;
 
   /**
    * Returns the string corresponding to the stored enum value.
--- a/dom/base/nsAttrValueInlines.h
+++ b/dom/base/nsAttrValueInlines.h
@@ -29,17 +29,17 @@ struct MiscContainer final
       union {
         int32_t mInteger;
         nscolor mColor;
         uint32_t mEnumValue;
         int32_t mPercent;
         mozilla::DeclarationBlock* mCSSDeclaration;
         mozilla::css::URLValue* mURL;
         mozilla::css::ImageValue* mImage;
-        nsAttrValue::AtomArray* mAtomArray;
+        mozilla::AtomArray* mAtomArray;
         nsIntMargin* mIntMargin;
         const nsSVGAngle* mSVGAngle;
         const nsSVGIntegerPair* mSVGIntegerPair;
         const nsSVGLength2* mSVGLength;
         const mozilla::SVGLengthList* mSVGLengthList;
         const mozilla::SVGNumberList* mSVGNumberList;
         const nsSVGNumberPair* mSVGNumberPair;
         const mozilla::SVGPathData* mSVGPathData;
@@ -134,17 +134,17 @@ nsAttrValue::GetPercentValue() const
 {
   NS_PRECONDITION(Type() == ePercent, "wrong type");
   return ((BaseType() == eIntegerBase)
           ? GetIntInternal()
           : GetMiscContainer()->mValue.mPercent)
             / 100.0f;
 }
 
-inline nsAttrValue::AtomArray*
+inline mozilla::AtomArray*
 nsAttrValue::GetAtomArrayValue() const
 {
   NS_PRECONDITION(Type() == eAtomArray, "wrong type");
   return GetMiscContainer()->mValue.mAtomArray;
 }
 
 inline mozilla::DeclarationBlock*
 nsAttrValue::GetCSSDeclarationValue() const
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6752,17 +6752,17 @@ nsContentUtils::StripNullChars(const nsA
   while (start != end) {
     if (*start != '\0')
       aOutStr.Append(*start);
     ++start;
   }
 }
 
 struct ClassMatchingInfo {
-  nsAttrValue::AtomArray mClasses;
+  AtomArray mClasses;
   nsCaseTreatment mCaseTreatment;
 };
 
 // static
 bool
 nsContentUtils::MatchClassNames(Element* aElement, int32_t aNamespaceID,
                                 nsAtom* aAtom, void* aData)
 {
--- a/dom/base/nsDOMTokenList.cpp
+++ b/dom/base/nsDOMTokenList.cpp
@@ -57,32 +57,31 @@ nsDOMTokenList::GetParsedAttr()
 void
 nsDOMTokenList::RemoveDuplicates(const nsAttrValue* aAttr)
 {
   if (!aAttr || aAttr->Type() != nsAttrValue::eAtomArray) {
     return;
   }
 
   BloomFilter<8, nsAtom> filter;
-  nsAttrValue::AtomArray* array = aAttr->GetAtomArrayValue();
+  AtomArray* array = aAttr->GetAtomArrayValue();
   for (uint32_t i = 0; i < array->Length(); i++) {
     nsAtom* atom = array->ElementAt(i);
     if (filter.mightContain(atom)) {
       // Start again, with a hashtable
       RemoveDuplicatesInternal(array, i);
       return;
     } else {
       filter.add(atom);
     }
   }
 }
 
 void
-nsDOMTokenList::RemoveDuplicatesInternal(nsAttrValue::AtomArray* aArray,
-                                         uint32_t aStart)
+nsDOMTokenList::RemoveDuplicatesInternal(AtomArray* aArray, uint32_t aStart)
 {
   nsDataHashtable<nsPtrHashKey<nsAtom>, bool> tokens;
 
   for (uint32_t i = 0; i < aArray->Length(); i++) {
     nsAtom* atom = aArray->ElementAt(i);
     // No need to check the hashtable below aStart
     if (i >= aStart && tokens.Get(atom)) {
       aArray->RemoveElementAt(i);
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -860,17 +860,17 @@ BrowserElementChild.prototype = {
         (ChromeUtils.getClassName(elem) === "HTMLAreaElement" && elem.href)) {
       return {uri: elem.href,
               documentURI: documentURI,
               text: elem.textContent.substring(0, kLongestReturnedString)};
     }
     if (elem instanceof Ci.nsIImageLoadingContent && elem.currentURI) {
       return {uri: elem.currentURI.spec, documentURI: documentURI};
     }
-    if (elem instanceof Ci.nsIDOMHTMLImageElement) {
+    if (ChromeUtils.getClassName(elem) === "HTMLImageElement") {
       return {uri: elem.src, documentURI: documentURI};
     }
     if (elem instanceof Ci.nsIDOMHTMLMediaElement) {
       let hasVideo = !(elem.readyState >= elem.HAVE_METADATA &&
                        (elem.videoWidth == 0 || elem.videoHeight == 0));
       return {uri: elem.currentSrc || elem.src,
               hasVideo: hasVideo,
               documentURI: documentURI};
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -133,17 +133,16 @@ HTMLImageElement::~HTMLImageElement()
 
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLImageElement,
                                    nsGenericHTMLElement,
                                    mResponsiveSelector)
 
 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLImageElement,
                                              nsGenericHTMLElement,
-                                             nsIDOMHTMLImageElement,
                                              nsIImageLoadingContent,
                                              imgIOnloadBlocker,
                                              imgINotificationObserver)
 
 NS_IMPL_ELEMENT_CLONE(HTMLImageElement)
 
 
 bool
@@ -751,16 +750,23 @@ HTMLImageElement::Image(const GlobalObje
         return nullptr;
       }
     }
   }
 
   return img.forget();
 }
 
+NS_IMETHODIMP
+HTMLImageElement::GetNaturalHeight(uint32_t* aNaturalHeight)
+{
+  *aNaturalHeight = NaturalHeight();
+  return NS_OK;
+}
+
 uint32_t
 HTMLImageElement::NaturalHeight()
 {
   uint32_t height;
   nsresult rv = nsImageLoadingContent::GetNaturalHeight(&height);
 
   if (NS_FAILED(rv)) {
     MOZ_ASSERT(false, "GetNaturalHeight should not fail");
@@ -772,19 +778,19 @@ HTMLImageElement::NaturalHeight()
     MOZ_ASSERT(density >= 0.0);
     height = NSToIntRound(double(height) / density);
   }
 
   return height;
 }
 
 NS_IMETHODIMP
-HTMLImageElement::GetNaturalHeight(uint32_t* aNaturalHeight)
+HTMLImageElement::GetNaturalWidth(uint32_t* aNaturalWidth)
 {
-  *aNaturalHeight = NaturalHeight();
+  *aNaturalWidth = NaturalWidth();
   return NS_OK;
 }
 
 uint32_t
 HTMLImageElement::NaturalWidth()
 {
   uint32_t width;
   nsresult rv = nsImageLoadingContent::GetNaturalWidth(&width);
@@ -798,23 +804,16 @@ HTMLImageElement::NaturalWidth()
     double density = mResponsiveSelector->GetSelectedImageDensity();
     MOZ_ASSERT(density >= 0.0);
     width = NSToIntRound(double(width) / density);
   }
 
   return width;
 }
 
-NS_IMETHODIMP
-HTMLImageElement::GetNaturalWidth(uint32_t* aNaturalWidth)
-{
-  *aNaturalWidth = NaturalWidth();
-  return NS_OK;
-}
-
 nsresult
 HTMLImageElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
 {
   bool destIsStatic = aDest->OwnerDoc()->IsStaticDocument();
   auto dest = static_cast<HTMLImageElement*>(aDest);
   if (destIsStatic) {
     CreateStaticImageClone(dest);
   }
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -5,31 +5,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_HTMLImageElement_h
 #define mozilla_dom_HTMLImageElement_h
 
 #include "mozilla/Attributes.h"
 #include "nsGenericHTMLElement.h"
 #include "nsImageLoadingContent.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "imgRequestProxy.h"
 #include "Units.h"
 #include "nsCycleCollectionParticipant.h"
 
 namespace mozilla {
 class EventChainPreVisitor;
 namespace dom {
 
 class ImageLoadTask;
 
 class ResponsiveImageSelector;
 class HTMLImageElement final : public nsGenericHTMLElement,
-                               public nsImageLoadingContent,
-                               public nsIDOMHTMLImageElement
+                               public nsImageLoadingContent
 {
   friend class HTMLSourceElement;
   friend class HTMLPictureElement;
   friend class ImageLoadTask;
 public:
   explicit HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   static already_AddRefed<HTMLImageElement>
@@ -47,19 +45,16 @@ public:
   virtual bool Draggable() const override;
 
   // Element
   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
 
   // EventTarget
   virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
 
-  // nsIDOMHTMLImageElement
-  NS_DECL_NSIDOMHTMLIMAGEELEMENT
-
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLImageElement, img)
 
   // override from nsImageLoadingContent
   CORSMode GetCORSMode() override;
 
   // nsIContent
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsAtom* aAttribute,
@@ -85,16 +80,21 @@ public:
                          bool aPreallocateChildren) const override;
 
   virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
 
   nsresult CopyInnerTo(Element* aDest, bool aPreallocateChildren);
 
   void MaybeLoadImage(bool aAlwaysForceLoad);
 
+  // Overrides for nsImageLoadingContent's GetNaturalHeight/Width, since we
+  // handle responsive scaling in the element's version of these methods.
+  NS_IMETHOD GetNaturalHeight(uint32_t* aNaturalHeight) override;
+  NS_IMETHOD GetNaturalWidth(uint32_t* aNaturalWidth) override;
+
   bool IsMap()
   {
     return GetBoolAttr(nsGkAtoms::ismap);
   }
   void SetIsMap(bool aIsMap, ErrorResult& aError)
   {
     SetHTMLBoolAttr(nsGkAtoms::ismap, aIsMap, aError);
   }
@@ -390,18 +390,16 @@ protected:
                                 nsIPrincipal* aMaybeScriptedPrincipal,
                                 bool aNotify) override;
   virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
                                           const nsAttrValueOrString& aValue,
                                           bool aNotify) override;
 
   // Override for nsImageLoadingContent.
   nsIContent* AsContent() override { return this; }
-  NS_IMETHOD GetNaturalWidth(uint32_t* aNaturalWidth) override;
-  NS_IMETHOD GetNaturalHeight(uint32_t* aNaturalHeight) override;
 
   // This is a weak reference that this element and the HTMLFormElement
   // cooperate in maintaining.
   HTMLFormElement* mForm;
 
   // Created when we're tracking responsive image state
   RefPtr<ResponsiveImageSelector> mResponsiveSelector;
 
--- a/dom/html/ImageDocument.cpp
+++ b/dom/html/ImageDocument.cpp
@@ -8,17 +8,16 @@
 #include "mozilla/dom/ImageDocumentBinding.h"
 #include "mozilla/dom/HTMLImageElement.h"
 #include "nsRect.h"
 #include "nsIImageLoadingContent.h"
 #include "nsGenericHTMLElement.h"
 #include "nsDocShell.h"
 #include "nsIDocumentInlines.h"
 #include "nsDOMTokenList.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIDOMEventListener.h"
 #include "nsIFrame.h"
 #include "nsGkAtoms.h"
 #include "imgIRequest.h"
 #include "imgILoader.h"
--- a/dom/interfaces/html/moz.build
+++ b/dom/interfaces/html/moz.build
@@ -9,17 +9,16 @@ with Files("**"):
 
 XPIDL_SOURCES += [
     'nsIDOMHTMLBaseElement.idl',
     'nsIDOMHTMLCollection.idl',
     'nsIDOMHTMLDocument.idl',
     'nsIDOMHTMLElement.idl',
     'nsIDOMHTMLFormElement.idl',
     'nsIDOMHTMLHtmlElement.idl',
-    'nsIDOMHTMLImageElement.idl',
     'nsIDOMHTMLInputElement.idl',
     'nsIDOMHTMLMediaElement.idl',
     'nsIDOMHTMLMenuItemElement.idl',
     'nsIDOMHTMLOptionElement.idl',
     'nsIDOMHTMLOptionsCollection.idl',
     'nsIDOMHTMLScriptElement.idl',
     'nsIDOMHTMLSelectElement.idl',
     'nsIDOMHTMLSourceElement.idl',
deleted file mode 100644
--- a/dom/interfaces/html/nsIDOMHTMLImageElement.idl
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMHTMLElement.idl"
-
-/**
- * The nsIDOMHTMLImageElement interface is the interface to a [X]HTML
- * img element.
- *
- * This interface is trying to follow the DOM Level 2 HTML specification:
- * http://www.w3.org/TR/DOM-Level-2-HTML/
- *
- * with changes from the work-in-progress WHATWG HTML specification:
- * http://www.whatwg.org/specs/web-apps/current-work/
- */
-
-[uuid(ec18e71c-4f5c-4cc3-aa36-5273168644dc)]
-interface nsIDOMHTMLImageElement : nsISupports
-{
-};
--- a/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
+++ b/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
@@ -21,17 +21,16 @@
 #include "nsIComponentRegistrar.h"
 #include "nsIContent.h"
 #include "nsIDOMAttr.h"
 #include "nsIDOMComment.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLBaseElement.h"
 #include "nsIDOMHTMLCollection.h"
 #include "nsIDOMHTMLDocument.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLMediaElement.h"
 #include "nsIDOMHTMLOptionElement.h"
 #include "nsIDOMHTMLScriptElement.h"
 #include "nsIDOMHTMLSourceElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsIDOMMozNamedAttrMap.h"
 #include "nsIDOMNode.h"
@@ -478,18 +477,17 @@ ResourceReader::OnWalkDOMNode(nsIDOMNode
     }
 
     nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
     if (!content) {
         return NS_OK;
     }
 
     // Test the node to see if it's an image, frame, iframe, css, js
-    nsCOMPtr<nsIDOMHTMLImageElement> nodeAsImage = do_QueryInterface(aNode);
-    if (nodeAsImage) {
+    if (content->IsHTMLElement(nsGkAtoms::img)) {
         return OnWalkAttribute(aNode, "src");
     }
 
     if (content->IsSVGElement(nsGkAtoms::img)) {
         return OnWalkAttribute(aNode, "href", "http://www.w3.org/1999/xlink");
     }
 
     nsCOMPtr<nsIDOMHTMLMediaElement> nodeAsMedia = do_QueryInterface(aNode);
@@ -982,18 +980,17 @@ PersistNodeFixup::FixupNode(nsIDOMNode *
     if (content->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th)) {
         rv = GetNodeToFixup(aNodeIn, aNodeOut);
         if (NS_SUCCEEDED(rv) && *aNodeOut) {
             FixupAttribute(*aNodeOut, "background");
         }
         return rv;
     }
 
-    nsCOMPtr<nsIDOMHTMLImageElement> nodeAsImage = do_QueryInterface(aNodeIn);
-    if (nodeAsImage) {
+    if (content->IsHTMLElement(nsGkAtoms::img)) {
         rv = GetNodeToFixup(aNodeIn, aNodeOut);
         if (NS_SUCCEEDED(rv) && *aNodeOut) {
             // Disable image loads
             nsCOMPtr<nsIImageLoadingContent> imgCon =
                 do_QueryInterface(*aNodeOut);
             if (imgCon) {
                 imgCon->SetLoadingEnabled(false);
             }
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -34,17 +34,16 @@
 #include "nsGkAtoms.h"
 #include "nsIClipboard.h"
 #include "nsIContent.h"
 #include "nsIContentFilter.h"
 #include "nsIDOMComment.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIDOMElement.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLScriptElement.h"
 #include "nsIDOMNode.h"
 #include "nsIDocument.h"
 #include "nsIEditRules.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIMIMEService.h"
--- a/gfx/doc/README.webrender
+++ b/gfx/doc/README.webrender
@@ -170,9 +170,9 @@ 2. Sometimes autoland tip has changed en
    has an env var you can set to do this). In theory you can get the same
    result by resolving the conflict manually but Cargo.lock files are usually not
    trivial to merge by hand. If it's just the third_party/rust dir that has conflicts
    you can delete it and run |mach vendor rust| again to repopulate it.
 
 -------------------------------------------------------------------------------
 
 The version of WebRender currently in the tree is:
-6440dff485271cdfd24a22c920cea31e01e2b164
+a624aa6d3b6006c510c8b14026567af4ac545d2f
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -22,36 +22,36 @@ StackingContextHelper::StackingContextHe
                                              wr::DisplayListBuilder& aBuilder,
                                              const nsTArray<wr::WrFilterOp>& aFilters,
                                              const gfx::Matrix4x4* aBoundTransform,
                                              uint64_t aAnimationsId,
                                              float* aOpacityPtr,
                                              gfx::Matrix4x4* aTransformPtr,
                                              gfx::Matrix4x4* aPerspectivePtr,
                                              const gfx::CompositionOp& aMixBlendMode,
-                                             bool aBackfaceVisible)
+                                             bool aBackfaceVisible,
+                                             bool aIsPreserve3D)
   : mBuilder(&aBuilder)
   , mScale(1.0f, 1.0f)
 {
-  bool is2d = !aTransformPtr || (aTransformPtr->Is2D() && !aPerspectivePtr);
   if (aTransformPtr) {
     mTransform = *aTransformPtr;
   }
 
   // Compute scale for fallback rendering.
   gfx::Matrix transform2d;
   if (aBoundTransform && aBoundTransform->CanDraw2D(&transform2d)) {
     mScale = transform2d.ScaleFactors(true) * aParentSC.mScale;
   }
 
   mBuilder->PushStackingContext(wr::LayoutRect(),
                                 aAnimationsId,
                                 aOpacityPtr,
                                 aTransformPtr,
-                                is2d ? wr::TransformStyle::Flat : wr::TransformStyle::Preserve3D,
+                                aIsPreserve3D ? wr::TransformStyle::Preserve3D : wr::TransformStyle::Flat,
                                 aPerspectivePtr,
                                 wr::ToMixBlendMode(aMixBlendMode),
                                 aFilters,
                                 aBackfaceVisible);
 }
 
 StackingContextHelper::~StackingContextHelper()
 {
--- a/gfx/layers/wr/StackingContextHelper.h
+++ b/gfx/layers/wr/StackingContextHelper.h
@@ -32,17 +32,18 @@ public:
                         wr::DisplayListBuilder& aBuilder,
                         const nsTArray<wr::WrFilterOp>& aFilters = nsTArray<wr::WrFilterOp>(),
                         const gfx::Matrix4x4* aBoundTransform = nullptr,
                         uint64_t aAnimationsId = 0,
                         float* aOpacityPtr = nullptr,
                         gfx::Matrix4x4* aTransformPtr = nullptr,
                         gfx::Matrix4x4* aPerspectivePtr = nullptr,
                         const gfx::CompositionOp& aMixBlendMode = gfx::CompositionOp::OP_OVER,
-                        bool aBackfaceVisible = true);
+                        bool aBackfaceVisible = true,
+                        bool aIsPreserve3D = false);
   // This version of the constructor should only be used at the root level
   // of the tree, so that we have a StackingContextHelper to pass down into
   // the RenderLayer traversal, but don't actually want it to push a stacking
   // context on the display list builder.
   StackingContextHelper();
 
   // Pops the stacking context, if one was pushed during the constructor.
   ~StackingContextHelper();
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -626,17 +626,17 @@ WebRenderBridgeParent::RecvEmptyTransact
 {
   if (mDestroyed) {
     for (const auto& op : aToDestroy) {
       DestroyActor(op);
     }
     return IPC_OK();
   }
 
-  AutoProfilerTracing tracing("Paint", "EmptyTransaction");
+  AUTO_PROFILER_TRACING("Paint", "EmptyTransaction");
   UpdateFwdTransactionId(aFwdTransactionId);
   AutoClearReadLocks clearLocks(mReadLocks);
 
   // This ensures that destroy operations are always processed. It is not safe
   // to early-return without doing so.
   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
 
   if (!aCommands.IsEmpty()) {
--- a/gfx/webrender/Cargo.toml
+++ b/gfx/webrender/Cargo.toml
@@ -9,17 +9,17 @@ build = "build.rs"
 [features]
 default = ["freetype-lib"]
 freetype-lib = ["freetype/servo-freetype-sys"]
 profiler = ["thread_profiler/thread_profiler"]
 debugger = ["ws", "serde_json", "serde", "serde_derive"]
 
 [dependencies]
 app_units = "0.5.6"
-bincode = "0.8"
+bincode = "0.9"
 byteorder = "1.0"
 euclid = "0.15.2"
 fxhash = "0.2.1"
 gleam = "0.4.8"
 lazy_static = "0.2"
 log = "0.3"
 num-traits = "0.1.32"
 time = "0.1"
@@ -39,15 +39,15 @@ env_logger = "0.4"
 rand = "0.3"                # for the benchmarks
 servo-glutin = "0.12"     # for the example apps
 
 [target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
 freetype = { version = "0.3", default-features = false }
 
 [target.'cfg(target_os = "windows")'.dependencies]
 dwrote = "0.4"
-gamma-lut = "0.2"
+gamma-lut = "0.2.1"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.4"
 core-graphics = "0.9"
 core-text = { version = "7.0", default-features = false }
-gamma-lut = "0.2"
+gamma-lut = "0.2.1"
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/examples/common/image_helper.rs
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use webrender::api::{ImageData, ImageDescriptor, ImageFormat};
+
+pub fn make_checkerboard(width: u32, height: u32) -> (ImageDescriptor, ImageData) {
+    let mut image_data = Vec::new();
+    for y in 0 .. height {
+        for x in 0 .. width {
+            let lum = 255 * (((x & 8) == 0) ^ ((y & 8) == 0)) as u8;
+            image_data.extend_from_slice(&[lum, lum, lum, 0xff]);
+        }
+    }
+    (ImageDescriptor::new(width, height, ImageFormat::BGRA8, true), ImageData::new(image_data))
+}
--- a/gfx/webrender/examples/image_resize.rs
+++ b/gfx/webrender/examples/image_resize.rs
@@ -3,16 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
+#[path = "common/image_helper.rs"]
+mod image_helper;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use webrender::api::*;
 
 struct App {
     image_key: ImageKey,
 }
 
@@ -21,28 +23,21 @@ impl Example for App {
         &mut self,
         _api: &RenderApi,
         builder: &mut DisplayListBuilder,
         resources: &mut ResourceUpdates,
         _layout_size: LayoutSize,
         _pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
-        let mut image_data = Vec::new();
-        for y in 0 .. 32 {
-            for x in 0 .. 32 {
-                let lum = 255 * (((x & 8) == 0) ^ ((y & 8) == 0)) as u8;
-                image_data.extend_from_slice(&[lum, lum, lum, 0xff]);
-            }
-        }
-
+        let (image_descriptor, image_data) = image_helper::make_checkerboard(32, 32);
         resources.add_image(
             self.image_key,
-            ImageDescriptor::new(32, 32, ImageFormat::BGRA8, true),
-            ImageData::new(image_data),
+            image_descriptor,
+            image_data,
             None,
         );
 
         let bounds = (0, 0).to(512, 512);
         let info = LayoutPrimitiveInfo::new(bounds);
         builder.push_stacking_context(
             &info,
             ScrollPolicy::Scrollable,
--- a/gfx/webrender/res/ps_split_composite.glsl
+++ b/gfx/webrender/res/ps_split_composite.glsl
@@ -33,21 +33,25 @@ vec3 bilerp(vec3 a, vec3 b, vec3 c, vec3
     vec3 y = mix(c, d, t);
     return mix(x, y, s);
 }
 
 void main(void) {
     CompositeInstance ci = fetch_composite_instance();
     SplitGeometry geometry = fetch_split_geometry(ci.user_data0);
     AlphaBatchTask src_task = fetch_alpha_batch_task(ci.src_task_index);
+    AlphaBatchTask dest_task = fetch_alpha_batch_task(ci.render_task_index);
+
+    vec2 dest_origin = dest_task.render_target_origin -
+                       dest_task.screen_space_origin;
 
     vec3 world_pos = bilerp(geometry.points[0], geometry.points[1],
                             geometry.points[3], geometry.points[2],
                             aPosition.y, aPosition.x);
-    vec4 final_pos = vec4(world_pos.xy * uDevicePixelRatio, ci.z, 1.0);
+    vec4 final_pos = vec4((world_pos.xy + dest_origin) * uDevicePixelRatio, ci.z, 1.0);
 
     gl_Position = uTransform * final_pos;
 
     vec2 uv_origin = src_task.render_target_origin;
     vec2 uv_pos = uv_origin + world_pos.xy - src_task.screen_space_origin;
     vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
     vUv = vec3(uv_pos / texture_size, src_task.render_target_layer_index);
     vUvTaskBounds = vec4(uv_origin, uv_origin + src_task.size) / texture_size.xyxy;
--- a/gfx/webrender/res/ps_text_run.glsl
+++ b/gfx/webrender/res/ps_text_run.glsl
@@ -59,26 +59,43 @@ void main(void) {
 
     vColor = vec4(text.color.rgb * text.color.a, text.color.a);
     vUv = vec3(mix(st0, st1, f), res.layer);
     vUvBorder = (res.uv_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
+
+#define MODE_ALPHA          0
+#define MODE_SUBPX_PASS0    1
+#define MODE_SUBPX_PASS1    2
+
 void main(void) {
     vec3 tc = vec3(clamp(vUv.xy, vUvBorder.xy, vUvBorder.zw), vUv.z);
-#ifdef WR_FEATURE_SUBPIXEL_AA
-    //note: the blend mode is not compatible with clipping
-    oFragColor = texture(sColor0, tc);
-#else
-    vec4 color = texture(sColor0, tc) * vColor;
+    vec4 color = texture(sColor0, tc);
+
     float alpha = 1.0;
 #ifdef WR_FEATURE_TRANSFORM
-    float a = 0.0;
-    init_transform_fs(vLocalPos, a);
-    alpha *= a;
+    init_transform_fs(vLocalPos, alpha);
 #endif
-    alpha = min(alpha, do_clip());
-    oFragColor = color * alpha;
-#endif
+    alpha *= do_clip();
+
+    // TODO(gw): It would be worth profiling this and seeing
+    //           if we should instead handle the mode via
+    //           a combination of mix() etc. Branching on
+    //           a uniform is probably fast in most GPUs now though?
+    vec4 modulate_color = vec4(0.0);
+    switch (uMode) {
+        case MODE_ALPHA:
+            modulate_color = alpha * vColor;
+            break;
+        case MODE_SUBPX_PASS0:
+            modulate_color = vec4(alpha);
+            break;
+        case MODE_SUBPX_PASS1:
+            modulate_color = vColor;
+            break;
+    }
+
+    oFragColor = color * modulate_color;
 }
 #endif
--- a/gfx/webrender/res/shared.glsl
+++ b/gfx/webrender/res/shared.glsl
@@ -34,16 +34,20 @@
     // Attribute inputs
     in vec3 aPosition;
 #endif
 
 //======================================================================================
 // Fragment shader attributes and uniforms
 //======================================================================================
 #ifdef WR_FRAGMENT_SHADER
+    // A generic uniform that shaders can optionally use to configure
+    // an operation mode for this batch.
+    uniform int uMode;
+
     // Uniform inputs
 
     // Fragment shader outputs
     out vec4 oFragColor;
 #endif
 
 //======================================================================================
 // Shared shader uniforms
--- a/gfx/webrender/src/clip_scroll_node.rs
+++ b/gfx/webrender/src/clip_scroll_node.rs
@@ -53,17 +53,17 @@ pub enum NodeType {
     /// Transforms it's content, but doesn't clip it. Can also be adjusted
     /// by scroll events or setting scroll offsets.
     ScrollFrame(ScrollingState),
 
     /// A special kind of node that adjusts its position based on the position
     /// of its parent node and a given set of sticky positioning constraints.
     /// Sticky positioned is described in the CSS Positioned Layout Module Level 3 here:
     /// https://www.w3.org/TR/css-position-3/#sticky-pos
-    StickyFrame(StickyFrameInfo),
+    StickyFrame(StickyFrameInfo, LayerVector2D),
 }
 
 /// Contains information common among all types of ClipScrollTree nodes.
 #[derive(Debug)]
 pub struct ClipScrollNode {
     /// Viewing rectangle in the coordinate system of the parent reference frame.
     pub local_viewport_rect: LayerRect,
 
@@ -189,17 +189,17 @@ impl ClipScrollNode {
             local_clip_rect: frame_rect,
             combined_local_viewport_rect: LayerRect::zero(),
             world_viewport_transform: LayerToWorldTransform::identity(),
             world_content_transform: LayerToWorldTransform::identity(),
             reference_frame_relative_scroll_offset: LayerVector2D::zero(),
             parent: Some(parent_id),
             children: Vec::new(),
             pipeline_id,
-            node_type: NodeType::StickyFrame(sticky_frame_info),
+            node_type: NodeType::StickyFrame(sticky_frame_info, LayerVector2D::zero()),
         }
     }
 
 
     pub fn add_child(&mut self, child: ClipId) {
         self.children.push(child);
     }
 
@@ -251,50 +251,48 @@ impl ClipScrollNode {
 
         scrolling.offset = new_offset;
         scrolling.bouncing_back = false;
         scrolling.started_bouncing_back = false;
         true
     }
 
     pub fn update_transform(&mut self, state: &TransformUpdateState) {
-        let scrolled_parent_combined_clip = state
-            .parent_combined_viewport_rect
-            .translate(&-state.parent_scroll_offset);
+        // We calculate this here to avoid a double-borrow later.
+        let sticky_offset = self.calculate_sticky_offset(
+            &state.nearest_scrolling_ancestor_offset,
+            &state.nearest_scrolling_ancestor_viewport,
+        );
 
         let (local_transform, accumulated_scroll_offset) = match self.node_type {
             NodeType::ReferenceFrame(ref info) => {
                 self.combined_local_viewport_rect = info.transform
                     .with_destination::<LayerPixel>()
-                    .inverse_rect_footprint(&scrolled_parent_combined_clip);
+                    .inverse_rect_footprint(&state.parent_combined_viewport_rect);
                 self.reference_frame_relative_scroll_offset = LayerVector2D::zero();
                 (info.transform, state.parent_accumulated_scroll_offset)
             }
             NodeType::Clip(_) | NodeType::ScrollFrame(_) => {
                 // Move the parent's viewport into the local space (of the node origin)
                 // and intersect with the local clip rectangle to get the local viewport.
-                self.combined_local_viewport_rect = scrolled_parent_combined_clip
+                self.combined_local_viewport_rect =
+                    state.parent_combined_viewport_rect
                     .intersection(&self.local_clip_rect)
                     .unwrap_or(LayerRect::zero());
                 self.reference_frame_relative_scroll_offset =
                     state.parent_accumulated_scroll_offset;
                 (
                     LayerToScrollTransform::identity(),
                     self.reference_frame_relative_scroll_offset,
                 )
             }
-            NodeType::StickyFrame(sticky_frame_info) => {
-                let sticky_offset = self.calculate_sticky_offset(
-                    &self.local_viewport_rect,
-                    &sticky_frame_info,
-                    &state.nearest_scrolling_ancestor_offset,
-                    &state.nearest_scrolling_ancestor_viewport,
-                );
-
-                self.combined_local_viewport_rect = scrolled_parent_combined_clip
+            NodeType::StickyFrame(_, ref mut node_sticky_offset) => {
+                *node_sticky_offset = sticky_offset;
+                self.combined_local_viewport_rect =
+                    state.parent_combined_viewport_rect
                     .translate(&-sticky_offset)
                     .intersection(&self.local_clip_rect)
                     .unwrap_or(LayerRect::zero());
                 self.reference_frame_relative_scroll_offset =
                     state.parent_accumulated_scroll_offset + sticky_offset;
                 (
                     LayerToScrollTransform::identity(),
                     self.reference_frame_relative_scroll_offset,
@@ -316,22 +314,25 @@ impl ClipScrollNode {
         // whatever scrolling offset we supply as well.
         let scroll_offset = self.scroll_offset();
         self.world_content_transform = self.world_viewport_transform
             .pre_translate(scroll_offset.to_3d());
     }
 
     fn calculate_sticky_offset(
         &self,
-        sticky_rect: &LayerRect,
-        sticky_frame_info: &StickyFrameInfo,
         viewport_scroll_offset: &LayerVector2D,
         viewport_rect: &LayerRect,
     ) -> LayerVector2D {
-        let sticky_rect = sticky_rect.translate(viewport_scroll_offset);
+        let sticky_frame_info = match self.node_type {
+            NodeType::StickyFrame(info, _) => info,
+            _ => return LayerVector2D::zero(),
+        };
+
+        let sticky_rect = self.local_viewport_rect.translate(viewport_scroll_offset);
         let mut sticky_offset = LayerVector2D::zero();
 
         if let Some(info) = sticky_frame_info.top {
             sticky_offset.y = viewport_rect.min_y() + info.margin - sticky_rect.min_y();
             sticky_offset.y = sticky_offset.y.max(0.0).min(info.max_offset);
         }
 
         if sticky_offset.y == 0.0 {
--- a/gfx/webrender/src/clip_scroll_tree.rs
+++ b/gfx/webrender/src/clip_scroll_tree.rs
@@ -36,17 +36,16 @@ pub struct ClipScrollTree {
     /// A set of pipelines which should be discarded the next time this
     /// tree is drained.
     pub pipelines_to_discard: FastHashSet<PipelineId>,
 }
 
 pub struct TransformUpdateState {
     pub parent_reference_frame_transform: LayerToWorldTransform,
     pub parent_combined_viewport_rect: LayerRect,
-    pub parent_scroll_offset: LayerVector2D,
     pub parent_accumulated_scroll_offset: LayerVector2D,
     pub nearest_scrolling_ancestor_offset: LayerVector2D,
     pub nearest_scrolling_ancestor_viewport: LayerRect,
 }
 
 impl ClipScrollTree {
     pub fn new() -> ClipScrollTree {
         let dummy_pipeline = PipelineId::dummy();
@@ -307,17 +306,16 @@ impl ClipScrollTree {
         let root_viewport = self.nodes[&root_reference_frame_id].local_clip_rect;
         let state = TransformUpdateState {
             parent_reference_frame_transform: LayerToWorldTransform::create_translation(
                 pan.x,
                 pan.y,
                 0.0,
             ),
             parent_combined_viewport_rect: root_viewport,
-            parent_scroll_offset: LayerVector2D::zero(),
             parent_accumulated_scroll_offset: LayerVector2D::zero(),
             nearest_scrolling_ancestor_offset: LayerVector2D::zero(),
             nearest_scrolling_ancestor_viewport: LayerRect::zero(),
         };
         self.update_node_transform(root_reference_frame_id, &state);
     }
 
     fn update_node_transform(&mut self, layer_id: ClipId, state: &TransformUpdateState) {
@@ -333,37 +331,44 @@ impl ClipScrollTree {
             // The transformation we are passing is the transformation of the parent
             // reference frame and the offset is the accumulated offset of all the nodes
             // between us and the parent reference frame. If we are a reference frame,
             // we need to reset both these values.
             let state = match node.node_type {
                 NodeType::ReferenceFrame(ref info) => TransformUpdateState {
                     parent_reference_frame_transform: node.world_viewport_transform,
                     parent_combined_viewport_rect: node.combined_local_viewport_rect,
-                    parent_scroll_offset: LayerVector2D::zero(),
                     parent_accumulated_scroll_offset: LayerVector2D::zero(),
                     nearest_scrolling_ancestor_viewport: state
                         .nearest_scrolling_ancestor_viewport
                         .translate(&info.origin_in_parent_reference_frame),
                     ..*state
                 },
-                NodeType::Clip(..) | NodeType::StickyFrame(..) => TransformUpdateState {
+                NodeType::Clip(..) => TransformUpdateState {
                     parent_combined_viewport_rect: node.combined_local_viewport_rect,
-                    parent_scroll_offset: LayerVector2D::zero(),
                     ..*state
                 },
                 NodeType::ScrollFrame(ref scrolling) => TransformUpdateState {
-                    parent_combined_viewport_rect: node.combined_local_viewport_rect,
-                    parent_scroll_offset: scrolling.offset,
+                    parent_combined_viewport_rect:
+                        node.combined_local_viewport_rect.translate(&-scrolling.offset),
                     parent_accumulated_scroll_offset: scrolling.offset +
                         state.parent_accumulated_scroll_offset,
                     nearest_scrolling_ancestor_offset: scrolling.offset,
                     nearest_scrolling_ancestor_viewport: node.local_viewport_rect,
                     ..*state
                 },
+                NodeType::StickyFrame(_, sticky_offset) => TransformUpdateState {
+                    // We don't translate the combined rect by the sticky offset, because sticky
+                    // offsets actually adjust the node position itself, whereas scroll offsets
+                    // only apply to contents inside the node.
+                    parent_combined_viewport_rect: node.combined_local_viewport_rect,
+                    parent_accumulated_scroll_offset:
+                        sticky_offset + state.parent_accumulated_scroll_offset,
+                    ..*state
+                }
             };
 
             (state, node.children.clone())
         };
 
         for child_layer_id in node_children {
             self.update_node_transform(child_layer_id, &state);
         }
@@ -474,19 +479,20 @@ impl ClipScrollTree {
             NodeType::ReferenceFrame(ref info) => {
                 pt.new_level(format!("ReferenceFrame {:?}", info.transform));
             }
             NodeType::ScrollFrame(scrolling_info) => {
                 pt.new_level(format!("ScrollFrame"));
                 pt.add_item(format!("scrollable_size: {:?}", scrolling_info.scrollable_size));
                 pt.add_item(format!("scroll.offset: {:?}", scrolling_info.offset));
             }
-            NodeType::StickyFrame(sticky_frame_info) => {
+            NodeType::StickyFrame(sticky_frame_info, sticky_offset) => {
                 pt.new_level(format!("StickyFrame"));
                 pt.add_item(format!("sticky info: {:?}", sticky_frame_info));
+                pt.add_item(format!("sticky offset: {:?}", sticky_offset));
             }
         }
 
         pt.add_item(format!(
             "local_viewport_rect: {:?}",
             node.local_viewport_rect
         ));
         pt.add_item(format!("local_clip_rect: {:?}", node.local_clip_rect));
--- a/gfx/webrender/src/debug_render.rs
+++ b/gfx/webrender/src/debug_render.rs
@@ -275,44 +275,44 @@ impl DebugRenderer {
             0.0,
             ORTHO_NEAR_PLANE,
             ORTHO_FAR_PLANE,
         );
 
         // Triangles
         if !self.tri_vertices.is_empty() {
             device.bind_program(&self.color_program);
-            device.set_uniforms(&self.color_program, &projection);
+            device.set_uniforms(&self.color_program, &projection, 0);
             device.bind_vao(&self.tri_vao);
             device.update_vao_indices(&self.tri_vao, &self.tri_indices, VertexUsageHint::Dynamic);
             device.update_vao_main_vertices(
                 &self.tri_vao,
                 &self.tri_vertices,
                 VertexUsageHint::Dynamic,
             );
             device.draw_triangles_u32(0, self.tri_indices.len() as i32);
         }
 
         // Lines
         if !self.line_vertices.is_empty() {
             device.bind_program(&self.color_program);
-            device.set_uniforms(&self.color_program, &projection);
+            device.set_uniforms(&self.color_program, &projection, 0);
             device.bind_vao(&self.line_vao);
             device.update_vao_main_vertices(
                 &self.line_vao,
                 &self.line_vertices,
                 VertexUsageHint::Dynamic,
             );
             device.draw_nonindexed_lines(0, self.line_vertices.len() as i32);
         }
 
         // Glyph
         if !self.font_indices.is_empty() {
             device.bind_program(&self.font_program);
-            device.set_uniforms(&self.font_program, &projection);
+            device.set_uniforms(&self.font_program, &projection, 0);
             device.bind_texture(DebugSampler::Font, &self.font_texture);
             device.bind_vao(&self.font_vao);
             device.update_vao_indices(&self.font_vao, &self.font_indices, VertexUsageHint::Dynamic);
             device.update_vao_main_vertices(
                 &self.font_vao,
                 &self.font_vertices,
                 VertexUsageHint::Dynamic,
             );
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use super::shader_source;
-use api::{ColorF, ImageFormat};
+use api::ImageFormat;
 use api::{DeviceIntRect, DeviceUintSize};
 use euclid::Transform3D;
 use gleam::gl;
 use internal_types::RenderTargetMode;
 use std::fs::File;
 use std::io::Read;
 use std::iter::repeat;
 use std::mem;
@@ -425,16 +425,17 @@ impl Drop for Texture {
         debug_assert!(thread::panicking() || self.id == 0);
     }
 }
 
 pub struct Program {
     id: gl::GLuint,
     u_transform: gl::GLint,
     u_device_pixel_ratio: gl::GLint,
+    u_mode: gl::GLint,
 }
 
 impl Drop for Program {
     fn drop(&mut self) {
         debug_assert!(
             thread::panicking() || self.id == 0,
             "renderer::deinit not called"
         );
@@ -1407,21 +1408,23 @@ impl Device {
                 error_log
             );
             self.gl.delete_program(pid);
             return Err(ShaderError::Link(base_filename.to_string(), error_log));
         }
 
         let u_transform = self.gl.get_uniform_location(pid, "uTransform");
         let u_device_pixel_ratio = self.gl.get_uniform_location(pid, "uDevicePixelRatio");
+        let u_mode = self.gl.get_uniform_location(pid, "uMode");
 
         let program = Program {
             id: pid,
             u_transform,
             u_device_pixel_ratio,
+            u_mode,
         };
 
         self.bind_program(&program);
 
         Ok(program)
     }
 
     pub fn bind_shader_samplers<S>(&mut self, program: &Program, bindings: &[(&'static str, S)])
@@ -1443,22 +1446,29 @@ impl Device {
     }
 
     pub fn set_uniform_2f(&self, uniform: UniformLocation, x: f32, y: f32) {
         debug_assert!(self.inside_frame);
         let UniformLocation(location) = uniform;
         self.gl.uniform_2f(location, x, y);
     }
 
-    pub fn set_uniforms(&self, program: &Program, transform: &Transform3D<f32>) {
+    pub fn set_uniforms(
+        &self,
+        program: &Program,
+        transform: &Transform3D<f32>,
+        mode: i32,
+    ) {
         debug_assert!(self.inside_frame);
         self.gl
             .uniform_matrix_4fv(program.u_transform, false, &transform.to_row_major_array());
         self.gl
             .uniform_1f(program.u_device_pixel_ratio, self.device_pixel_ratio);
+        self.gl
+            .uniform_1i(program.u_mode, mode);
     }
 
     pub fn create_pbo(&mut self) -> PBO {
         let id = self.gl.gen_buffers(1)[0];
         PBO { id }
     }
 
     pub fn delete_pbo(&mut self, mut pbo: PBO) {
@@ -1842,37 +1852,37 @@ impl Device {
             gl::SRC_ALPHA,
             gl::ONE_MINUS_SRC_ALPHA,
             gl::ONE,
             gl::ONE_MINUS_SRC_ALPHA,
         );
         self.gl.blend_equation(gl::FUNC_ADD);
     }
 
-    pub fn set_blend_mode_subpixel(&self, color: ColorF) {
-        self.gl.blend_color(color.r, color.g, color.b, color.a);
-        self.gl
-            .blend_func(gl::CONSTANT_COLOR, gl::ONE_MINUS_SRC_COLOR);
-    }
-
     pub fn set_blend_mode_multiply(&self) {
         self.gl
             .blend_func_separate(gl::ZERO, gl::SRC_COLOR, gl::ZERO, gl::SRC_ALPHA);
         self.gl.blend_equation(gl::FUNC_ADD);
     }
     pub fn set_blend_mode_max(&self) {
         self.gl
             .blend_func_separate(gl::ONE, gl::ONE, gl::ONE, gl::ONE);
         self.gl.blend_equation_separate(gl::MAX, gl::FUNC_ADD);
     }
     pub fn set_blend_mode_min(&self) {
         self.gl
             .blend_func_separate(gl::ONE, gl::ONE, gl::ONE, gl::ONE);
         self.gl.blend_equation_separate(gl::MIN, gl::FUNC_ADD);
     }
+    pub fn set_blend_mode_subpixel_pass0(&self) {
+        self.gl.blend_func(gl::ZERO, gl::ONE_MINUS_SRC_COLOR);
+    }
+    pub fn set_blend_mode_subpixel_pass1(&self) {
+        self.gl.blend_func(gl::ONE, gl::ONE);
+    }
 }
 
 /// return (gl_internal_format, gl_format)
 fn gl_texture_formats_for_image_format(
     gl: &gl::Gl,
     format: ImageFormat,
 ) -> (gl::GLint, gl::GLuint) {
     match format {
--- a/gfx/webrender/src/frame.rs
+++ b/gfx/webrender/src/frame.rs
@@ -1,8 +1,9 @@
+
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{BuiltDisplayListIter, ClipAndScrollInfo, ClipId, ColorF, ComplexClipRegion};
 use api::{DeviceUintRect, DeviceUintSize, DisplayItemRef, Epoch, FilterOp, HitTestFlags};
 use api::{HitTestResult, ImageDisplayItem, ItemRange, LayerPoint, LayerPrimitiveInfo, LayerRect};
 use api::{LayerSize, LayerToScrollTransform, LayerVector2D, LayoutSize, LayoutTransform};
@@ -682,18 +683,18 @@ impl Frame {
             }
             SpecificDisplayItem::PushShadow(shadow) => {
                 let mut prim_info = prim_info.clone();
                 prim_info.rect = LayerRect::zero();
                 context
                     .builder
                     .push_shadow(shadow, clip_and_scroll, &prim_info);
             }
-            SpecificDisplayItem::PopShadow => {
-                context.builder.pop_shadow();
+            SpecificDisplayItem::PopAllShadows => {
+                context.builder.pop_all_shadows();
             }
         }
         None
     }
 
     fn flatten_root<'a>(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{BorderDetails, BorderDisplayItem, BorderRadius, BoxShadowClipMode, BuiltDisplayList};
 use api::{ClipAndScrollInfo, ClipId, ColorF};
 use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintRect, DeviceUintSize};
 use api::{ExtendMode, FIND_ALL, FilterOp, FontInstance, FontRenderMode};
 use api::{GlyphInstance, GlyphOptions, GradientStop, HitTestFlags, HitTestItem, HitTestResult};
 use api::{ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect};
-use api::{LayerSize, LayerToScrollTransform, LayerVector2D, LayoutVector2D, LineOrientation};
+use api::{LayerPixel, LayerSize, LayerToScrollTransform, LayerVector2D, LayoutVector2D, LineOrientation};
 use api::{LineStyle, LocalClip, POINT_RELATIVE_TO_PIPELINE_VIEWPORT, PipelineId, RepeatMode};
 use api::{ScrollSensitivity, Shadow, TileOffset, TransformStyle};
 use api::{WorldPixel, WorldPoint, YuvColorSpace, YuvData, device_length};
 use app_units::Au;
 use border::ImageBorderSegment;
 use clip::{ClipMode, ClipRegion, ClipSource, ClipSources, ClipStore, Contains};
 use clip_scroll_node::{ClipInfo, ClipScrollNode, NodeType};
 use clip_scroll_tree::ClipScrollTree;
@@ -97,17 +97,21 @@ pub struct FrameBuilder {
     stacking_context_store: Vec<StackingContext>,
     clip_scroll_group_store: Vec<ClipScrollGroup>,
     // Note: value here is meant to be `ClipScrollGroupIndex`,
     // but we already have `ClipAndScrollInfo` in the key
     clip_scroll_group_indices: FastHashMap<ClipAndScrollInfo, usize>,
     packed_layers: Vec<PackedLayer>,
 
     // A stack of the current shadow primitives.
-    shadow_prim_stack: Vec<PrimitiveIndex>,
+    // The sub-Vec stores a buffer of fast-path primitives to be appended on pop.
+    shadow_prim_stack: Vec<(PrimitiveIndex, Vec<(PrimitiveIndex, ClipAndScrollInfo)>)>,
+    // If we're doing any fast-path shadows, we buffer the "real"
+    // content here, to be appended when the shadow stack is empty.
+    pending_shadow_contents: Vec<(PrimitiveIndex, ClipAndScrollInfo, LayerPrimitiveInfo)>,
 
     scrollbar_prims: Vec<ScrollbarPrimitive>,
 
     /// A stack of scroll nodes used during display list processing to properly
     /// parent new scroll nodes.
     reference_frame_stack: Vec<ClipId>,
 
     /// A stack of stacking contexts used for creating ClipScrollGroups as
@@ -215,16 +219,17 @@ impl FrameBuilder {
             Some(prev) => FrameBuilder {
                 stacking_context_store: recycle_vec(prev.stacking_context_store),
                 clip_scroll_group_store: recycle_vec(prev.clip_scroll_group_store),
                 clip_scroll_group_indices: FastHashMap::default(),
                 cmds: recycle_vec(prev.cmds),
                 hit_testing_runs: recycle_vec(prev.hit_testing_runs),
                 packed_layers: recycle_vec(prev.packed_layers),
                 shadow_prim_stack: recycle_vec(prev.shadow_prim_stack),
+                pending_shadow_contents: recycle_vec(prev.pending_shadow_contents),
                 scrollbar_prims: recycle_vec(prev.scrollbar_prims),
                 reference_frame_stack: recycle_vec(prev.reference_frame_stack),
                 stacking_context_stack: recycle_vec(prev.stacking_context_stack),
                 prim_store: prev.prim_store.recycle(),
                 clip_store: prev.clip_store.recycle(),
                 screen_size,
                 background_color,
                 config,
@@ -233,16 +238,17 @@ impl FrameBuilder {
             None => FrameBuilder {
                 stacking_context_store: Vec::new(),
                 clip_scroll_group_store: Vec::new(),
                 clip_scroll_group_indices: FastHashMap::default(),
                 cmds: Vec::new(),
                 hit_testing_runs: Vec::new(),
                 packed_layers: Vec::new(),
                 shadow_prim_stack: Vec::new(),
+                pending_shadow_contents: Vec::new(),
                 scrollbar_prims: Vec::new(),
                 reference_frame_stack: Vec::new(),
                 stacking_context_stack: Vec::new(),
                 prim_store: PrimitiveStore::new(),
                 clip_store: ClipStore::new(),
                 screen_size,
                 background_color,
                 config,
@@ -586,40 +592,59 @@ impl FrameBuilder {
         info: &LayerPrimitiveInfo,
     ) {
         let prim = PicturePrimitive::new_shadow(shadow);
 
         // Create an empty shadow primitive. Insert it into
         // the draw lists immediately so that it will be drawn
         // before any visual text elements that are added as
         // part of this shadow context.
-        let prim_index = self.add_primitive(
+        let prim_index = self.create_primitive(
             clip_and_scroll,
             info,
             Vec::new(),
             PrimitiveContainer::Picture(prim),
         );
 
-        self.shadow_prim_stack.push(prim_index);
+        let pending = vec![(prim_index, clip_and_scroll)];
+        self.shadow_prim_stack.push((prim_index, pending));
     }
 
-    pub fn pop_shadow(&mut self) {
-        let prim_index = self.shadow_prim_stack
-            .pop()
-            .expect("invalid shadow push/pop count");
+    pub fn pop_all_shadows(&mut self) {
+        assert!(self.shadow_prim_stack.len() > 0, "popped shadows, but none were present");
+
+        // Borrowcheck dance
+        let mut shadows = mem::replace(&mut self.shadow_prim_stack, Vec::new());
+        for (prim_index, pending_primitives) in shadows.drain(..) {
+            {
+                // By now, the local rect of the text shadow has been calculated. It
+                // is calculated as the items in the shadow are added. It's now
+                // safe to offset the local rect by the offset of the shadow, which
+                // is then used when blitting the shadow to the final location.
+                let metadata = &mut self.prim_store.cpu_metadata[prim_index.0];
+                let prim = &self.prim_store.cpu_pictures[metadata.cpu_prim_index.0];
+                let shadow = prim.as_shadow();
 
-        // By now, the local rect of the text shadow has been calculated. It
-        // is calculated as the items in the shadow are added. It's now
-        // safe to offset the local rect by the offset of the shadow, which
-        // is then used when blitting the shadow to the final location.
-        let metadata = &mut self.prim_store.cpu_metadata[prim_index.0];
-        let prim = &self.prim_store.cpu_pictures[metadata.cpu_prim_index.0];
-        let shadow = prim.as_shadow();
+                metadata.local_rect = metadata.local_rect.translate(&shadow.offset);
+            }
+
+            // Push any fast-path shadows now
+            for (prim_index, clip_and_scroll) in pending_primitives {
+                self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
+            }
+        }
 
-        metadata.local_rect = metadata.local_rect.translate(&shadow.offset);
+        let mut pending_primitives = mem::replace(&mut self.pending_shadow_contents, Vec::new());
+        for (prim_index, clip_and_scroll, info) in pending_primitives.drain(..) {
+            self.add_primitive_to_hit_testing_list(&info, clip_and_scroll);
+            self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
+        }
+
+        mem::replace(&mut self.pending_shadow_contents, pending_primitives);
+        mem::replace(&mut self.shadow_prim_stack, shadows);
     }
 
     pub fn add_solid_rectangle(
         &mut self,
         clip_and_scroll: ClipAndScrollInfo,
         info: &LayerPrimitiveInfo,
         color: &ColorF,
         flags: PrimitiveFlags,
@@ -677,52 +702,58 @@ impl FrameBuilder {
 
         let line = LinePrimitive {
             color: *color,
             style: style,
             orientation: orientation,
         };
 
         let mut fast_shadow_prims = Vec::new();
-        for shadow_prim_index in &self.shadow_prim_stack {
+        for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() {
             let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0];
             let picture = &self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0];
             let shadow = picture.as_shadow();
             if shadow.blur_radius == 0.0 {
-                fast_shadow_prims.push(shadow.clone());
+                fast_shadow_prims.push((idx, shadow.clone()));
             }
         }
-        for shadow in fast_shadow_prims {
+
+        for (idx, shadow) in fast_shadow_prims {
             let mut line = line.clone();
             line.color = shadow.color;
             let mut info = info.clone();
             info.rect = new_rect.translate(&shadow.offset);
-            self.add_primitive(
+            let prim_index = self.create_primitive(
                 clip_and_scroll,
                 &info,
                 Vec::new(),
                 PrimitiveContainer::Line(line),
             );
+            self.shadow_prim_stack[idx].1.push((prim_index, clip_and_scroll));
         }
 
         let mut info = info.clone();
         info.rect = new_rect;
         let prim_index = self.create_primitive(
             clip_and_scroll,
             &info,
             Vec::new(),
             PrimitiveContainer::Line(line),
         );
 
         if color.a > 0.0 {
-            self.add_primitive_to_hit_testing_list(&info, clip_and_scroll);
-            self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
+            if self.shadow_prim_stack.is_empty() {
+                self.add_primitive_to_hit_testing_list(&info, clip_and_scroll);
+                self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
+            } else {
+                self.pending_shadow_contents.push((prim_index, clip_and_scroll, info));
+            }
         }
 
-        for shadow_prim_index in &self.shadow_prim_stack {
+        for &(shadow_prim_index, _) in &self.shadow_prim_stack {
             let shadow_metadata = &mut self.prim_store.cpu_metadata[shadow_prim_index.0];
             debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Picture);
             let picture =
                 &mut self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0];
             let blur_radius = picture.as_shadow().blur_radius;
 
             // Only run real blurs here (fast path zero blurs are handled above).
             if blur_radius > 0.0 {
@@ -1137,44 +1168,40 @@ impl FrameBuilder {
             .limit_by(font.render_mode);
         if let Some(options) = glyph_options {
             render_mode = render_mode.limit_by(options.render_mode);
         }
 
         // There are some conditions under which we can't use
         // subpixel text rendering, even if enabled.
         if render_mode == FontRenderMode::Subpixel {
-            if color.a != 1.0 {
-                render_mode = FontRenderMode::Alpha;
-            }
-
             // text on a stacking context that has filters
             // (e.g. opacity) can't use sub-pixel.
             // TODO(gw): It's possible we can relax this in
             //           the future, if we modify the way
             //           we handle subpixel blending.
             if let Some(sc_index) = self.stacking_context_stack.last() {
                 let stacking_context = &self.stacking_context_store[sc_index.0];
-                if stacking_context.composite_ops.count() > 0 {
+                if !stacking_context.allow_subpixel_aa {
                     render_mode = FontRenderMode::Alpha;
                 }
             }
         }
 
         let prim_font = FontInstance::new(
             font.font_key,
             font.size,
             *color,
             render_mode,
             font.subpx_dir,
             font.platform_options,
             font.variations.clone(),
             font.synthetic_italics,
         );
-        let prim = TextRunPrimitiveCpu {
+        let mut prim = TextRunPrimitiveCpu {
             font: prim_font,
             glyph_range,
             glyph_count,
             glyph_gpu_blocks: Vec::new(),
             glyph_keys: Vec::new(),
             offset: run_offset,
         };
 
@@ -1182,68 +1209,80 @@ impl FrameBuilder {
         // text elements to get pixel perfect results for reftests. It's also a big
         // performance win to avoid blurs and render target allocations where
         // possible. For any text shadows that have zero blur, create a normal text
         // primitive with the shadow's color and offset. These need to be added
         // *before* the visual text primitive in order to get the correct paint
         // order. Store them in a Vec first to work around borrowck issues.
         // TODO(gw): Refactor to avoid having to store them in a Vec first.
         let mut fast_shadow_prims = Vec::new();
-        for shadow_prim_index in &self.shadow_prim_stack {
+        for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() {
             let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0];
             let picture_prim = &self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0];
             let shadow = picture_prim.as_shadow();
             if shadow.blur_radius == 0.0 {
                 let mut text_prim = prim.clone();
                 text_prim.font.color = shadow.color.into();
                 // If we have translucent text, we need to ensure it won't go
                 // through the subpixel blend mode, which doesn't work with
                 // traditional alpha blending.
                 if shadow.color.a != 1.0 {
                     text_prim.font.render_mode = text_prim.font.render_mode.limit_by(FontRenderMode::Alpha);
                 }
                 text_prim.offset += shadow.offset;
-                fast_shadow_prims.push(text_prim);
+                fast_shadow_prims.push((idx, text_prim));
             }
         }
-        for text_prim in fast_shadow_prims {
+
+        for (idx, text_prim) in fast_shadow_prims {
             let rect = info.rect;
             let mut info = info.clone();
             info.rect = rect.translate(&text_prim.offset);
-            self.add_primitive(
+            let prim_index = self.create_primitive(
                 clip_and_scroll,
                 &info,
                 Vec::new(),
                 PrimitiveContainer::TextRun(text_prim),
             );
+            self.shadow_prim_stack[idx].1.push((prim_index, clip_and_scroll));
+        }
+
+        // We defer this until after fast-shadows so that shadows of transparent text
+        // get subpixel-aa
+        if color.a != 1.0 {
+            prim.font.render_mode = FontRenderMode::Alpha;
         }
 
         // Create (and add to primitive store) the primitive that will be
         // used for both the visual element and also the shadow(s).
         let prim_index = self.create_primitive(
             clip_and_scroll,
             info,
             Vec::new(),
             PrimitiveContainer::TextRun(prim),
         );
 
         // Only add a visual element if it can contribute to the scene.
         if color.a > 0.0 {
-            self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
-            self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
+            if self.shadow_prim_stack.is_empty() {
+                self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
+                self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
+            } else {
+                self.pending_shadow_contents.push((prim_index, clip_and_scroll, *info));
+            }
         }
 
         // Now add this primitive index to all the currently active text shadow
         // primitives. Although we're adding the indices *after* the visual
         // primitive here, they will still draw before the visual text, since
         // the shadow primitive itself has been added to the draw cmd
         // list *before* the visual element, during push_shadow. We need
         // the primitive index of the visual element here before we can add
         // the indices as sub-primitives to the shadow primitives.
-        for shadow_prim_index in &self.shadow_prim_stack {
+        for &(shadow_prim_index, _) in &self.shadow_prim_stack {
             let shadow_metadata = &mut self.prim_store.cpu_metadata[shadow_prim_index.0];
             debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Picture);
             let picture_prim =
                 &mut self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0];
 
             // Only run real blurs here (fast path zero blurs are handled above).
             let blur_radius = picture_prim.as_shadow().blur_radius;
             if blur_radius > 0.0 {
@@ -1726,30 +1765,41 @@ impl FrameBuilder {
                 &mut self.clip_store,
             ) {
                 stacking_context.screen_bounds = stacking_context
                     .screen_bounds
                     .union(&prim_geom.device_rect);
                 stacking_context.isolated_items_bounds = stacking_context
                     .isolated_items_bounds
                     .union(&prim_geom.local_rect);
+                stacking_context.has_any_primitive = true;
 
                 profile_counters.visible_primitives.inc();
             }
         }
 
         true //visible
     }
 
-    fn handle_pop_stacking_context(&mut self, screen_rect: &DeviceIntRect) {
+    fn handle_pop_stacking_context(
+        &mut self,
+        screen_rect: &DeviceIntRect,
+        clip_scroll_tree: &ClipScrollTree) {
         let stacking_context_index = self.stacking_context_stack.pop().unwrap();
 
         let (bounding_rect, is_visible, is_preserve_3d, reference_id, reference_bounds) = {
             let stacking_context =
                 &mut self.stacking_context_store[stacking_context_index.0];
+            if !stacking_context.has_any_primitive {
+                stacking_context.isolated_items_bounds = stacking_context.children_sc_bounds;
+            } else if stacking_context.isolation != ContextIsolation::Items {
+                stacking_context.isolated_items_bounds = stacking_context
+                    .isolated_items_bounds
+                    .union(&stacking_context.children_sc_bounds);
+            }
             stacking_context.screen_bounds = stacking_context
                 .screen_bounds
                 .intersection(screen_rect)
                 .unwrap_or(DeviceIntRect::zero());
             (
                 stacking_context.screen_bounds.clone(),
                 stacking_context.is_visible,
                 stacking_context.isolation == ContextIsolation::Items,
@@ -1758,19 +1808,31 @@ impl FrameBuilder {
                     .isolated_items_bounds
                     .translate(&stacking_context.reference_frame_offset),
             )
         };
 
         if let Some(ref mut parent_index) = self.stacking_context_stack.last_mut() {
             let parent = &mut self.stacking_context_store[parent_index.0];
             parent.screen_bounds = parent.screen_bounds.union(&bounding_rect);
+            let child_bounds = reference_bounds.translate(&-parent.reference_frame_offset);
+            let frame_node = clip_scroll_tree
+                .nodes
+                .get(&reference_id)
+                .unwrap();
+            let local_transform = match frame_node.node_type {
+                NodeType::ReferenceFrame(ref info) => info.transform,
+                _ => LayerToScrollTransform::identity(),
+            };
+            let transformed_bounds = local_transform
+                .with_destination::<LayerPixel>()
+                .transform_rect(&child_bounds);
+            parent.children_sc_bounds = parent.children_sc_bounds.union(&transformed_bounds);
             // add children local bounds only for non-item-isolated contexts
             if !is_preserve_3d && parent.reference_frame_id == reference_id {
-                let child_bounds = reference_bounds.translate(&-parent.reference_frame_offset);
                 parent.isolated_items_bounds = parent.isolated_items_bounds.union(&child_bounds);
             }
             // Per-primitive stacking context visibility checks do not take into account
             // visibility of child stacking contexts, so do that now.
             parent.is_visible = parent.is_visible || is_visible;
         }
     }
 
@@ -1912,17 +1974,17 @@ impl FrameBuilder {
                         pipelines,
                         clip_scroll_tree,
                         screen_rect,
                         device_pixel_ratio,
                         profile_counters,
                     );
                 }
                 PrimitiveRunCmd::PopStackingContext => {
-                    self.handle_pop_stacking_context(screen_rect);
+                    self.handle_pop_stacking_context(screen_rect, clip_scroll_tree);
                 }
             }
         }
 
         mem::replace(&mut self.cmds, commands);
     }
 
     fn update_scroll_bars(&mut self, clip_scroll_tree: &ClipScrollTree, gpu_cache: &mut GpuCache) {
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -710,12 +710,12 @@ impl ToDebugString for SpecificDisplayIt
             SpecificDisplayItem::PushStackingContext(..) => String::from("push_stacking_context"),
             SpecificDisplayItem::Iframe(..) => String::from("iframe"),
             SpecificDisplayItem::Clip(..) => String::from("clip"),
             SpecificDisplayItem::ScrollFrame(..) => String::from("scroll_frame"),
             SpecificDisplayItem::StickyFrame(..) => String::from("sticky_frame"),
             SpecificDisplayItem::SetGradientStops => String::from("set_gradient_stops"),
             SpecificDisplayItem::PopStackingContext => String::from("pop_stacking_context"),
             SpecificDisplayItem::PushShadow(..) => String::from("push_shadow"),
-            SpecificDisplayItem::PopShadow => String::from("pop_shadow"),
+            SpecificDisplayItem::PopAllShadows => String::from("pop_all_shadows"),
         }
     }
 }
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -5,17 +5,17 @@
 //! The webrender API.
 //!
 //! The `webrender::renderer` module provides the interface to webrender, which
 //! is accessible through [`Renderer`][renderer]
 //!
 //! [renderer]: struct.Renderer.html
 
 use api::{channel, BlobImageRenderer, FontRenderMode};
-use api::{ColorF, ColorU, Epoch, PipelineId, RenderApiSender, RenderNotifier};
+use api::{ColorF, Epoch, PipelineId, RenderApiSender, RenderNotifier};
 use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintRect, DeviceUintSize};
 use api::{ExternalImageId, ExternalImageType, ImageFormat};
 use api::{YUV_COLOR_SPACES, YUV_FORMATS};
 use api::{YuvColorSpace, YuvFormat};
 #[cfg(not(feature = "debugger"))]
 use api::ApiMsg;
 use api::DebugCommand;
 #[cfg(not(feature = "debugger"))]
@@ -209,16 +209,33 @@ bitflags! {
     pub struct DebugFlags: u32 {
         const PROFILER_DBG      = 1 << 0;
         const RENDER_TARGET_DBG = 1 << 1;
         const TEXTURE_CACHE_DBG = 1 << 2;
         const ALPHA_PRIM_DBG    = 1 << 3;
     }
 }
 
+// A generic mode that can be passed to shaders to change
+// behaviour per draw-call.
+type ShaderMode = i32;
+
+#[repr(C)]
+enum TextShaderMode {
+    Alpha = 0,
+    SubpixelPass0 = 1,
+    SubpixelPass1 = 2,
+}
+
+impl Into<ShaderMode> for TextShaderMode {
+    fn into(self) -> i32 {
+        self as i32
+    }
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 enum TextureSampler {
     Color0,
     Color1,
     Color2,
     CacheA8,
     CacheRGBA8,
     ResourceCache,
@@ -620,19 +637,17 @@ impl SourceTextureResolver {
     }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub enum BlendMode {
     None,
     Alpha,
     PremultipliedAlpha,
-
-    // Use the color of the text itself as a constant color blend factor.
-    Subpixel(ColorU),
+    Subpixel,
 }
 
 // Tracks the state of each row in the GPU cache texture.
 struct CacheRow {
     is_dirty: bool,
 }
 
 impl CacheRow {
@@ -838,17 +853,16 @@ impl VertexDataTexture {
 
     fn deinit(self, device: &mut Device) {
         device.delete_pbo(self.pbo);
         device.delete_texture(self.texture);
     }
 }
 
 const TRANSFORM_FEATURE: &str = "TRANSFORM";
-const SUBPIXEL_AA_FEATURE: &str = "SUBPIXEL_AA";
 const CLIP_FEATURE: &str = "CLIP";
 
 enum ShaderKind {
     Primitive,
     Cache(VertexArrayKind),
     ClipCache,
 }
 
@@ -876,31 +890,32 @@ impl LazilyCompiledShader {
 
         if precache {
             try!{ shader.get(device) };
         }
 
         Ok(shader)
     }
 
-    fn bind(
+    fn bind<M>(
         &mut self,
         device: &mut Device,
         projection: &Transform3D<f32>,
+        mode: M,
         renderer_errors: &mut Vec<RendererError>,
-    ) {
+    ) where M: Into<ShaderMode> {
         let program = match self.get(device) {
             Ok(program) => program,
             Err(e) => {
                 renderer_errors.push(RendererError::from(e));
                 return;
             }
         };
         device.bind_program(program);
-        device.set_uniforms(program, projection);
+        device.set_uniforms(program, projection, mode.into());
     }
 
     fn get(&mut self, device: &mut Device) -> Result<&Program, ShaderError> {
         if self.program.is_none() {
             let program = try!{
                 match self.kind {
                     ShaderKind::Primitive => {
                         create_prim_shader(self.name,
@@ -979,29 +994,30 @@ impl PrimitiveShader {
                                       &transform_features,
                                       device,
                                       precache)
         };
 
         Ok(PrimitiveShader { simple, transform })
     }
 
-    fn bind(
+    fn bind<M>(
         &mut self,
         device: &mut Device,
         transform_kind: TransformedRectKind,
         projection: &Transform3D<f32>,
+        mode: M,
         renderer_errors: &mut Vec<RendererError>,
-    ) {
+    ) where M: Into<ShaderMode> {
         match transform_kind {
             TransformedRectKind::AxisAligned => {
-                self.simple.bind(device, projection, renderer_errors)
+                self.simple.bind(device, projection, mode, renderer_errors)
             }
             TransformedRectKind::Complex => {
-                self.transform.bind(device, projection, renderer_errors)
+                self.transform.bind(device, projection, mode, renderer_errors)
             }
         }
     }
 
     fn deinit(self, device: &mut Device) {
         self.simple.deinit(device);
         self.transform.deinit(device);
     }
@@ -1123,17 +1139,16 @@ pub struct Renderer {
     // Most draw directly to the framebuffer, but some use inputs
     // from the cache shaders to draw. Specifically, the box
     // shadow primitive shader stretches the box shadow cache
     // output, and the cache_image shader blits the results of
     // a cache shader (e.g. blur) to the screen.
     ps_rectangle: PrimitiveShader,
     ps_rectangle_clip: PrimitiveShader,
     ps_text_run: PrimitiveShader,
-    ps_text_run_subpixel: PrimitiveShader,
     ps_image: Vec<Option<PrimitiveShader>>,
     ps_yuv_image: Vec<Option<PrimitiveShader>>,
     ps_border_corner: PrimitiveShader,
     ps_border_edge: PrimitiveShader,
     ps_gradient: PrimitiveShader,
     ps_angle_gradient: PrimitiveShader,
     ps_radial_gradient: PrimitiveShader,
     ps_box_shadow: PrimitiveShader,
@@ -1368,23 +1383,16 @@ impl Renderer {
 
         let ps_text_run = try!{
             PrimitiveShader::new("ps_text_run",
                                  &mut device,
                                  &[],
                                  options.precache_shaders)
         };
 
-        let ps_text_run_subpixel = try!{
-            PrimitiveShader::new("ps_text_run",
-                                 &mut device,
-                                 &[ SUBPIXEL_AA_FEATURE ],
-                                 options.precache_shaders)
-        };
-
         // All image configuration.
         let mut image_features = Vec::new();
         let mut ps_image: Vec<Option<PrimitiveShader>> = Vec::new();
         // PrimitiveShader is not clonable. Use push() to initialize the vec.
         for _ in 0 .. IMAGE_BUFFER_KINDS.len() {
             ps_image.push(None);
         }
         for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() {
@@ -1730,17 +1738,16 @@ impl Renderer {
             cs_line,
             cs_blur,
             cs_clip_rectangle,
             cs_clip_border,
             cs_clip_image,
             ps_rectangle,
             ps_rectangle_clip,
             ps_text_run,
-            ps_text_run_subpixel,
             ps_image,
             ps_yuv_image,
             ps_border_corner,
             ps_border_edge,
             ps_box_shadow,
             ps_gradient,
             ps_angle_gradient,
             ps_radial_gradient,
@@ -2337,180 +2344,175 @@ impl Renderer {
         projection: &Transform3D<f32>,
         render_tasks: &RenderTaskTree,
         render_target: Option<(&Texture, i32)>,
         target_dimensions: DeviceUintSize,
     ) {
         let marker = match key.kind {
             BatchKind::Composite { .. } => {
                 self.ps_composite
-                    .bind(&mut self.device, projection, &mut self.renderer_errors);
+                    .bind(&mut self.device, projection, 0, &mut self.renderer_errors);
                 GPU_TAG_PRIM_COMPOSITE
             }
             BatchKind::HardwareComposite => {
                 self.ps_hw_composite
-                    .bind(&mut self.device, projection, &mut self.renderer_errors);
+                    .bind(&mut self.device, projection, 0, &mut self.renderer_errors);
                 GPU_TAG_PRIM_HW_COMPOSITE
             }
             BatchKind::SplitComposite => {
                 self.ps_split_composite.bind(
                     &mut self.device,
                     projection,
+                    0,
                     &mut self.renderer_errors,
                 );
                 GPU_TAG_PRIM_SPLIT_COMPOSITE
             }
             BatchKind::Blend => {
                 self.ps_blend
-                    .bind(&mut self.device, projection, &mut self.renderer_errors);
+                    .bind(&mut self.device, projection, 0, &mut self.renderer_errors);
                 GPU_TAG_PRIM_BLEND
             }
             BatchKind::Transformable(transform_kind, batch_kind) => match batch_kind {
                 TransformBatchKind::Rectangle(needs_clipping) => {
                     debug_assert!(
                         !needs_clipping || match key.blend_mode {
                             BlendMode::Alpha |
                             BlendMode::PremultipliedAlpha |
-                            BlendMode::Subpixel(..) => true,
+                            BlendMode::Subpixel => true,
                             BlendMode::None => false,
                         }
                     );
 
                     if needs_clipping {
                         self.ps_rectangle_clip.bind(
                             &mut self.device,
                             transform_kind,
                             projection,
+                            0,
                             &mut self.renderer_errors,
                         );
                     } else {
                         self.ps_rectangle.bind(
                             &mut self.device,
                             transform_kind,
                             projection,
+                            0,
                             &mut self.renderer_errors,
                         );
                     }
                     GPU_TAG_PRIM_RECT
                 }
                 TransformBatchKind::Line => {
                     self.ps_line.bind(
                         &mut self.device,
                         transform_kind,
                         projection,
+                        0,
                         &mut self.renderer_errors,
                     );
                     GPU_TAG_PRIM_LINE
                 }
                 TransformBatchKind::TextRun => {
-                    match key.blend_mode {
-                        BlendMode::Subpixel(..) => {
-                            self.ps_text_run_subpixel.bind(
-                                &mut self.device,
-                                transform_kind,
-                                projection,
-                                &mut self.renderer_errors,
-                            );
-                        }
-                        BlendMode::Alpha | BlendMode::PremultipliedAlpha | BlendMode::None => {
-                            self.ps_text_run.bind(
-                                &mut self.device,
-                                transform_kind,
-                                projection,
-                                &mut self.renderer_errors,
-                            );
-                        }
-                    };
-                    GPU_TAG_PRIM_TEXT_RUN
+                    unreachable!("bug: text batches are special cased");
                 }
                 TransformBatchKind::Image(image_buffer_kind) => {
                     self.ps_image[image_buffer_kind as usize]
                         .as_mut()
                         .expect("Unsupported image shader kind")
                         .bind(
                             &mut self.device,
                             transform_kind,
                             projection,
+                            0,
                             &mut self.renderer_errors,
                         );
                     GPU_TAG_PRIM_IMAGE
                 }
                 TransformBatchKind::YuvImage(image_buffer_kind, format, color_space) => {
                     let shader_index =
                         Renderer::get_yuv_shader_index(image_buffer_kind, format, color_space);
                     self.ps_yuv_image[shader_index]
                         .as_mut()
                         .expect("Unsupported YUV shader kind")
                         .bind(
                             &mut self.device,
                             transform_kind,
                             projection,
+                            0,
                             &mut self.renderer_errors,
                         );
                     GPU_TAG_PRIM_YUV_IMAGE
                 }
                 TransformBatchKind::BorderCorner => {
                     self.ps_border_corner.bind(
                         &mut self.device,
                         transform_kind,
                         projection,
+                        0,
                         &mut self.renderer_errors,
                     );
                     GPU_TAG_PRIM_BORDER_CORNER
                 }
                 TransformBatchKind::BorderEdge => {
                     self.ps_border_edge.bind(
                         &mut self.device,
                         transform_kind,
                         projection,
+                        0,
                         &mut self.renderer_errors,
                     );
                     GPU_TAG_PRIM_BORDER_EDGE
                 }
                 TransformBatchKind::AlignedGradient => {
                     self.ps_gradient.bind(
                         &mut self.device,
                         transform_kind,
                         projection,
+                        0,
                         &mut self.renderer_errors,
                     );
                     GPU_TAG_PRIM_GRADIENT
                 }
                 TransformBatchKind::AngleGradient => {
                     self.ps_angle_gradient.bind(
                         &mut self.device,
                         transform_kind,
                         projection,
+                        0,
                         &mut self.renderer_errors,
                     );
                     GPU_TAG_PRIM_ANGLE_GRADIENT
                 }
                 TransformBatchKind::RadialGradient => {
                     self.ps_radial_gradient.bind(
                         &mut self.device,
                         transform_kind,
                         projection,
+                        0,
                         &mut self.renderer_errors,
                     );
                     GPU_TAG_PRIM_RADIAL_GRADIENT
                 }
                 TransformBatchKind::BoxShadow => {
                     self.ps_box_shadow.bind(
                         &mut self.device,
                         transform_kind,
                         projection,
+                        0,
                         &mut self.renderer_errors,
                     );
                     GPU_TAG_PRIM_BOX_SHADOW
                 }
                 TransformBatchKind::CacheImage => {
                     self.ps_cache_image.bind(
                         &mut self.device,
                         transform_kind,
                         projection,
+                        0,
                         &mut self.renderer_errors,
                     );
                     GPU_TAG_PRIM_CACHE_IMAGE
                 }
             },
         };
 
         // Handle special case readback for composites.
@@ -2633,17 +2635,17 @@ impl Renderer {
         // TODO(gw): In the future, consider having
         //           fast path blur shaders for common
         //           blur radii with fixed weights.
         if !target.vertical_blurs.is_empty() || !target.horizontal_blurs.is_empty() {
             let _gm = self.gpu_profile.add_marker(GPU_TAG_BLUR);
 
             self.device.set_blend(false);
             self.cs_blur
-                .bind(&mut self.device, projection, &mut self.renderer_errors);
+                .bind(&mut self.device, projection, 0, &mut self.renderer_errors);
 
             if !target.vertical_blurs.is_empty() {
                 self.draw_instanced_batch(
                     &target.vertical_blurs,
                     VertexArrayKind::Blur,
                     &BatchTextures::no_texture(),
                 );
             }
@@ -2664,34 +2666,34 @@ impl Renderer {
         // it removes the overhead of submitting many small glyphs
         // to multiple tiles in the normal text run case.
         if !target.text_run_cache_prims.is_empty() {
             self.device.set_blend(true);
             self.device.set_blend_mode_alpha();
 
             let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_TEXT_RUN);
             self.cs_text_run
-                .bind(&mut self.device, projection, &mut self.renderer_errors);
+                .bind(&mut self.device, projection, 0, &mut self.renderer_errors);
             for (texture_id, instances) in &target.text_run_cache_prims {
                 self.draw_instanced_batch(
                     instances,
                     VertexArrayKind::Primitive,
                     &BatchTextures::color(*texture_id),
                 );
             }
         }
         if !target.line_cache_prims.is_empty() {
             // TODO(gw): Technically, we don't need blend for solid
             //           lines. We could check that here?
             self.device.set_blend(true);
             self.device.set_blend_mode_alpha();
 
             let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_LINE);
             self.cs_line
-                .bind(&mut self.device, projection, &mut self.renderer_errors);
+                .bind(&mut self.device, projection, 0, &mut self.renderer_errors);
             self.draw_instanced_batch(
                 &target.line_cache_prims,
                 VertexArrayKind::Primitive,
                 &BatchTextures::no_texture(),
             );
         }
 
         //TODO: record the pixel count for cached primitives
@@ -2727,57 +2729,136 @@ impl Renderer {
                     target_size,
                 );
             }
 
             self.device.disable_depth_write();
             self.gpu_profile.add_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
 
             for batch in &target.alpha_batcher.batch_list.alpha_batch_list.batches {
-                if batch.key.blend_mode != prev_blend_mode {
-                    match batch.key.blend_mode {
-                        BlendMode::None => {
-                            self.device.set_blend(false);
-                        }
-                        BlendMode::Alpha => {
-                            self.device.set_blend(true);
-                            self.device.set_blend_mode_alpha();
-                        }
-                        BlendMode::PremultipliedAlpha => {
-                            self.device.set_blend(true);
-                            self.device.set_blend_mode_premultiplied_alpha();
-                        }
-                        BlendMode::Subpixel(color) => {
-                            self.device.set_blend(true);
-                            self.device.set_blend_mode_subpixel(color.into());
-                        }
-                    }
-                    prev_blend_mode = batch.key.blend_mode;
-                }
-
                 if self.debug_flags.contains(ALPHA_PRIM_DBG) {
                     let color = match batch.key.blend_mode {
                         BlendMode::None => ColorF::new(0.3, 0.3, 0.3, 1.0),
                         BlendMode::Alpha => ColorF::new(0.0, 0.9, 0.1, 1.0),
                         BlendMode::PremultipliedAlpha => ColorF::new(0.0, 0.3, 0.7, 1.0),
-                        BlendMode::Subpixel(_) => ColorF::new(0.5, 0.0, 0.4, 1.0),
+                        BlendMode::Subpixel => ColorF::new(0.5, 0.0, 0.4, 1.0),
                     }.into();
                     for item_rect in &batch.item_rects {
                         self.debug.add_rect(item_rect, color);
                     }
                 }
 
-                self.submit_batch(
-                    &batch.key,
-                    &batch.instances,
-                    &projection,
-                    render_tasks,
-                    render_target,
-                    target_size,
-                );
+                match batch.key.kind {
+                    BatchKind::Transformable(transform_kind, TransformBatchKind::TextRun) => {
+                        // Text run batches are handled by this special case branch.
+                        // In the case of subpixel text, we draw it as a two pass
+                        // effect, to ensure we can apply clip masks correctly.
+                        // In the future, there are several optimizations available:
+                        // 1) Use dual source blending where available (almost all recent hardware).
+                        // 2) Use frame buffer fetch where available (most modern hardware).
+                        // 3) Consider the old constant color blend method where no clip is applied.
+                        let _gm = self.gpu_profile.add_marker(GPU_TAG_PRIM_TEXT_RUN);
+
+                        self.device.set_blend(true);
+
+                        match batch.key.blend_mode {
+                            BlendMode::PremultipliedAlpha => {
+                                self.device.set_blend_mode_premultiplied_alpha();
+
+                                self.ps_text_run.bind(
+                                    &mut self.device,
+                                    transform_kind,
+                                    projection,
+                                    TextShaderMode::Alpha,
+                                    &mut self.renderer_errors,
+                                );
+
+                                self.draw_instanced_batch(
+                                    &batch.instances,
+                                    VertexArrayKind::Primitive,
+                                    &batch.key.textures
+                                );
+                            }
+                            BlendMode::Subpixel => {
+                                // Using the two pass component alpha rendering technique:
+                                //
+                                // http://anholt.livejournal.com/32058.html
+                                //
+                                self.device.set_blend_mode_subpixel_pass0();
+
+                                self.ps_text_run.bind(
+                                    &mut self.device,
+                                    transform_kind,
+                                    projection,
+                                    TextShaderMode::SubpixelPass0,
+                                    &mut self.renderer_errors,
+                                );
+
+                                self.draw_instanced_batch(
+                                    &batch.instances,
+                                    VertexArrayKind::Primitive,
+                                    &batch.key.textures
+                                );
+
+                                self.device.set_blend_mode_subpixel_pass1();
+
+                                self.ps_text_run.bind(
+                                    &mut self.device,
+                                    transform_kind,
+                                    projection,
+                                    TextShaderMode::SubpixelPass1,
+                                    &mut self.renderer_errors,
+                                );
+
+                                // When drawing the 2nd pass, we know that the VAO, textures etc
+                                // are all set up from the previous draw_instanced_batch call,
+                                // so just issue a draw call here to avoid re-uploading the
+                                // instances and re-binding textures etc.
+                                self.device
+                                    .draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
+                            }
+                            BlendMode::Alpha | BlendMode::None => {
+                                unreachable!("bug: bad blend mode for text");
+                            }
+                        }
+
+                        prev_blend_mode = BlendMode::None;
+                        self.device.set_blend(false);
+                    }
+                    _ => {
+                        if batch.key.blend_mode != prev_blend_mode {
+                            match batch.key.blend_mode {
+                                BlendMode::None => {
+                                    self.device.set_blend(false);
+                                }
+                                BlendMode::Alpha => {
+                                    self.device.set_blend(true);
+                                    self.device.set_blend_mode_alpha();
+                                }
+                                BlendMode::PremultipliedAlpha => {
+                                    self.device.set_blend(true);
+                                    self.device.set_blend_mode_premultiplied_alpha();
+                                }
+                                BlendMode::Subpixel => {
+                                    unreachable!("bug: subpx text handled earlier");
+                                }
+                            }
+                            prev_blend_mode = batch.key.blend_mode;
+                        }
+
+                        self.submit_batch(
+                            &batch.key,
+                            &batch.instances,
+                            &projection,
+                            render_tasks,
+                            render_target,
+                            target_size,
+                        );
+                    }
+                }
             }
 
             self.device.disable_depth();
             self.device.set_blend(false);
             self.gpu_profile.done_sampler();
         }
 
         // For any registered image outputs on this render target,
@@ -2840,17 +2921,17 @@ impl Renderer {
                 .clear_target_rect(Some(clear_color), None, target.used_rect());
         }
 
         // Draw any box-shadow caches for this target.
         if !target.box_shadow_cache_prims.is_empty() {
             self.device.set_blend(false);
             let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_BOX_SHADOW);
             self.cs_box_shadow
-                .bind(&mut self.device, projection, &mut self.renderer_errors);
+                .bind(&mut self.device, projection, 0, &mut self.renderer_errors);
             self.draw_instanced_batch(
                 &target.box_shadow_cache_prims,
                 VertexArrayKind::CacheBoxShadow,
                 &BatchTextures::no_texture(),
             );
         }
 
         // Draw the clip items into the tiled alpha mask.
@@ -2859,17 +2940,17 @@ impl Renderer {
 
             // If we have border corner clips, the first step is to clear out the
             // area in the clip mask. This allows drawing multiple invididual clip
             // in regions below.
             if !target.clip_batcher.border_clears.is_empty() {
                 let _gm2 = GpuMarker::new(self.device.rc_gl(), "clip borders [clear]");
                 self.device.set_blend(false);
                 self.cs_clip_border
-                    .bind(&mut self.device, projection, &mut self.renderer_errors);
+                    .bind(&mut self.device, projection, 0, &mut self.renderer_errors);
                 self.draw_instanced_batch(
                     &target.clip_batcher.border_clears,
                     VertexArrayKind::Clip,
                     &BatchTextures::no_texture(),
                 );
             }
 
             // Draw any dots or dashes for border corners.
@@ -2877,17 +2958,17 @@ impl Renderer {
                 let _gm2 = GpuMarker::new(self.device.rc_gl(), "clip borders");
                 // We are masking in parts of the corner (dots or dashes) here.
                 // Blend mode is set to max to allow drawing multiple dots.
                 // The individual dots and dashes in a border never overlap, so using
                 // a max blend mode here is fine.
                 self.device.set_blend(true);
                 self.device.set_blend_mode_max();
                 self.cs_clip_border
-                    .bind(&mut self.device, projection, &mut self.renderer_errors);
+                    .bind(&mut self.device, projection, 0, &mut self.renderer_errors);
                 self.draw_instanced_batch(
                     &target.clip_batcher.borders,
                     VertexArrayKind::Clip,
                     &BatchTextures::no_texture(),
                 );
             }
 
             // switch to multiplicative blending
@@ -2895,16 +2976,17 @@ impl Renderer {
             self.device.set_blend_mode_multiply();
 
             // draw rounded cornered rectangles
             if !target.clip_batcher.rectangles.is_empty() {
                 let _gm2 = GpuMarker::new(self.device.rc_gl(), "clip rectangles");
                 self.cs_clip_rectangle.bind(
                     &mut self.device,
                     projection,
+                    0,
                     &mut self.renderer_errors,
                 );
                 self.draw_instanced_batch(
                     &target.clip_batcher.rectangles,
                     VertexArrayKind::Clip,
                     &BatchTextures::no_texture(),
                 );
             }
@@ -2914,17 +2996,17 @@ impl Renderer {
                 let textures = BatchTextures {
                     colors: [
                         mask_texture_id.clone(),
                         SourceTexture::Invalid,
                         SourceTexture::Invalid,
                     ],
                 };
                 self.cs_clip_image
-                    .bind(&mut self.device, projection, &mut self.renderer_errors);
+                    .bind(&mut self.device, projection, 0, &mut self.renderer_errors);
                 self.draw_instanced_batch(items, VertexArrayKind::Clip, &textures);
             }
         }
 
         self.gpu_profile.done_sampler();
     }
 
     fn update_deferred_resolves(&mut self, frame: &mut Frame) {
@@ -3398,17 +3480,16 @@ impl Renderer {
         self.cs_line.deinit(&mut self.device);
         self.cs_blur.deinit(&mut self.device);
         self.cs_clip_rectangle.deinit(&mut self.device);
         self.cs_clip_image.deinit(&mut self.device);
         self.cs_clip_border.deinit(&mut self.device);
         self.ps_rectangle.deinit(&mut self.device);
         self.ps_rectangle_clip.deinit(&mut self.device);
         self.ps_text_run.deinit(&mut self.device);
-        self.ps_text_run_subpixel.deinit(&mut self.device);
         for shader in self.ps_image {
             if let Some(shader) = shader {
                 shader.deinit(&mut self.device);
             }
         }
         for shader in self.ps_yuv_image {
             if let Some(shader) = shader {
                 shader.deinit(&mut self.device);
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -50,17 +50,17 @@ impl AlphaBatchHelpers for PrimitiveStor
     ) -> BlendMode {
         let needs_blending = !metadata.opacity.is_opaque || metadata.clip_task_id.is_some() ||
             transform_kind == TransformedRectKind::Complex;
 
         match metadata.prim_kind {
             PrimitiveKind::TextRun => {
                 let text_run_cpu = &self.cpu_text_runs[metadata.cpu_prim_index.0];
                 match text_run_cpu.font.render_mode {
-                    FontRenderMode::Subpixel => BlendMode::Subpixel(text_run_cpu.font.color),
+                    FontRenderMode::Subpixel => BlendMode::Subpixel,
                     FontRenderMode::Alpha |
                     FontRenderMode::Mono |
                     FontRenderMode::Bitmap => BlendMode::PremultipliedAlpha,
                 }
             }
             PrimitiveKind::Image |
             PrimitiveKind::AlignedGradient |
             PrimitiveKind::AngleGradient |
@@ -124,36 +124,59 @@ impl AlphaBatchList {
 
     fn get_suitable_batch(
         &mut self,
         key: BatchKey,
         item_bounding_rect: &DeviceIntRect,
     ) -> &mut Vec<PrimitiveInstance> {
         let mut selected_batch_index = None;
 
-        // Composites always get added to their own batch.
-        // This is because the result of a composite can affect
-        // the input to the next composite. Perhaps we can
-        // optimize this in the future.
         match key.kind {
-            BatchKind::Composite { .. } => {}
-            _ => 'outer: for (batch_index, batch) in self.batches.iter().enumerate().rev().take(10)
-            {
-                if batch.key.is_compatible_with(&key) {
-                    selected_batch_index = Some(batch_index);
-                    break;
-                }
+            BatchKind::Composite { .. } => {
+                // Composites always get added to their own batch.
+                // This is because the result of a composite can affect
+                // the input to the next composite. Perhaps we can
+                // optimize this in the future.
+            }
+            BatchKind::Transformable(_, TransformBatchKind::TextRun) => {
+                'outer_text: for (batch_index, batch) in self.batches.iter().enumerate().rev().take(10) {
+                    // Subpixel text is drawn in two passes. Because of this, we need
+                    // to check for overlaps with every batch (which is a bit different
+                    // than the normal batching below).
+                    for item_rect in &batch.item_rects {
+                        if item_rect.intersects(item_bounding_rect) {
+                            break 'outer_text;
+                        }
+                    }
 
-                // check for intersections
-                for item_rect in &batch.item_rects {
-                    if item_rect.intersects(item_bounding_rect) {
-                        break 'outer;
+                    if batch.key.is_compatible_with(&key) {
+                        selected_batch_index = Some(batch_index);
+                        break;
                     }
                 }
-            },
+            }
+            _ => {
+                'outer_default: for (batch_index, batch) in self.batches.iter().enumerate().rev().take(10) {
+                    // For normal batches, we only need to check for overlaps for batches
+                    // other than the first batch we consider. If the first batch
+                    // is compatible, then we know there isn't any potential overlap
+                    // issues to worry about.
+                    if batch.key.is_compatible_with(&key) {
+                        selected_batch_index = Some(batch_index);
+                        break;
+                    }
+
+                    // check for intersections
+                    for item_rect in &batch.item_rects {
+                        if item_rect.intersects(item_bounding_rect) {
+                            break 'outer_default;
+                        }
+                    }
+                }
+            }
         }
 
         if selected_batch_index.is_none() {
             let new_batch = AlphaPrimitiveBatch::new(key);
             selected_batch_index = Some(self.batches.len());
             self.batches.push(new_batch);
         }
 
@@ -224,17 +247,17 @@ impl BatchList {
 
     fn get_suitable_batch(
         &mut self,
         key: BatchKey,
         item_bounding_rect: &DeviceIntRect,
     ) -> &mut Vec<PrimitiveInstance> {
         match key.blend_mode {
             BlendMode::None => self.opaque_batch_list.get_suitable_batch(key),
-            BlendMode::Alpha | BlendMode::PremultipliedAlpha | BlendMode::Subpixel(..) => {
+            BlendMode::Alpha | BlendMode::PremultipliedAlpha | BlendMode::Subpixel => {
                 self.alpha_batch_list
                     .get_suitable_batch(key, item_bounding_rect)
             }
         }
     }
 
     fn finalize(&mut self) {
         self.opaque_batch_list.finalize()
@@ -1596,16 +1619,27 @@ pub struct StackingContext {
     pub is_pipeline_root: bool,
 
     /// Whether or not this stacking context has any visible components, calculated
     /// based on the size and position of all children and how they are clipped.
     pub is_visible: bool,
 
     /// Current stacking context visibility of backface.
     pub is_backface_visible: bool,
+
+    /// Allow subpixel AA for text runs on this stacking context.
+    /// This is a temporary hack while we don't support subpixel AA
+    /// on transparent stacking contexts.
+    pub allow_subpixel_aa: bool,
+
+    /// Indicate that if any pritimive contained in this stacking context.
+    pub has_any_primitive: bool,
+
+    /// Union of all stacking context bounds of all children.
+    pub children_sc_bounds: LayerRect,
 }
 
 impl StackingContext {
     pub fn new(
         pipeline_id: PipelineId,
         reference_frame_offset: LayerVector2D,
         is_page_root: bool,
         is_pipeline_root: bool,
@@ -1613,28 +1647,33 @@ impl StackingContext {
         transform_style: TransformStyle,
         composite_ops: CompositeOps,
         is_backface_visible: bool,
     ) -> StackingContext {
         let isolation = match transform_style {
             TransformStyle::Flat => ContextIsolation::None,
             TransformStyle::Preserve3D => ContextIsolation::Items,
         };
+        let allow_subpixel_aa = composite_ops.count() == 0 &&
+                                isolation == ContextIsolation::None;
         StackingContext {
             pipeline_id,
             reference_frame_offset,
             reference_frame_id,
             screen_bounds: DeviceIntRect::zero(),
             isolated_items_bounds: LayerRect::zero(),
             composite_ops,
             isolation,
             is_page_root,
             is_pipeline_root,
             is_visible: false,
             is_backface_visible,
+            allow_subpixel_aa,
+            has_any_primitive: false,
+            children_sc_bounds: LayerRect::zero(),
         }
     }
 
     pub fn can_contribute_to_scene(&self) -> bool {
         !self.composite_ops.will_make_invisible()
     }
 }
 
--- a/gfx/webrender/tests/angle_shader_validation.rs
+++ b/gfx/webrender/tests/angle_shader_validation.rs
@@ -99,17 +99,17 @@ const SHADERS: &[Shader] = &[
         features: PRIM_FEATURES,
     },
     Shader {
         name: "ps_yuv_image",
         features: PRIM_FEATURES,
     },
     Shader {
         name: "ps_text_run",
-        features: &["", "TRANSFORM", "SUBPIXEL_AA_FEATURE"],
+        features: PRIM_FEATURES,
     },
     Shader {
         name: "ps_rectangle",
         features: &["", "TRANSFORM", "CLIP_FEATURE", "TRANSFORM,CLIP_FEATURE"],
     },
 ];
 
 const VERSION_STRING: &str = "#version 300 es\n";
--- a/gfx/webrender_api/Cargo.toml
+++ b/gfx/webrender_api/Cargo.toml
@@ -6,22 +6,22 @@ license = "MPL-2.0"
 repository = "https://github.com/servo/webrender"
 
 [features]
 nightly = ["euclid/unstable", "serde/unstable"]
 ipc = ["ipc-channel"]
 
 [dependencies]
 app_units = "0.5.6"
-bincode = "0.8"
+bincode = "0.9"
 bitflags = "0.9"
 byteorder = "1.0"
 euclid = "0.15"
 heapsize = ">= 0.3.6, < 0.5"
-ipc-channel = {version = "0.8", optional = true}
+ipc-channel = {version = "0.9", optional = true}
 serde = { version = "1.0", features = ["rc", "derive"] }
 time = "0.1"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.4"
 core-graphics = "0.9"
 
 [target.'cfg(target_os = "windows")'.dependencies]
--- a/gfx/webrender_api/src/display_item.rs
+++ b/gfx/webrender_api/src/display_item.rs
@@ -98,23 +98,22 @@ pub enum SpecificDisplayItem {
     BoxShadow(BoxShadowDisplayItem),
     Gradient(GradientDisplayItem),
     RadialGradient(RadialGradientDisplayItem),
     Iframe(IframeDisplayItem),
     PushStackingContext(PushStackingContextDisplayItem),
     PopStackingContext,
     SetGradientStops,
     PushShadow(Shadow),
-    PopShadow,
+    PopAllShadows,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ClipDisplayItem {
     pub id: ClipId,
-    pub parent_id: ClipId,
     pub image_mask: Option<ImageMask>,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct StickyFrameDisplayItem {
     pub id: ClipId,
     pub sticky_frame_info: StickyFrameInfo,
 }
@@ -132,17 +131,16 @@ pub struct StickySideConstraint {
 pub enum ScrollSensitivity {
     ScriptAndInputEvents,
     Script,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ScrollFrameDisplayItem {
     pub id: ClipId,
-    pub parent_id: ClipId,
     pub image_mask: Option<ImageMask>,
     pub scroll_sensitivity: ScrollSensitivity,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct RectangleDisplayItem {
     pub color: ColorF,
 }
--- a/gfx/webrender_api/src/display_list.rs
+++ b/gfx/webrender_api/src/display_list.rs
@@ -12,19 +12,20 @@ use {LineDisplayItem, LineOrientation, L
 use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
 use {RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity};
 use {SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, StickyFrameInfo};
 use {TextDisplayItem, Shadow, TransformStyle, YuvColorSpace, YuvData};
 use YuvImageDisplayItem;
 use bincode;
 use serde::{Deserialize, Serialize, Serializer};
 use serde::ser::{SerializeMap, SerializeSeq};
-use std::io::Write;
+use std::io::{Read, Write};
 use std::{io, ptr};
 use std::marker::PhantomData;
+use std::slice;
 use time::precise_time_ns;
 
 // We don't want to push a long text-run. If a text-run is too long, split it into several parts.
 // Please check the renderer::MAX_VERTEX_TEXTURE_WIDTH for the detail.
 pub const MAX_TEXT_RUN_LENGTH: usize = 2040;
 
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
@@ -166,16 +167,17 @@ fn skip_slice<T: for<'de> Deserialize<'d
         _boo: PhantomData,
     };
 
     // Adjust data pointer to skip read values
     *data = &data[range.length ..];
     (range, count)
 }
 
+
 impl<'a> BuiltDisplayListIter<'a> {
     pub fn new(list: &'a BuiltDisplayList) -> Self {
         Self::new_with_list_and_data(list, list.item_slice())
     }
 
     pub fn new_with_list_and_data(list: &'a BuiltDisplayList, data: &'a [u8]) -> Self {
         BuiltDisplayListIter {
             list,
@@ -216,17 +218,17 @@ impl<'a> BuiltDisplayListIter<'a> {
         self.cur_stops = ItemRange::default();
         self.cur_complex_clip = (ItemRange::default(), 0);
 
         loop {
             if self.data.len() == 0 {
                 return None;
             }
 
-            self.cur_item = bincode::deserialize_from(&mut self.data, bincode::Infinite)
+            self.cur_item = bincode::deserialize_from(&mut UnsafeReader::new(&mut self.data), bincode::Infinite)
                 .expect("MEH: malicious process?");
 
             match self.cur_item.item {
                 SetGradientStops => {
                     self.cur_stops = skip_slice::<GradientStop>(self.list, &mut self.data).0;
 
                     // This is a dummy item, skip over it
                     continue;
@@ -358,17 +360,17 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> {
     }
 }
 
 impl<'de, 'a, T: Deserialize<'de>> AuxIter<'a, T> {
     pub fn new(mut data: &'a [u8]) -> Self {
         let size: usize = if data.len() == 0 {
             0 // Accept empty ItemRanges pointing anywhere
         } else {
-            bincode::deserialize_from(&mut data, bincode::Infinite).expect("MEH: malicious input?")
+            bincode::deserialize_from(&mut UnsafeReader::new(&mut data), bincode::Infinite).expect("MEH: malicious input?")
         };
 
         AuxIter {
             data,
             size,
             _boo: PhantomData,
         }
     }
@@ -378,17 +380,17 @@ impl<'a, T: for<'de> Deserialize<'de>> I
     type Item = T;
 
     fn next(&mut self) -> Option<T> {
         if self.size == 0 {
             None
         } else {
             self.size -= 1;
             Some(
-                bincode::deserialize_from(&mut self.data, bincode::Infinite)
+                bincode::deserialize_from(&mut UnsafeReader::new(&mut self.data), bincode::Infinite)
                     .expect("MEH: malicious input?"),
             )
         }
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
         (self.size, Some(self.size))
     }
@@ -520,16 +522,83 @@ fn serialize_fast<T: Serialize>(vec: &mu
 
     // fix up the length
     unsafe { vec.set_len(old_len + size.0); }
 
     // make sure we wrote the right amount
     debug_assert!(((w.0 as usize) - (vec.as_ptr() as usize)) == vec.len());
 }
 
+// This uses a (start, end) representation instead of (start, len) so that
+// only need to update a single field as we read through it. This
+// makes it easier for llvm to understand what's going on. (https://github.com/rust-lang/rust/issues/45068)
+// We update the slice only once we're done reading
+struct UnsafeReader<'a: 'b, 'b> {
+    start: *const u8,
+    end: *const u8,
+    slice: &'b mut &'a [u8],
+}
+
+impl<'a, 'b> UnsafeReader<'a, 'b> {
+    #[inline(always)]
+    fn new(buf: &'b mut &'a [u8]) -> UnsafeReader<'a, 'b> {
+        unsafe {
+            let end = buf.as_ptr().offset(buf.len() as isize);
+            let start = buf.as_ptr();
+            UnsafeReader { start: start, end, slice: buf }
+        }
+    }
+
+    // This read implementation is significantly faster than the standard &[u8] one.
+    //
+    // First, it only supports reading exactly buf.len() bytes. This ensures that
+    // the argument to memcpy is always buf.len() and will allow a constant buf.len()
+    // to be propagated through to memcpy which LLVM will turn into explicit loads and
+    // stores. The standard implementation does a len = min(slice.len(), buf.len())
+    //
+    // Second, we only need to adjust 'start' after reading and it's only adjusted by a
+    // constant. This allows LLVM to avoid adjusting the length field after ever read
+    // and lets it be aggregated into a single adjustment.
+    #[inline(always)]
+    fn read_internal(&mut self, buf: &mut [u8]) {
+        // this is safe because we panic if start + buf.len() > end
+        unsafe {
+            assert!(self.start.offset(buf.len() as isize) <= self.end, "UnsafeReader: read past end of target");
+            ptr::copy_nonoverlapping(self.start, buf.as_mut_ptr(), buf.len());
+            self.start = self.start.offset(buf.len() as isize);
+        }
+    }
+}
+
+impl<'a, 'b> Drop for UnsafeReader<'a, 'b> {
+    // this adjusts input slice so that it properly represents the amount that's left.
+    #[inline(always)]
+    fn drop(&mut self) {
+        // this is safe because we know that start and end are contained inside the original slice
+        unsafe {
+            *self.slice = slice::from_raw_parts(self.start, (self.end as usize) - (self.start as usize));
+        }
+    }
+}
+
+impl<'a, 'b> Read for UnsafeReader<'a, 'b> {
+    // These methods were not being inlined and we need them to be so that the memcpy
+    // is for a constant size
+    #[inline(always)]
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.read_internal(buf);
+        Ok(buf.len())
+    }
+    #[inline(always)]
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        self.read_internal(buf);
+        Ok(())
+    }
+}
+
 #[derive(Clone, Debug)]
 pub struct SaveState {
     dl_len: usize,
     clip_stack_len: usize,
     next_clip_id: u64,
 }
 
 #[derive(Clone)]
@@ -625,16 +694,32 @@ impl DisplayListBuilder {
             &DisplayItem {
                 item,
                 clip_and_scroll: *self.clip_stack.last().unwrap(),
                 info: *info,
             },
         )
     }
 
+    fn push_item_with_clip_scroll_info(
+        &mut self,
+        item: SpecificDisplayItem,
+        info: &LayoutPrimitiveInfo,
+        scrollinfo: ClipAndScrollInfo
+    ) {
+        serialize_fast(
+            &mut self.data,
+            &DisplayItem {
+                item,
+                clip_and_scroll: scrollinfo,
+                info: *info,
+            },
+        )
+    }
+
     fn push_new_empty_item(&mut self, item: SpecificDisplayItem) {
         let info = LayoutPrimitiveInfo::new(LayoutRect::zero());
         serialize_fast(
             &mut self.data,
             &DisplayItem {
                 item,
                 clip_and_scroll: *self.clip_stack.last().unwrap(),
                 info,
@@ -1038,103 +1123,103 @@ impl DisplayListBuilder {
         complex_clips: I,
         image_mask: Option<ImageMask>,
         scroll_sensitivity: ScrollSensitivity,
     ) -> ClipId
     where
         I: IntoIterator<Item = ComplexClipRegion>,
         I::IntoIter: ExactSizeIterator,
     {
-        let parent_id = self.clip_stack.last().unwrap().scroll_node_id;
+        let parent = self.clip_stack.last().unwrap().scroll_node_id;
         self.define_scroll_frame_with_parent(
             id,
-            parent_id,
+            parent,
             content_rect,
             clip_rect,
             complex_clips,
             image_mask,
             scroll_sensitivity)
     }
 
     pub fn define_scroll_frame_with_parent<I>(
         &mut self,
         id: Option<ClipId>,
-        parent_id: ClipId,
+        parent: ClipId,
         content_rect: LayoutRect,
         clip_rect: LayoutRect,
         complex_clips: I,
         image_mask: Option<ImageMask>,
         scroll_sensitivity: ScrollSensitivity,
     ) -> ClipId
     where
         I: IntoIterator<Item = ComplexClipRegion>,
         I::IntoIter: ExactSizeIterator,
     {
         let id = self.generate_clip_id(id);
         let item = SpecificDisplayItem::ScrollFrame(ScrollFrameDisplayItem {
             id: id,
-            parent_id: parent_id,
             image_mask: image_mask,
             scroll_sensitivity,
         });
 
         let info = LayoutPrimitiveInfo {
             rect: content_rect,
             local_clip: LocalClip::from(clip_rect),
             is_backface_visible: true,
             tag: None,
         };
 
-        self.push_item(item, &info);
+        let scrollinfo = ClipAndScrollInfo::simple(parent);
+        self.push_item_with_clip_scroll_info(item, &info, scrollinfo);
         self.push_iter(complex_clips);
         id
     }
 
     pub fn define_clip<I>(
         &mut self,
         id: Option<ClipId>,
         clip_rect: LayoutRect,
         complex_clips: I,
         image_mask: Option<ImageMask>,
     ) -> ClipId
     where
         I: IntoIterator<Item = ComplexClipRegion>,
         I::IntoIter: ExactSizeIterator,
     {
-        let parent_id = self.clip_stack.last().unwrap().scroll_node_id;
+        let parent = self.clip_stack.last().unwrap().scroll_node_id;
         self.define_clip_with_parent(
             id,
-            parent_id,
+            parent,
             clip_rect,
             complex_clips,
             image_mask)
     }
 
     pub fn define_clip_with_parent<I>(
         &mut self,
         id: Option<ClipId>,
-        parent_id: ClipId,
+        parent: ClipId,
         clip_rect: LayoutRect,
         complex_clips: I,
         image_mask: Option<ImageMask>,
     ) -> ClipId
     where
         I: IntoIterator<Item = ComplexClipRegion>,
         I::IntoIter: ExactSizeIterator,
     {
         let id = self.generate_clip_id(id);
         let item = SpecificDisplayItem::Clip(ClipDisplayItem {
             id,
-            parent_id: parent_id,
             image_mask: image_mask,
         });
 
         let info = LayoutPrimitiveInfo::new(clip_rect);
 
-        self.push_item(item, &info);
+        let scrollinfo = ClipAndScrollInfo::simple(parent);
+        self.push_item_with_clip_scroll_info(item, &info, scrollinfo);
         self.push_iter(complex_clips);
         id
     }
 
     pub fn define_sticky_frame(
         &mut self,
         id: Option<ClipId>,
         frame_rect: LayoutRect,
@@ -1174,18 +1259,18 @@ impl DisplayListBuilder {
         });
         self.push_item(item, info);
     }
 
     pub fn push_shadow(&mut self, info: &LayoutPrimitiveInfo, shadow: Shadow) {
         self.push_item(SpecificDisplayItem::PushShadow(shadow), info);
     }
 
-    pub fn pop_shadow(&mut self) {
-        self.push_new_empty_item(SpecificDisplayItem::PopShadow);
+    pub fn pop_all_shadows(&mut self) {
+        self.push_new_empty_item(SpecificDisplayItem::PopAllShadows);
     }
 
     pub fn finalize(self) -> (PipelineId, LayoutSize, BuiltDisplayList) {
         assert!(self.save_state.is_none(), "Finalized DisplayListBuilder with a pending save");
 
         let end_time = precise_time_ns();
 
 
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -1079,19 +1079,19 @@ DisplayListBuilder::PushShadow(const wr:
                                const wr::LayoutRect& aClip,
                                bool aIsBackfaceVisible,
                                const wr::Shadow& aShadow)
 {
   wr_dp_push_shadow(mWrState, aRect, aClip, aIsBackfaceVisible, aShadow);
 }
 
 void
-DisplayListBuilder::PopShadow()
+DisplayListBuilder::PopAllShadows()
 {
-  wr_dp_pop_shadow(mWrState);
+  wr_dp_pop_all_shadows(mWrState);
 }
 
 void
 DisplayListBuilder::PushBoxShadow(const wr::LayoutRect& aRect,
                                   const wr::LayoutRect& aClip,
                                   bool aIsBackfaceVisible,
                                   const wr::LayoutRect& aBoxBounds,
                                   const wr::LayoutVector2D& aOffset,
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -369,17 +369,17 @@ public:
                 bool aIsBackfaceVisible,
                 const wr::Line& aLine);
 
   void PushShadow(const wr::LayoutRect& aBounds,
                       const wr::LayoutRect& aClip,
                       bool aIsBackfaceVisible,
                       const wr::Shadow& aShadow);
 
-  void PopShadow();
+  void PopAllShadows();
 
 
 
   void PushBoxShadow(const wr::LayoutRect& aRect,
                      const wr::LayoutRect& aClip,
                      bool aIsBackfaceVisible,
                      const wr::LayoutRect& aBoxBounds,
                      const wr::LayoutVector2D& aOffset,
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1453,20 +1453,20 @@ pub extern "C" fn wr_dp_push_shadow(stat
     debug_assert!(unsafe { is_in_main_thread() });
 
     let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
     prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder.dl_builder.push_shadow(&prim_info, shadow.into());
 }
 
 #[no_mangle]
-pub extern "C" fn wr_dp_pop_shadow(state: &mut WrState) {
+pub extern "C" fn wr_dp_pop_all_shadows(state: &mut WrState) {
     debug_assert!(unsafe { is_in_main_thread() });
 
-    state.frame_builder.dl_builder.pop_shadow();
+    state.frame_builder.dl_builder.pop_all_shadows();
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_line(state: &mut WrState,
                                   clip: LayoutRect,
                                   is_backface_visible: bool,
                                   baseline: f32,
                                   start: f32,
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -934,32 +934,32 @@ uint64_t wr_dp_define_sticky_frame(WrSta
                                    LayoutRect aContentRect,
                                    const StickySideConstraint *aTopRange,
                                    const StickySideConstraint *aRightRange,
                                    const StickySideConstraint *aBottomRange,
                                    const StickySideConstraint *aLeftRange)
 WR_FUNC;
 
 WR_INLINE
+void wr_dp_pop_all_shadows(WrState *aState)
+WR_FUNC;
+
+WR_INLINE
 void wr_dp_pop_clip(WrState *aState)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_pop_clip_and_scroll_info(WrState *aState)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_pop_scroll_layer(WrState *aState)
 WR_FUNC;
 
 WR_INLINE
-void wr_dp_pop_shadow(WrState *aState)
-WR_FUNC;
-
-WR_INLINE
 void wr_dp_pop_stacking_context(WrState *aState)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_border(WrState *aState,
                        LayoutRect aRect,
                        LayoutRect aClip,
                        bool aIsBackfaceVisible,
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -59,17 +59,16 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsDocShell.h"
 #include "nsIBaseWindow.h"
 #include "nsILayoutHistoryState.h"
 #include "nsCharsetSource.h"
 #include "mozilla/ReflowInput.h"
 #include "nsIImageLoadingContent.h"
 #include "nsCopySupport.h"
-#include "nsIDOMHTMLImageElement.h"
 #ifdef MOZ_XUL
 #include "nsIXULDocument.h"
 #include "nsXULPopupManager.h"
 #endif
 
 #include "nsIClipboardHelper.h"
 
 #include "nsPIDOMWindow.h"
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -7462,17 +7462,17 @@ nsLayoutUtils::SurfaceFromElement(nsIIma
     return result;
   }
 
   uint32_t status;
   imgRequest->GetImageStatus(&status);
   result.mHasSize = status & imgIRequest::STATUS_SIZE_AVAILABLE;
   if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0) {
     // Spec says to use GetComplete, but that only works on
-    // nsIDOMHTMLImageElement, and we support all sorts of other stuff
+    // HTMLImageElement, and we support all sorts of other stuff
     // here.  Do this for now pending spec clarification.
     result.mIsStillLoading = (status & imgIRequest::STATUS_ERROR) == 0;
     return result;
   }
 
   nsCOMPtr<nsIPrincipal> principal;
   rv = imgRequest->GetImagePrincipal(getter_AddRefs(principal));
   if (NS_FAILED(rv)) {
--- a/layout/generic/TextDrawTarget.h
+++ b/layout/generic/TextDrawTarget.h
@@ -132,26 +132,26 @@ public:
                                      color, mSc, mBoundsRect, mClipRect,
                                      mBackfaceVisible);
   }
 
   void
   AppendShadow(const wr::Shadow& aShadow)
   {
     mBuilder.PushShadow(mBoundsRect, mClipRect, mBackfaceVisible, aShadow);
-    mShadowCount++;
+    mHasShadows = true;
   }
 
   void
   TerminateShadows()
   {
-    for (size_t i = 0; i < mShadowCount; ++i) {
-      mBuilder.PopShadow();
+    if (mHasShadows) {
+      mBuilder.PopAllShadows();
+      mHasShadows = false;
     }
-    mShadowCount = 0;
   }
 
   void
   AppendSelectionRect(const LayoutDeviceRect& aRect, const Color& aColor)
   {
     auto rect = wr::ToLayoutRect(aRect);
     auto color = wr::ToColorF(aColor);
     mBuilder.PushRect(rect, mClipRect, mBackfaceVisible, color);
@@ -215,18 +215,18 @@ private:
   // * SVG fonts
   // * Unserializable fonts
   // * Tofu glyphs
   // * Pratial ligatures
   // * Text writing-mode
   // * Text stroke
   bool mHasUnsupportedFeatures = false;
 
-  // Number of shadows currently pushed, so we can pop them later.
-  size_t mShadowCount = 0;
+  // Whether PopAllShadows needs to be called
+  bool mHasShadows = false;
 
   // Things used to push to webrender
   wr::DisplayListBuilder& mBuilder;
   const layers::StackingContextHelper& mSc;
   layers::WebRenderLayerManager* mManager;
 
   // Computed facts
   wr::LayerRect mBoundsRect;
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1505,61 +1505,16 @@ nsBlockFrame::Reflow(nsPresContext*     
     char buf[400];
     SprintfLiteral(buf,
                    ": %" PRId64 " elapsed (%" PRId64 " per line) (%d lines; %d new lines)",
                    delta, perLineDelta, numLines, ectc - ctc);
     printf("%s\n", buf);
   }
 #endif
 
-#ifdef EARLY_BETA_OR_EARLIER
-  // Bug 1358299 START: Remove this code after the 56 merge date.
-  static bool sIsTelemetryEnabled;
-  static bool sTelemetryPrefCached = false;
-
-  if (!sTelemetryPrefCached) {
-    sTelemetryPrefCached = true;
-    Preferences::AddBoolVarCache(&sIsTelemetryEnabled,
-                                 "toolkit.telemetry.enabled");
-  }
-
-  if (sIsTelemetryEnabled) {
-    // Collect data for the BOX_ALIGN_PROPS_IN_BLOCKS_FLAG probe.
-    auto IsStyleNormalOrAuto = [](uint16_t value)->bool {
-      return ((value == NS_STYLE_ALIGN_NORMAL) ||
-              (value == NS_STYLE_ALIGN_AUTO));
-    };
-
-    // First check this frame for non-default values of the css-align properties
-    // that apply to block containers.
-    // Note: we check here for non-default "justify-items", though technically
-    // that'd only affect rendering if some child has "justify-self:auto".
-    // (It's safe to assume that's likely, since it's the default value that
-    // a child would have.)
-    const nsStylePosition* stylePosition = reflowInput->mStylePosition;
-    if (!IsStyleNormalOrAuto(stylePosition->mJustifyContent) ||
-        !IsStyleNormalOrAuto(stylePosition->mAlignContent) ||
-        !IsStyleNormalOrAuto(stylePosition->mJustifyItems)) {
-      Telemetry::Accumulate(Telemetry::BOX_ALIGN_PROPS_IN_BLOCKS_FLAG, true);
-    } else {
-      // If not already flagged by the parent, now check justify-self of the
-      // block-level child frames.
-      for (nsBlockFrame::LineIterator line = LinesBegin();
-           line != LinesEnd(); ++line) {
-        if (line->IsBlock() &&
-            !IsStyleNormalOrAuto(line->mFirstChild->StylePosition()->mJustifySelf)) {
-          Telemetry::Accumulate(Telemetry::BOX_ALIGN_PROPS_IN_BLOCKS_FLAG, true);
-          break;
-        }
-      }
-    }
-  }
-  // Bug 1358299 END
-#endif
-
   NS_FRAME_SET_TRUNCATION(aStatus, (*reflowInput), aMetrics);
 }
 
 bool
 nsBlockFrame::CheckForCollapsedBEndMarginFromClearanceLine()
 {
   LineIterator begin = LinesBegin();
   LineIterator line = LinesEnd();
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -4664,17 +4664,17 @@ ScrollFrameHelper::UpdateScrollbarPositi
     if (!weakFrame.IsAlive()) {
       return;
     }
   }
 
   mFrameIsUpdatingScrollbar = false;
 }
 
-void ScrollFrameHelper::CurPosAttributeChanged(nsIContent* aContent)
+void ScrollFrameHelper::CurPosAttributeChanged(nsIContent* aContent, bool aDoScroll)
 {
   NS_ASSERTION(aContent, "aContent must not be null");
   NS_ASSERTION((mHScrollbarBox && mHScrollbarBox->GetContent() == aContent) ||
                (mVScrollbarBox && mVScrollbarBox->GetContent() == aContent),
                "unexpected child");
 
   // Attribute changes on the scrollbars happen in one of three ways:
   // 1) The scrollbar changed the attribute in response to some user event
@@ -4720,19 +4720,22 @@ void ScrollFrameHelper::CurPosAttributeC
     // see that the scroll position is not (yet) what they thought it
     // was.
     AutoWeakFrame weakFrame(mOuter);
     UpdateScrollbarPosition();
     if (!weakFrame.IsAlive()) {
       return;
     }
   }
-  ScrollToWithOrigin(dest,
-                     isSmooth ? nsIScrollableFrame::SMOOTH : nsIScrollableFrame::INSTANT,
-                     nsGkAtoms::scrollbars, &allowedRange);
+
+  if (aDoScroll) {
+    ScrollToWithOrigin(dest,
+                       isSmooth ? nsIScrollableFrame::SMOOTH : nsIScrollableFrame::INSTANT,
+                       nsGkAtoms::scrollbars, &allowedRange);
+  }
   // 'this' might be destroyed here
 }
 
 /* ============= Scroll events ========== */
 
 ScrollFrameHelper::ScrollEvent::ScrollEvent(ScrollFrameHelper* aHelper)
   : Runnable("ScrollFrameHelper::ScrollEvent")
   , mHelper(aHelper)
@@ -5319,34 +5322,38 @@ ScrollFrameHelper::FinishReflowForScroll
   SetCoordAttribute(aContent, nsGkAtoms::increment, aIncrement);
 }
 
 bool
 ScrollFrameHelper::ReflowFinished()
 {
   mPostedReflowCallback = false;
 
+  bool doScroll = true;
   if (NS_SUBTREE_DIRTY(mOuter)) {
     // We will get another call after the next reflow and scrolling
     // later is less janky.
-    return false;
+    doScroll = false;
   }
 
   nsAutoScriptBlocker scriptBlocker;
-  ScrollToRestoredPosition();
-
-  // Clamp current scroll position to new bounds. Normally this won't
-  // do anything.
-  nsPoint currentScrollPos = GetScrollPosition();
-  ScrollToImpl(currentScrollPos, nsRect(currentScrollPos, nsSize(0, 0)));
-  if (!mAsyncScroll && !mAsyncSmoothMSDScroll && !mApzSmoothScrollDestination) {
-    // We need to have mDestination track the current scroll position,
-    // in case it falls outside the new reflow area. mDestination is used
-    // by ScrollBy as its starting position.
-    mDestination = GetScrollPosition();
+
+  if (doScroll) {
+    ScrollToRestoredPosition();
+
+    // Clamp current scroll position to new bounds. Normally this won't
+    // do anything.
+    nsPoint currentScrollPos = GetScrollPosition();
+    ScrollToImpl(currentScrollPos, nsRect(currentScrollPos, nsSize(0, 0)));
+    if (!mAsyncScroll && !mAsyncSmoothMSDScroll && !mApzSmoothScrollDestination) {
+      // We need to have mDestination track the current scroll position,
+      // in case it falls outside the new reflow area. mDestination is used
+      // by ScrollBy as its starting position.
+      mDestination = GetScrollPosition();
+    }
   }
 
   if (!mUpdateScrollbarAttributes) {
     return false;
   }
   mUpdateScrollbarAttributes = false;
 
   // Update scrollbar attributes.
@@ -5428,18 +5435,19 @@ ScrollFrameHelper::ReflowFinished()
   // mFrameIsUpdatingScrollbar and call CurPosAttributeChanged here.
   // (It actually even works some of the time without this, thanks to
   // nsSliderFrame::AttributeChanged's handling of maxpos, but not when
   // we hide the scrollbar on a large size change, such as
   // maximization.)
   if (!mHScrollbarBox && !mVScrollbarBox)
     return false;
   CurPosAttributeChanged(mVScrollbarBox ? mVScrollbarBox->GetContent()
-                                        : mHScrollbarBox->GetContent());
-  return true;
+                                        : mHScrollbarBox->GetContent(),
+                         doScroll);
+  return doScroll;
 }
 
 void
 ScrollFrameHelper::ReflowCallbackCanceled()
 {
   mPostedReflowCallback = false;
 }
 
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -83,17 +83,17 @@ public:
   // nsIReflowCallback
   virtual bool ReflowFinished() override;
   virtual void ReflowCallbackCanceled() override;
 
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    * Called when the 'curpos' attribute on one of the scrollbars changes.
    */
-  void CurPosAttributeChanged(nsIContent* aChild);
+  void CurPosAttributeChanged(nsIContent* aChild, bool aDoScroll = true);
 
   void PostScrollEvent();
   void FireScrollEvent();
   void PostScrolledAreaEvent();
   void FireScrolledAreaEvent();
 
   bool IsSmoothScrollingEnabled();
 
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -8,17 +8,16 @@
 
 #include "nsVideoFrame.h"
 
 #include "nsCOMPtr.h"
 #include "nsGkAtoms.h"
 
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "nsDisplayList.h"
 #include "nsGenericHTMLElement.h"
 #include "nsPresContext.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsBoxLayoutState.h"
 #include "nsBoxFrame.h"
 #include "nsImageFrame.h"
 #include "nsIImageLoadingContent.h"
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -8059,17 +8059,18 @@ nsDisplayTransform::CreateWebRenderComma
                            aBuilder,
                            filters,
                            &newTransformMatrix,
                            animationsId,
                            nullptr,
                            transformForSC,
                            nullptr,
                            gfx::CompositionOp::OP_OVER,
-                           !BackfaceIsHidden());
+                           !BackfaceIsHidden(),
+                           mFrame->Extend3DContext());
 
   return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc,
                                              aManager, aDisplayListBuilder);
 }
 
 bool
 nsDisplayTransform::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
                                      mozilla::layers::WebRenderLayerScrollData* aLayerData)
@@ -8670,17 +8671,18 @@ nsDisplayPerspective::CreateWebRenderCom
                            aBuilder,
                            filters,
                            nullptr,
                            0,
                            nullptr,
                            &transformForSC,
                            &perspectiveMatrix,
                            gfx::CompositionOp::OP_OVER,
-                           !BackfaceIsHidden());
+                           !BackfaceIsHidden(),
+                           true);
 
   return mList.CreateWebRenderCommands(aBuilder, aResources, sc,
                                        aManager, aDisplayListBuilder);
 }
 
 int32_t
 nsDisplayPerspective::ZIndex() const
 {
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -96,17 +96,16 @@ static const char kPrintingPromptService
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIBaseWindow.h"
 #include "nsILayoutHistoryState.h"
 #include "nsFrameManager.h"
 #include "mozilla/ReflowInput.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "nsIContentViewerContainer.h"
 #include "nsIContentViewer.h"
 #include "nsIDocumentViewerPrint.h"
 
 #include "nsFocusManager.h"
 #include "nsRange.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsIURIFixup.h"
--- a/layout/reftests/async-scrolling/reftest.list
+++ b/layout/reftests/async-scrolling/reftest.list
@@ -31,17 +31,17 @@ skip-if(!asyncPan) == sticky-pos-scrolla
 skip-if(!asyncPan) == fixed-pos-scrollable-1.html fixed-pos-scrollable-1-ref.html
 skip-if(!asyncPan) == culling-1.html culling-1-ref.html
 skip-if(!asyncPan) == position-fixed-iframe-1.html position-fixed-iframe-1-ref.html
 skip-if(!asyncPan) == position-fixed-iframe-2.html position-fixed-iframe-2-ref.html
 fuzzy-if(skiaContent,1,11300) skip-if(!asyncPan) == position-fixed-in-scroll-container.html position-fixed-in-scroll-container-ref.html
 skip-if(!asyncPan) == position-fixed-inside-sticky-1.html position-fixed-inside-sticky-1-ref.html
 skip-if(!asyncPan) == position-fixed-inside-sticky-2.html position-fixed-inside-sticky-2-ref.html
 fuzzy(1,60000) skip-if(!asyncPan) == group-opacity-surface-size-1.html group-opacity-surface-size-1-ref.html
-fails-if(webrender) fuzzy-if(Android,1,197) skip-if(!asyncPan) == position-sticky-transformed.html position-sticky-transformed-ref.html # bug 1366295 for webrender
+fuzzy-if(Android,1,197) skip-if(!asyncPan) == position-sticky-transformed.html position-sticky-transformed-ref.html # bug 1366295 for webrender
 skip-if(!asyncPan) == offscreen-prerendered-active-opacity.html offscreen-prerendered-active-opacity-ref.html
 fuzzy-if(Android,6,4) fuzzy-if(skiaContent&&!Android,1,34) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,6,4) skip == offscreen-clipped-blendmode-3.html offscreen-clipped-blendmode-ref.html # bug 1251588 - wrong AGR on mix-blend-mode item
 fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-1.html perspective-scrolling-1-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-2.html perspective-scrolling-2-ref.html
 fuzzy-if(Android,7,4) fails-if(webrender) skip-if(!asyncPan) == perspective-scrolling-3.html perspective-scrolling-3-ref.html # bug 1361720 for webrender
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -179,9 +179,9 @@ fuzzy(30,474) fuzzy-if(skiaContent,31,47
 skip-if(!cocoaWidget) == background-repeat-resampling.html background-repeat-resampling-ref.html
 
 fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) == background-clip-text-1a.html background-clip-text-1-ref.html
 fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) == background-clip-text-1b.html background-clip-text-1-ref.html
 fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) == background-clip-text-1c.html background-clip-text-1-ref.html
 fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) == background-clip-text-1d.html background-clip-text-1-ref.html
 fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) == background-clip-text-1e.html background-clip-text-1-ref.html
 
-== background-clip-text-2.html background-clip-text-2-ref.html
+fuzzy-if(webrender,5-5,7193-7193) == background-clip-text-2.html background-clip-text-2-ref.html
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -198,17 +198,17 @@ fuzzy-if(skiaContent,1,2) == fallback-co
 == filter-bounds-02.svg pass.svg
 # This pref is normally on by default, but we turn it off in reftest runs to
 # disable an unnecessary security-check. This reftest is actually testing that
 # the security check works, though, so it needs the pref to be turned on:
 fails-if(Android) pref(security.fileuri.strict_origin_policy,true) == filter-extref-differentOrigin-01.svg pass.svg # Bug 695385
 == filter-foreignObject-01.svg pass.svg
 == filter-in-mask-01.svg pass.svg
 == filter-invalidation-01.svg pass.svg
-fuzzy(71,817) fails-if(winWidget&&stylo) == filter-on-continuation-box-01.html filter-on-continuation-box-ref.html
+fuzzy(71,817) fails-if(winWidget&&stylo) fails-if(webrender) == filter-on-continuation-box-01.html filter-on-continuation-box-ref.html
 == filter-result-01.svg filter-result-01-ref.svg
 == filter-scaled-01.svg pass.svg
 fuzzy-if(skiaContent,1,500) == filter-scaled-02.html filter-scaled-02-ref.html
 == filter-translated-01.svg filter-translated-01-ref.svg
 == filter-use-element-01.svg pass.svg
 fuzzy-if(skiaContent,1,800000) == filters-and-group-opacity-01.svg filters-and-group-opacity-01-ref.svg
 
 == foreignObject-01.svg pass.svg
--- a/layout/reftests/text-shadow/reftest.list
+++ b/layout/reftests/text-shadow/reftest.list
@@ -4,24 +4,24 @@
 random-if(Android) == basic-negcoord.xul basic-negcoord-ref.xul
 != blur.xul blur-notref.xul
 == color-inherit.xul color-inherit-ref.xul
 == multiple-noblur.xul multiple-noblur-ref.xul
 HTTP(..) == blur-opacity.html blur-opacity-ref.html
 
 == basic.html basic-ref.html
 == basic-negcoord.html basic-negcoord-ref.html
-== basic-opacity.html basic-opacity-ref.html
+fuzzy-if(webrender,24-24,80-80) == basic-opacity.html basic-opacity-ref.html
 != blur.html blur-notref.html
 == color-inherit.html color-inherit-ref.html
 == color-parserorder.html color-parserorder-ref.html
-fails-if(webrender) == decorations-multiple-zorder.html decorations-multiple-zorder-ref.html
+== decorations-multiple-zorder.html decorations-multiple-zorder-ref.html
 == multiple-noblur.html multiple-noblur-ref.html
-fails-if(webrender) == quirks-decor-noblur.html quirks-decor-noblur-ref.html
-fails-if(webrender) == standards-decor-noblur.html standards-decor-noblur-ref.html
+== quirks-decor-noblur.html quirks-decor-noblur-ref.html
+== standards-decor-noblur.html standards-decor-noblur-ref.html
 == padding-decoration.html padding-decoration-ref.html
 == textindent.html textindent-ref.html
 == lineoverflow.html lineoverflow-ref.html
 
 == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html
 == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html
 == overflow-not-scrollable-2.html overflow-not-scrollable-2-ref.html
 
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -42,19 +42,19 @@ fuzzy-if(winWidget&&!layersGPUAccelerate
 == perspective-clipping-2.html perspective-clipping-2-ref.html
 != perspective-origin-1a.html rotatex-perspective-1a.html
 fuzzy-if(webrender,0-1,0-3) == perspective-origin-1b.html perspective-origin-1a.html
 fuzzy(3,99) random-if(Android&&!browserIsRemote) == perspective-origin-2a.html perspective-origin-2-ref.html # subpixel AA, bug 732568
 fuzzy-if(winWidget&&!layersGPUAccelerated,1,61) == perspective-origin-3a.html perspective-origin-3-ref.html
 == perspective-origin-4a.html perspective-origin-4-ref.html
 == perspective-zindex.html green-rect.html
 == perspective-zindex-2.html green-rect.html
-fails-if(webrender) != sorting-1a.html sorting-1-ref.html
+!= sorting-1a.html sorting-1-ref.html
 # Parallel planes, different z depth
-fails-if(webrender) == sorting-2a.html sorting-2-ref.html
+== sorting-2a.html sorting-2-ref.html
 # Parallel planes, same z depth (shouldn't be sorted!)
 == sorting-2b.html sorting-2-ref.html
 == sorting-3a.html green-rect.html
 # Different, but equivalent (for the given transform) transform origins
 fuzzy-if(webrender,0-1,0-2) == rotatex-transformorigin-1a.html rotatex-transformorigin-1-ref.html
 fuzzy-if((gtkWidget&&layersOMTC)||(winWidget&&!layersGPUAccelerated),1,86) == overflow-hidden-1a.html overflow-hidden-1-ref.html
 fails-if(webrender) == transform-style-flat-1a.html transform-style-flat-1-ref.html
 == willchange-containing-block.html?willchange willchange-containing-block.html?ref
@@ -74,19 +74,19 @@ fuzzy-if(cocoaWidget,128,9) == animate-p
 fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-child.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
 == animate-backface-hidden.html about:blank
 == 1245450-1.html green-rect.html
 fuzzy(1,2000) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
 fuzzy(1,15000) == opacity-preserve3d-2.html opacity-preserve3d-2-ref.html
 fuzzy(1,10000) == opacity-preserve3d-3.html opacity-preserve3d-3-ref.html
 fuzzy(1,10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
 == opacity-preserve3d-5.html opacity-preserve3d-5-ref.html
-fails-if(webrender) == snap-perspective-1.html snap-perspective-1-ref.html
+== snap-perspective-1.html snap-perspective-1-ref.html
 == mask-layer-1.html mask-layer-ref.html
 == mask-layer-2.html mask-layer-ref.html
 fails-if(webrender) == mask-layer-3.html mask-layer-ref.html
 fails-if(webrender) == split-intersect1.html split-intersect1-ref.html
-fuzzy(255,150) fails-if(webrender) == split-intersect2.html split-intersect2-ref.html
+fuzzy(255,150) == split-intersect2.html split-intersect2-ref.html
 fuzzy(255,100) fails-if(webrender) == split-non-ortho1.html split-non-ortho1-ref.html
 fuzzy-if(winWidget,150,120) == component-alpha-1.html component-alpha-1-ref.html
 == nested-transform-1.html nested-transform-1-ref.html
 == transform-geometry-1.html transform-geometry-1-ref.html
 == intermediate-1.html intermediate-1-ref.html
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -50,17 +50,16 @@ EXPORTS += [
     'nsCSSRuleProcessor.h',
     'nsCSSScanner.h',
     'nsCSSValue.h',
     'nsDOMCSSAttrDeclaration.h',
     'nsDOMCSSDeclaration.h',
     'nsDOMCSSRGBColor.h',
     'nsICSSDeclaration.h',
     'nsICSSLoaderObserver.h',
-    'nsICSSPseudoComparator.h',
     'nsICSSStyleRuleDOMWrapper.h',
     'nsIStyleRule.h',
     'nsIStyleRuleProcessor.h',
     'nsLayoutStylesheetCache.h',
     'nsMediaFeatures.h',
     'nsMediaList.h',
     'nsRuleData.h',
     'nsRuleNode.h',
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -11,17 +11,16 @@
 
 #include "nsCSSRuleProcessor.h"
 
 #include "nsAutoPtr.h"
 #include "nsRuleProcessorData.h"
 #include <algorithm>
 #include "nsAtom.h"
 #include "PLDHashTable.h"
-#include "nsICSSPseudoComparator.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/css/ImportRule.h"
 #include "mozilla/css/StyleRule.h"
 #include "mozilla/css/GroupRule.h"
 #include "nsIDocument.h"
 #include "nsPresContext.h"
 #include "nsGkAtoms.h"
 #include "nsUnicharUtils.h"
@@ -2584,31 +2583,47 @@ nsCSSRuleProcessor::RulesMatching(AnonBo
         declaration->SetImmutable();
         aData->mRuleWalker->Forward(declaration);
       }
     }
   }
 }
 
 #ifdef MOZ_XUL
+static bool
+XULTreePseudoMatches(nsCSSSelector* aSelector, const AtomArray& aInputWord)
+{
+  // Iterate the class list.  For each item in the list, see if
+  // it is contained in our scratch array.  If we have a miss, then
+  // we aren't a match.  If all items in the class list are
+  // present in the scratch array, then we have a match.
+  nsAtomList* curr = aSelector->mClassList;
+  while (curr) {
+    if (!aInputWord.Contains(curr->mAtom))
+      return false;
+    curr = curr->mNext;
+  }
+  return true;
+}
+
 /* virtual */ void
 nsCSSRuleProcessor::RulesMatching(XULTreeRuleProcessorData* aData)
 {
   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
 
   if (cascade && cascade->mXULTreeRules.EntryCount()) {
     auto entry = static_cast<RuleHashTagTableEntry*>
                             (cascade->mXULTreeRules.Search(aData->mPseudoTag));
     if (entry) {
       NodeMatchContext nodeContext(EventStates(),
                                    nsCSSRuleProcessor::IsLink(aData->mElement));
       nsTArray<RuleValue>& rules = entry->mRules;
       for (RuleValue *value = rules.Elements(), *end = value + rules.Length();
            value != end; ++value) {
-        if (aData->mComparator->PseudoMatches(value->mSelector)) {
+        if (XULTreePseudoMatches(value->mSelector, aData->mInputWord)) {
           ContentEnumFunc(*value, value->mSelector->mNext, aData, nodeContext,
                           nullptr);
         }
       }
     }
   }
 }
 #endif
deleted file mode 100644
--- a/layout/style/nsICSSPseudoComparator.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* internal interface for implementing complex pseudo-classes */
-
-#ifndef nsICSSPseudoComparator_h___
-#define nsICSSPseudoComparator_h___
-
-struct nsCSSSelector;
-
-class nsICSSPseudoComparator
-{
-public:
-  virtual bool PseudoMatches(nsCSSSelector* aSelector)=0;
-};
-
-#endif /* nsICSSPseudoComparator_h___ */
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -15,16 +15,17 @@
 #include "nsChangeHint.h"
 #include "nsCompatibility.h"
 #include "nsCSSPseudoElements.h"
 #include "nsRuleWalker.h"
 #include "nsNthIndexCache.h"
 #include "nsILoadContext.h"
 #include "nsIDocument.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/AtomArray.h"
 #include "mozilla/BloomFilter.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/dom/Element.h"
 
 class nsAtom;
 class nsIContent;
 class nsICSSPseudoComparator;
@@ -546,31 +547,30 @@ struct MOZ_STACK_CLASS AnonBoxRuleProces
 
 #ifdef MOZ_XUL
 struct MOZ_STACK_CLASS XULTreeRuleProcessorData :
                           public ElementDependentRuleProcessorData {
   XULTreeRuleProcessorData(nsPresContext* aPresContext,
                            mozilla::dom::Element* aParentElement,
                            nsRuleWalker* aRuleWalker,
                            nsAtom* aPseudoTag,
-                           nsICSSPseudoComparator* aComparator,
+                           const mozilla::AtomArray& aInputWord,
                            TreeMatchContext& aTreeMatchContext)
     : ElementDependentRuleProcessorData(aPresContext, aParentElement,
                                         aRuleWalker, aTreeMatchContext),
       mPseudoTag(aPseudoTag),
-      mComparator(aComparator)
+      mInputWord(aInputWord)
   {
     NS_PRECONDITION(aPseudoTag, "null pointer");
     NS_PRECONDITION(aRuleWalker, "Must have rule walker");
-    NS_PRECONDITION(aComparator, "must have a comparator");
     NS_PRECONDITION(aTreeMatchContext.mForStyling, "Styling here!");
   }
 
   nsAtom*                 mPseudoTag;
-  nsICSSPseudoComparator*  mComparator;
+  const mozilla::AtomArray& mInputWord;
 };
 #endif
 
 struct MOZ_STACK_CLASS StateRuleProcessorData :
                           public ElementDependentRuleProcessorData {
   StateRuleProcessorData(nsPresContext* aPresContext,
                          mozilla::dom::Element* aElement,
                          mozilla::EventStates aStateMask,
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -2181,30 +2181,30 @@ nsStyleSet::ResolveNonInheritingAnonymou
   return retval.forget();
 }
 
 #ifdef MOZ_XUL
 already_AddRefed<GeckoStyleContext>
 nsStyleSet::ResolveXULTreePseudoStyle(Element* aParentElement,
                                       nsICSSAnonBoxPseudo* aPseudoTag,
                                       GeckoStyleContext* aParentContext,
-                                      nsICSSPseudoComparator* aComparator)
+                                      const mozilla::AtomArray& aInputWord)
 {
   NS_ENSURE_FALSE(mInShutdown, nullptr);
 
   NS_ASSERTION(aPseudoTag, "must have pseudo tag");
   NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
                "Unexpected pseudo");
 
   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aParentElement->OwnerDoc());
   InitStyleScopes(treeContext, aParentElement);
   XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
-                                aPseudoTag, aComparator, treeContext);
+                                aPseudoTag, aInputWord, treeContext);
   FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
             &ruleWalker);
 
   nsRuleNode *ruleNode = ruleWalker.CurrentNode();
   nsRuleNode *visitedRuleNode = nullptr;
 
   if (treeContext.HaveRelevantLink()) {
     treeContext.ResetForVisitedMatching();
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -7,16 +7,17 @@
  * the container for the style sheets that apply to a presentation, and
  * the internal API that the style system exposes for creating (and
  * potentially re-creating) style contexts
  */
 
 #ifndef nsStyleSet_h_
 #define nsStyleSet_h_
 
+#include "mozilla/AtomArray.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ServoTypes.h"
 #include "mozilla/SheetType.h"
 
@@ -297,22 +298,22 @@ class nsStyleSet final
   // anything.  aPseudoTag is the pseudo-tag to use and must be non-null.  It
   // must be an anon box, and must be a non-inheriting one.
   already_AddRefed<mozilla::GeckoStyleContext>
   ResolveNonInheritingAnonymousBoxStyle(nsAtom* aPseudoTag);
 
 #ifdef MOZ_XUL
   // Get a style context for a XUL tree pseudo.  aPseudoTag is the
   // pseudo-tag to use and must be non-null.  aParentContent must be
-  // non-null.  aComparator must be non-null.
+  // non-null.
   already_AddRefed<mozilla::GeckoStyleContext>
   ResolveXULTreePseudoStyle(mozilla::dom::Element* aParentElement,
                             nsICSSAnonBoxPseudo* aPseudoTag,
                             mozilla::GeckoStyleContext* aParentContext,
-                            nsICSSPseudoComparator* aComparator);
+                            const mozilla::AtomArray& aInputWord);
 #endif
 
   // Append all the currently-active font face rules to aArray.  Return
   // true for success and false for failure.
   bool AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray);
 
   // Return the winning (in the cascade) @keyframes rule for the given name.
   nsCSSKeyframesRule* KeyframesRuleForName(nsAtom* aName);
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -26,17 +26,16 @@
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
 #include "nsImageMap.h"
 #include "nsILinkHandler.h"
 #include "nsIURL.h"
 #include "nsILoadGroup.h"
 #include "nsContainerFrame.h"
 #include "nsCSSRendering.h"
-#include "nsIDOMHTMLImageElement.h"
 #include "nsNameSpaceManager.h"
 #include "nsTextFragment.h"
 #include "nsTransform2D.h"
 #include "nsITheme.h"
 
 #include "nsIServiceManager.h"
 #include "nsIURI.h"
 #include "nsThreadUtils.h"
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -4470,38 +4470,21 @@ nsTreeBodyFrame::ThumbMoved(nsScrollbarF
     UpdateScrollbars(parts);
   }
 }
 
 // The style cache.
 nsStyleContext*
 nsTreeBodyFrame::GetPseudoStyleContext(nsICSSAnonBoxPseudo* aPseudoElement)
 {
-  return mStyleCache.GetStyleContext(this, PresContext(), mContent,
+  return mStyleCache.GetStyleContext(PresContext(), mContent,
                                      mStyleContext, aPseudoElement,
                                      mScratchArray);
 }
 
-// Our comparator for resolving our complex pseudos
-bool
-nsTreeBodyFrame::PseudoMatches(nsCSSSelector* aSelector)
-{
-  // Iterate the class list.  For each item in the list, see if
-  // it is contained in our scratch array.  If we have a miss, then
-  // we aren't a match.  If all items in the class list are
-  // present in the scratch array, then we have a match.
-  nsAtomList* curr = aSelector->mClassList;
-  while (curr) {
-    if (!mScratchArray.Contains(curr->mAtom))
-      return false;
-    curr = curr->mNext;
-  }
-  return true;
-}
-
 nsIContent*
 nsTreeBodyFrame::GetBaseElement()
 {
   nsIFrame* parent = GetParent();
   while (parent) {
     nsIContent* content = parent->GetContent();
     if (content) {
       dom::NodeInfo* ni = content->NodeInfo();
--- a/layout/xul/tree/nsTreeBodyFrame.h
+++ b/layout/xul/tree/nsTreeBodyFrame.h
@@ -1,21 +1,21 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsTreeBodyFrame_h
 #define nsTreeBodyFrame_h
 
+#include "mozilla/AtomArray.h"
 #include "mozilla/Attributes.h"
 
 #include "nsLeafBoxFrame.h"
 #include "nsITreeView.h"
-#include "nsICSSPseudoComparator.h"
 #include "nsIScrollbarMediator.h"
 #include "nsITimer.h"
 #include "nsIReflowCallback.h"
 #include "nsTArray.h"
 #include "nsTreeStyleCache.h"
 #include "nsTreeColumns.h"
 #include "nsDataHashtable.h"
 #include "imgIRequest.h"
@@ -43,17 +43,16 @@ struct nsTreeImageCacheEntry
 
   nsCOMPtr<imgIRequest> request;
   nsCOMPtr<imgINotificationObserver> listener;
 };
 
 // The actual frame that paints the cells and rows.
 class nsTreeBodyFrame final
   : public nsLeafBoxFrame
-  , public nsICSSPseudoComparator
   , public nsIScrollbarMediator
   , public nsIReflowCallback
 {
   typedef mozilla::layout::ScrollbarActivity ScrollbarActivity;
   typedef mozilla::image::DrawResult DrawResult;
 
 public:
   explicit nsTreeBodyFrame(nsStyleContext* aContext);
@@ -126,19 +125,16 @@ public:
   virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
   virtual void SetXULBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect,
                             bool aRemoveOverflowArea = false) override;
 
   // nsIReflowCallback
   virtual bool ReflowFinished() override;
   virtual void ReflowCallbackCanceled() override;
 
-  // nsICSSPseudoComparator
-  virtual bool PseudoMatches(nsCSSSelector* aSelector) override;
-
   // nsIScrollbarMediator
   virtual void ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection,
                             nsIScrollbarMediator::ScrollSnapMode aSnap
                               = nsIScrollbarMediator::DISABLE_SNAP) override;
   virtual void ScrollByWhole(nsScrollbarFrame* aScrollbar, int32_t aDirection,
                              nsIScrollbarMediator::ScrollSnapMode aSnap
                                = nsIScrollbarMediator::DISABLE_SNAP) override;
   virtual void ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection,
@@ -594,17 +590,17 @@ protected: // Data Members
 
   // A hashtable that maps from URLs to image request/listener pairs.  The URL
   // is provided by the view or by the style context. The style context
   // represents a resolved :-moz-tree-cell-image (or twisty) pseudo-element.
   // It maps directly to an imgIRequest.
   nsDataHashtable<nsStringHashKey, nsTreeImageCacheEntry> mImageCache;
 
   // A scratch array used when looking up cached style contexts.
-  AtomArray mScratchArray;
+  mozilla::AtomArray mScratchArray;
 
   // The index of the first visible row and the # of rows visible onscreen.
   // The tree only examines onscreen rows, starting from
   // this index and going up to index+pageLength.
   int32_t mTopRowIndex;
   int32_t mPageLength;
 
   // The horizontal scroll position
--- a/layout/xul/tree/nsTreeStyleCache.cpp
+++ b/layout/xul/tree/nsTreeStyleCache.cpp
@@ -27,18 +27,17 @@ nsTreeStyleCache::Transition::Hash() con
   uint32_t hb = mState << 16;
   uint32_t lb = (NS_PTR_TO_UINT32(mInputSymbol.get()) << 16) >> 16;
   return hb+lb;
 }
 
 
 // The style context cache impl
 nsStyleContext*
-nsTreeStyleCache::GetStyleContext(nsICSSPseudoComparator* aComparator,
-                                  nsPresContext* aPresContext,
+nsTreeStyleCache::GetStyleContext(nsPresContext* aPresContext,
                                   nsIContent* aContent,
                                   nsStyleContext* aContext,
                                   nsICSSAnonBoxPseudo* aPseudoElement,
                                   const AtomArray & aInputWord)
 {
   MOZ_ASSERT(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoElement));
 
   uint32_t count = aInputWord.Length();
@@ -84,17 +83,17 @@ nsTreeStyleCache::GetStyleContext(nsICSS
     RefPtr<nsStyleContext> newResult;
     if (aPresContext->StyleSet()->IsServo()) {
       NS_ERROR("stylo: ServoStyleSets should not support XUL tree styles yet");
       newResult = aPresContext->StyleSet()->
         ResolveStyleForPlaceholder();
     } else {
       newResult = aPresContext->StyleSet()->AsGecko()->
         ResolveXULTreePseudoStyle(aContent->AsElement(), aPseudoElement,
-                                  aContext->AsGecko(), aComparator);
+                                  aContext->AsGecko(), aInputWord);
     }
 
     // Put the style context in our table, transferring the owning reference to the table.
     if (!mCache) {
       mCache = new StyleContextCache();
     }
     result = newResult.get();
     mCache->Put(currState, newResult.forget());
--- a/layout/xul/tree/nsTreeStyleCache.h
+++ b/layout/xul/tree/nsTreeStyleCache.h
@@ -1,26 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsTreeStyleCache_h__
 #define nsTreeStyleCache_h__
 
+#include "mozilla/AtomArray.h"
 #include "mozilla/Attributes.h"
 #include "nsAutoPtr.h"
-#include "nsAtom.h"
 #include "nsCOMArray.h"
-#include "nsICSSPseudoComparator.h"
 #include "nsRefPtrHashtable.h"
 #include "nsStyleContext.h"
 
-typedef nsTArray<RefPtr<nsAtom>> AtomArray;
-
 class nsTreeStyleCache
 {
 public:
   nsTreeStyleCache()
     : mNextState(0)
   {
   }
 
@@ -31,22 +28,21 @@ public:
 
   void Clear()
   {
     mTransitionTable = nullptr;
     mCache = nullptr;
     mNextState = 0;
   }
 
-  nsStyleContext* GetStyleContext(nsICSSPseudoComparator* aComparator,
-                                  nsPresContext* aPresContext,
+  nsStyleContext* GetStyleContext(nsPresContext* aPresContext,
                                   nsIContent* aContent,
                                   nsStyleContext* aContext,
                                   nsICSSAnonBoxPseudo* aPseudoElement,
-                                  const AtomArray & aInputWord);
+                                  const mozilla::AtomArray& aInputWord);
 
 protected:
   typedef uint32_t DFAState;
 
   class Transition final
   {
   public:
     Transition(DFAState aState, nsAtom* aSymbol);
--- a/layout/xul/tree/nsTreeUtils.h
+++ b/layout/xul/tree/nsTreeUtils.h
@@ -1,32 +1,34 @@
 /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsTreeUtils_h__
 #define nsTreeUtils_h__
 
+#include "mozilla/AtomArray.h"
 #include "nsError.h"
 #include "nsString.h"
 #include "nsTreeStyleCache.h"
 
 class nsAtom;
 class nsIContent;
 
 class nsTreeUtils
 {
   public:
     /**
      * Parse a whitespace separated list of properties into an array
      * of atoms.
      */
     static nsresult
-    TokenizeProperties(const nsAString& aProperties, AtomArray & aPropertiesArray);
+    TokenizeProperties(const nsAString& aProperties,
+                       mozilla::AtomArray& aPropertiesArray);
 
     static nsIContent*
     GetImmediateChild(nsIContent* aContainer, nsAtom* aTag);
 
     static nsIContent*
     GetDescendantChild(nsIContent* aContainer, nsAtom* aTag);
 
     static nsresult
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -280,37 +280,37 @@ classycle_jar := $(topsrcdir)/mobile/and
 # sometimes corrupt this information if present (which it does for some of the
 # included libraries). This corruption prevents dex from completing, so we need
 # to get rid of it.  This prevents us from seeing line numbers in stack traces
 # for stack frames inside libraries.
 #
 # This step can occur much earlier than the main Proguard pass: it needs only
 # gecko-R.jar to have been compiled (as that's where the library R.java files
 # end up), but it does block the main Proguard pass.
-.bundled.proguard.deps: gecko-R.jar $(proguard_config_dir)/strip-libs.cfg
+.bundled.proguard.deps: gecko-R.jar $(proguard_config_dir)/strip-libs.cfg $(PROGUARD_JAR)
 	$(REPORT_BUILD)
 	@$(TOUCH) $@
 	$(JAVA) \
 		-Xmx512m -Xms128m \
-		-jar $(ANDROID_SDK_ROOT)/tools/proguard/lib/proguard.jar \
+		-jar $(PROGUARD_JAR) \
 		@$(proguard_config_dir)/strip-libs.cfg \
 		-injars $(subst ::,:,$(java_bundled_libs))\
 		-outjars bundled-jars-nodebug \
 		-libraryjars $(library_jars):gecko-R.jar
 
 # We touch the target file before invoking Proguard so that Proguard's
 # outputs are fresher than the target, preventing a subsequent
 # invocation from thinking Proguard's outputs are stale.  This is safe
 # because Make removes the target file if any recipe command fails.
-.proguard.deps: .geckoview.deps .bundled.proguard.deps $(ALL_JARS) $(proguard_config_dir)/proguard.cfg
+.proguard.deps: .geckoview.deps .bundled.proguard.deps $(ALL_JARS) $(proguard_config_dir)/proguard.cfg $(PROGUARD_JAR)
 	$(REPORT_BUILD)
 	@$(TOUCH) $@
 	$(JAVA) \
 		-Xmx512m -Xms128m \
-		-jar $(ANDROID_SDK_ROOT)/tools/proguard/lib/proguard.jar \
+		-jar $(PROGUARD_JAR) \
 		@$(proguard_config_dir)/proguard.cfg \
 		-optimizationpasses $(PROGUARD_PASSES) \
 		-injars $(subst ::,:,$(all_jars_classpath)):bundled-jars-nodebug \
 		-outjars jars-proguarded \
 		-libraryjars $(library_jars)
 
 ANNOTATION_PROCESSOR_JAR_FILES := $(abspath $(DEPTH)/build/annotationProcessors/annotationProcessors.jar)
 
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -2131,16 +2131,18 @@ public abstract class GeckoApp extends G
 
                     editor.putBoolean(GeckoApp.PREFS_CLEANUP_TEMP_FILES, false);
                 }
 
                 editor.apply();
             }
         });
 
+        GeckoAppShell.setScreenOrientationDelegate(null);
+
         super.onPause();
     }
 
     @Override
     public void onRestart() {
         if (mIsAbortingAppLaunch) {
             super.onRestart();
             return;
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -2523,29 +2523,29 @@ var NativeWindow = {
         if (uri)
           return uri.schemeIs("tel");
         return false;
       }
     },
 
     imageLocationCopyableContext: {
       matches: function imageLinkCopyableContextMatches(aElement) {
-        if (aElement instanceof Ci.nsIDOMHTMLImageElement) {
+        if (ChromeUtils.getClassName(aElement) === "HTMLImageElement") {
           // The image is blocked by Tap-to-load Images
           if (aElement.hasAttribute("data-ctv-src") && !aElement.hasAttribute("data-ctv-show")) {
             return false;
           }
         }
         return (aElement instanceof Ci.nsIImageLoadingContent && aElement.currentURI);
       }
     },
 
     imageSaveableContext: {
       matches: function imageSaveableContextMatches(aElement) {
-        if (aElement instanceof Ci.nsIDOMHTMLImageElement) {
+        if (ChromeUtils.getClassName(aElement) === "HTMLImageElement") {
           // The image is blocked by Tap-to-load Images
           if (aElement.hasAttribute("data-ctv-src") && !aElement.hasAttribute("data-ctv-show")) {
             return false;
           }
         }
         if (aElement instanceof Ci.nsIImageLoadingContent && aElement.currentURI) {
           // The image must be loaded to allow saving
           let request = aElement.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
@@ -2553,17 +2553,17 @@ var NativeWindow = {
         }
         return false;
       }
     },
 
     imageShareableContext: {
       matches: aElement => {
         let imgSrc = '';
-        if (aElement instanceof Ci.nsIDOMHTMLImageElement) {
+        if (ChromeUtils.getClassName(aElement) === "HTMLImageElement") {
           imgSrc = aElement.src;
         } else if (aElement instanceof Ci.nsIImageLoadingContent &&
             aElement.currentURI &&
             aElement.currentURI.spec) {
           imgSrc = aElement.currentURI.spec;
         }
 
         // In order to share an image, we need to pass the image src over IPC via an Intent (in
@@ -2583,17 +2583,18 @@ var NativeWindow = {
       matches: function mediaSaveableContextMatches(aElement) {
         return (aElement instanceof HTMLVideoElement ||
                aElement instanceof HTMLAudioElement);
       }
     },
 
     imageBlockingPolicyContext: {
       matches: function imageBlockingPolicyContextMatches(aElement) {
-        if (aElement instanceof Ci.nsIDOMHTMLImageElement && aElement.getAttribute("data-ctv-src")) {
+        if (ChromeUtils.getClassName(aElement) === "HTMLImageElement" &&
+            aElement.getAttribute("data-ctv-src")) {
           // Only show the menuitem if we are blocking the image
           if (aElement.getAttribute("data-ctv-show") == "true") {
             return false;
           }
           return true;
         }
         return false;
       }
--- a/mobile/android/components/ImageBlockingPolicy.js
+++ b/mobile/android/components/ImageBlockingPolicy.js
@@ -47,17 +47,17 @@ ImageBlockingPolicy.prototype = {
     // When enabled or when on cellular, and option for cellular-only is selected
     if (this._enabled() == OPTION_NEVER || (this._enabled() == OPTION_WIFI_ONLY && this._usingCellular())) {
       if (contentType === Ci.nsIContentPolicy.TYPE_IMAGE || contentType === Ci.nsIContentPolicy.TYPE_IMAGESET) {
         // Accept any non-http(s) image URLs
         if (!contentLocation.schemeIs("http") && !contentLocation.schemeIs("https")) {
           return Ci.nsIContentPolicy.ACCEPT;
         }
 
-        if (node instanceof Ci.nsIDOMHTMLImageElement) {
+        if (ChromeUtils.getClassName(node) === "HTMLImageElement") {
           // Accept if the user has asked to view the image
           if (node.getAttribute("data-ctv-show") == "true") {
             sendImageSizeTelemetry(node.getAttribute("data-ctv-src"));
             return Ci.nsIContentPolicy.ACCEPT;
           }
 
           setTimeout(() => {
             // Cache the original image URL and swap in our placeholder
--- a/mobile/android/config/mozconfigs/android-api-16-gradle-dependencies/nightly
+++ b/mobile/android/config/mozconfigs/android-api-16-gradle-dependencies/nightly
@@ -48,12 +48,8 @@ STRIP_FLAGS="--strip-debug"
 
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 export MOZ_ANDROID_POCKET=1
 
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
 
 # End ../android-api-16-frontend/nightly.
-
-# Populated after checking out the sources and before building the
-# tree as part of the dependencies task bin/ scripts.
-ac_add_options --with-android-sdk="/builds/worker/.mozbuild/android-sdk-linux"
--- a/mobile/android/config/mozconfigs/common
+++ b/mobile/android/config/mozconfigs/common
@@ -103,8 +103,10 @@ fi
 export SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE=/builds/crash-stats-api.token
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 . "$topsrcdir/build/unix/mozconfig.stdcxx"
 
 JS_BINARY="$topsrcdir/mobile/android/config/js_wrapper.sh"
+
+export PROGUARD_JAR="$topsrcdir/proguard/lib/proguard.jar"
--- a/mobile/android/config/tooltool-manifests/android-frontend/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android-frontend/releng.manifest
@@ -1,18 +1,10 @@
 [
   {
-    "size": 735632692,
-    "visibility": "internal",
-    "digest": "dc4329803b4f941d52d61a32c054e209890c2dd793ac2cbbeadb15e4bd23104f7ba99c113472326c7751dbe99e00238208432a05183d9a01bed13f38297b3b3c",
-    "algorithm": "sha512",
-    "filename": "android-sdk-linux.tar.xz",
-    "unpack": true
-  },
-  {
     "size": 37130176,
     "visibility": "internal",
     "digest": "254eecc06eea407c098417c1dbedf89f59883cdde7e173b0473fa5b34719c967830afa11189c3a9f69dc3f3b9e5fb43469434340e1f8feb378609af965783b48",
     "algorithm": "sha512",
     "filename": "java_home.tar.xz",
     "unpack": true
   },
   {
--- a/mobile/android/config/tooltool-manifests/android-x86/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android-x86/releng.manifest
@@ -4,24 +4,16 @@
     "size": 299040511,
     "visibility": "internal",
     "digest": "0f9ba6efbc5379225ebe13b956b9f19d055654f9b0ae999b1eb18ca836e1665be820bcc05193ba24c9a328a1bfea63fe814c1f364b28ae29266effaa04eedbee",
     "algorithm": "sha512",
     "filename": "android-ndk.tar.bz2",
     "unpack": true
   },
   {
-    "size": 735632692,
-    "visibility": "internal",
-    "digest": "dc4329803b4f941d52d61a32c054e209890c2dd793ac2cbbeadb15e4bd23104f7ba99c113472326c7751dbe99e00238208432a05183d9a01bed13f38297b3b3c",
-    "algorithm": "sha512",
-    "filename": "android-sdk-linux.tar.xz",
-    "unpack": true
-  },
-  {
     "size": 6856444,
     "visibility": "public",
     "unpack": true,
     "digest": "d68dd7d31b0153095ecf5cde5837fb1f95dc6e3f799d496fb764f7afeb9c6095c332467177c3aa54d3749b1901e0d6fa84c42162526e764e8a9d2196a0189861",
     "algorithm": "sha512",
     "filename": "jsshell.tar.xz"
   },
   {
--- a/mobile/android/config/tooltool-manifests/android/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android/releng.manifest
@@ -4,24 +4,16 @@
     "size": 299040511,
     "visibility": "internal",
     "digest": "0f9ba6efbc5379225ebe13b956b9f19d055654f9b0ae999b1eb18ca836e1665be820bcc05193ba24c9a328a1bfea63fe814c1f364b28ae29266effaa04eedbee",
     "algorithm": "sha512",
     "filename": "android-ndk.tar.bz2",
     "unpack": true
   },
   {
-    "size": 735632692,
-    "visibility": "internal",
-    "digest": "dc4329803b4f941d52d61a32c054e209890c2dd793ac2cbbeadb15e4bd23104f7ba99c113472326c7751dbe99e00238208432a05183d9a01bed13f38297b3b3c",
-    "algorithm": "sha512",
-    "filename": "android-sdk-linux.tar.xz",
-    "unpack": true
-  },
-  {
     "size": 6856444,
     "visibility": "public",
     "unpack": true,
     "digest": "d68dd7d31b0153095ecf5cde5837fb1f95dc6e3f799d496fb764f7afeb9c6095c332467177c3aa54d3749b1901e0d6fa84c42162526e764e8a9d2196a0189861",
     "algorithm": "sha512",
     "filename": "jsshell.tar.xz"
   },
   {
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
@@ -79,16 +79,17 @@ import android.os.Bundle;
 import android.os.Environment;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v4.util.SimpleArrayMap;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.HapticFeedbackConstants;
@@ -623,17 +624,17 @@ public class GeckoAppShell
     public static void setNotificationListener(final NotificationListener listener) {
         sNotificationListener = (listener != null) ? listener : DEFAULT_LISTENERS;
     }
 
     public static ScreenOrientationDelegate getScreenOrientationDelegate() {
         return sScreenOrientationDelegate;
     }
 
-    public static void setScreenOrientationDelegate(ScreenOrientationDelegate screenOrientationDelegate) {
+    public static void setScreenOrientationDelegate(@Nullable ScreenOrientationDelegate screenOrientationDelegate) {
         sScreenOrientationDelegate = (screenOrientationDelegate != null) ? screenOrientationDelegate : DEFAULT_LISTENERS;
     }
 
     public static WakeLockDelegate getWakeLockDelegate() {
         return sWakeLockDelegate;
     }
 
     public void setWakeLockDelegate(final WakeLockDelegate delegate) {
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -574,30 +574,27 @@ nsHtml5TreeOperation::CreateMathMLElemen
   }
   return newContent;
 }
 
 void
 nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent)
 {
   nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(aNode));
-  nsCOMPtr<nsIDOMHTMLImageElement> domImageElement = do_QueryInterface(aNode);
+  RefPtr<dom::HTMLImageElement> domImageElement = dom::HTMLImageElement::FromContentOrNull(aNode);
   // NS_ASSERTION(formControl, "Form-associated element did not implement nsIFormControl.");
   // TODO: uncomment the above line when <keygen> (bug 101019) is supported by Gecko
   nsCOMPtr<nsIDOMHTMLFormElement> formElement(do_QueryInterface(aParent));
   NS_ASSERTION(formElement, "The form element doesn't implement nsIDOMHTMLFormElement.");
   // avoid crashing on <keygen>
   if (formControl &&
       !aNode->HasAttr(kNameSpaceID_None, nsGkAtoms::form)) {
     formControl->SetForm(formElement);
   } else if (domImageElement) {
-    RefPtr<dom::HTMLImageElement> imageElement =
-      static_cast<dom::HTMLImageElement*>(domImageElement.get());
-    MOZ_ASSERT(imageElement);
-    imageElement->SetForm(formElement);
+    domImageElement->SetForm(formElement);
   }
 }
 
 nsresult
 nsHtml5TreeOperation::FosterParentText(nsIContent* aStackParent,
                                        char16_t* aBuffer,
                                        uint32_t aLength,
                                        nsIContent* aTable,
--- a/python/mozboot/mozboot/android.py
+++ b/python/mozboot/mozboot/android.py
@@ -169,35 +169,20 @@ def ensure_android(os_name, artifact_mod
     sdk_url = 'https://dl.google.com/android/repository/sdk-tools-{0}-3859397.zip'.format(os_tag)
     ndk_url = android_ndk_url(os_name)
 
     ensure_android_sdk_and_ndk(mozbuild_path, os_name,
                                sdk_path=sdk_path, sdk_url=sdk_url,
                                ndk_path=ndk_path, ndk_url=ndk_url,
                                artifact_mode=artifact_mode)
 
-    if no_interactive:
-        # Cribbed from observation and https://stackoverflow.com/a/38381577.
-        path = os.path.join(mozbuild_path, 'android-sdk-{0}'.format(os_name), 'licenses')
-        ensure_dir(path)
-
-        licenses = {
-            'android-sdk-license': '8933bad161af4178b1185d1a37fbf41ea5269c55',
-            'android-sdk-preview-license': '84831b9409646a918e30573bab4c9c91346d8abd',
-        }
-        for license, tag in licenses.items():
-            lname = os.path.join(path, license)
-            if not os.path.isfile(lname):
-                open(lname, 'w').write('\n{0}\n'.format(tag))
-
-
     # We expect the |sdkmanager| tool to be at
     # ~/.mozbuild/android-sdk-$OS_NAME/tools/bin/sdkmanager.
     sdkmanager_tool = os.path.join(sdk_path, 'tools', 'bin', 'sdkmanager')
-    ensure_android_packages(sdkmanager_tool=sdkmanager_tool)
+    ensure_android_packages(sdkmanager_tool=sdkmanager_tool, no_interactive=no_interactive)
 
 
 def ensure_android_sdk_and_ndk(mozbuild_path, os_name, sdk_path, sdk_url, ndk_path, ndk_url, artifact_mode):
     '''
     Ensure the Android SDK and NDK are found at the given paths.  If not, fetch
     and unpack the SDK and/or NDK from the given URLs into |mozbuild_path/{android-sdk-$OS_NAME,android-ndk-$VER}|.
     '''
 
@@ -223,28 +208,49 @@ def ensure_android_sdk_and_ndk(mozbuild_
     else:
         # The SDK archive used to include a top-level
         # android-sdk-$OS_NAME directory; it no longer does so.  We
         # preserve the old convention to smooth detecting existing SDK
         # installations.
         install_mobile_android_sdk_or_ndk(sdk_url, os.path.join(mozbuild_path, 'android-sdk-{0}'.format(os_name)))
 
 
-def ensure_android_packages(sdkmanager_tool, packages=None):
+def ensure_android_packages(sdkmanager_tool, packages=None, no_interactive=False):
     '''
     Use the given sdkmanager tool (like 'sdkmanager') to install required
     Android packages.
     '''
 
     # This tries to install all the required Android packages.  The user
     # may be prompted to agree to the Android license.
     package_file_name = os.path.abspath(os.path.join(os.path.dirname(__file__), 'android-packages.txt'))
     print(INSTALLING_ANDROID_PACKAGES % open(package_file_name, 'rt').read())
-    subprocess.check_call([sdkmanager_tool,
-                           '--package_file={0}'.format(package_file_name)])
+
+    args = [sdkmanager_tool, '--package_file={0}'.format(package_file_name)]
+    if not no_interactive:
+        subprocess.check_call(args)
+        return
+
+    # Emulate yes.  For a discussion of passing input to check_output,
+    # see https://stackoverflow.com/q/10103551.
+    yes = '\n'.join(['y']*100)
+    proc = subprocess.Popen(args,
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.STDOUT,
+                            stdin=subprocess.PIPE)
+    output, unused_err = proc.communicate(yes)
+
+    retcode = proc.poll()
+    if retcode:
+        cmd = args[0]
+        e = subprocess.CalledProcessError(retcode, cmd)
+        e.output = output
+        raise e
+
+    print(output)
 
 
 def suggest_mozconfig(os_name, artifact_mode=False):
     _mozbuild_path, sdk_path, ndk_path = get_paths(os_name)
     if artifact_mode:
         print(MOBILE_ANDROID_ARTIFACT_MODE_MOZCONFIG_TEMPLATE % (sdk_path))
     else:
         print(MOBILE_ANDROID_MOZCONFIG_TEMPLATE % (sdk_path, ndk_path))
--- a/python/mozboot/mozboot/base.py
+++ b/python/mozboot/mozboot/base.py
@@ -146,17 +146,17 @@ ac_add_options --enable-artifact-builds
 # This should match OLDEST_NON_LEGACY_VERSION from
 # the hg setup wizard in version-control-tools.
 MODERN_MERCURIAL_VERSION = LooseVersion('3.7.3')
 
 # Upgrade Python older than this.
 MODERN_PYTHON_VERSION = LooseVersion('2.7.3')
 
 # Upgrade rust older than this.
-MODERN_RUST_VERSION = LooseVersion('1.19.0')
+MODERN_RUST_VERSION = LooseVersion('1.21.0')
 
 class BaseBootstrapper(object):
     """Base class for system bootstrappers."""
 
     def __init__(self, no_interactive=False):
         self.package_manager_updated = False
         self.no_interactive = no_interactive
         self.state_dir = None
--- a/python/mozbuild/mozbuild/artifacts.py
+++ b/python/mozbuild/mozbuild/artifacts.py
@@ -739,17 +739,23 @@ class ArtifactPersistLimit(PersistLimit)
         files = sorted(self.files, key=lambda f: f.stat.st_atime)
         kept = []
         while len(files) > self.file_limit and \
                 self._files_size >= self.size_limit:
             f = files.pop(0)
             if f.path in self._downloaded_now:
                 kept.append(f)
                 continue
-            fs.remove(f.path)
+            try:
+                fs.remove(f.path)
+            except WindowsError:
+                # For some reason, on automation, we can't remove those files.
+                # So for now, ignore the error.
+                kept.append(f)
+                continue
             self.log(logging.INFO, 'artifact',
                 {'filename': f.path},
                 'Purged artifact {filename}')
             self._files_size -= f.stat.st_size
         self.files = files + kept
 
     def remove_all(self):
         from dlmanager import fs
--- a/python/mozbuild/mozbuild/test/configure/common.py
+++ b/python/mozbuild/mozbuild/test/configure/common.py
@@ -37,17 +37,16 @@ def ensure_exe_extension(path):
     return path
 
 
 class ConfigureTestVFS(object):
     def __init__(self, paths):
         self._paths = set(mozpath.abspath(p) for p in paths)
 
     def exists(self, path):
-        path = mozpath.abspath(path)
         if path in self._paths:
             return True
         if mozpath.basedir(path, [topsrcdir, topobjdir]):
             return os.path.exists(path)
         return False
 
     def isfile(self, path):
         path = mozpath.abspath(path)
@@ -121,16 +120,25 @@ class ConfigureTestSandbox(ConfigureSand
             return ReadOnlyNamespace(
                 CalledProcessError=subprocess.CalledProcessError,
                 check_output=self.check_output,
                 PIPE=subprocess.PIPE,
                 STDOUT=subprocess.STDOUT,
                 Popen=self.Popen,
             )
 
+        if what == 'os.path':
+            return self.imported_os.path
+
+        if what == 'os.path.exists':
+            return self.imported_os.path.exists
+
+        if what == 'os.path.isfile':
+            return self.imported_os.path.isfile
+
         if what == 'os.environ':
             return self._environ
 
         if what == 'ctypes.wintypes':
             return ReadOnlyNamespace(
                 LPCWSTR=0,
                 LPWSTR=1,
                 DWORD=2,
--- a/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
@@ -476,199 +476,258 @@ class TestChecksConfigure(unittest.TestC
             checking for a... 
             DEBUG: a: Trying known-a
             ERROR: Paths provided to find_program must be a list of strings, not %r
         ''' % mozpath.dirname(self.OTHER_A)))
 
     def test_java_tool_checks(self):
         includes = ('util.configure', 'checks.configure', 'java.configure')
 
-        def mock_valid_javac(_, args):
-            if len(args) == 1 and args[0] == '-version':
-                return 0, '1.8', ''
-            self.fail("Unexpected arguments to mock_valid_javac: %s" % args)
-
         # A valid set of tools in a standard location.
         java = mozpath.abspath('/usr/bin/java')
         javah = mozpath.abspath('/usr/bin/javah')
         javac = mozpath.abspath('/usr/bin/javac')
         jar = mozpath.abspath('/usr/bin/jar')
         jarsigner = mozpath.abspath('/usr/bin/jarsigner')
         keytool = mozpath.abspath('/usr/bin/keytool')
+        proguard_jar = mozpath.abspath('/path/to/proguard.jar')
+        old_proguard_jar = mozpath.abspath('/path/to/old_proguard.jar')
+
+        def mock_valid_java(_, args):
+            # Yield valid proguard.jar output with a version based on the given path.
+            stdout = \
+                 'ProGuard, version {version}' + \
+                 'Usage: java proguard.ProGuard [options ...]'
+            args = tuple(args)
+            if args == ('-jar', proguard_jar):
+                return 1, stdout.format(version="5.3.3"), ''
+            elif args == ('-jar', old_proguard_jar):
+                return 1, stdout.format(version="4.2"), ''
+            self.fail("Unexpected arguments to mock_valid_java: %s" % args)
+
+        def mock_valid_javac(_, args):
+            if len(args) == 1 and args[0] == '-version':
+                return 0, '1.8', ''
+            self.fail("Unexpected arguments to mock_valid_javac: %s" % args)
 
         paths = {
-            java: None,
+            java: mock_valid_java,
             javah: None,
             javac: mock_valid_javac,
             jar: None,
             jarsigner: None,
             keytool: None,
+            proguard_jar: mock_valid_java,
         }
 
-        config, out, status = self.get_result(includes=includes, extra_paths=paths)
+        config, out, status = self.get_result(includes=includes, extra_paths=paths,
+                                              environ={
+                                                  'PROGUARD_JAR': proguard_jar,
+                                              })
+        self.assertEqual(out, textwrap.dedent('''\
+             checking for java... %s
+             checking for javah... %s
+             checking for jar... %s
+             checking for jarsigner... %s
+             checking for keytool... %s
+             checking for javac... %s
+             checking for javac version... 1.8
+             checking for proguard.jar version... %s
+        ''' % (java, javah, jar, jarsigner, keytool, javac, proguard_jar)))
         self.assertEqual(status, 0)
         self.assertEqual(config, {
             'JAVA': java,
             'JAVAH': javah,
             'JAVAC': javac,
             'JAR': jar,
             'JARSIGNER': jarsigner,
             'KEYTOOL': keytool,
+            'PROGUARD_JAR': proguard_jar,
         })
-        self.assertEqual(out, textwrap.dedent('''\
-             checking for java... %s
-             checking for javah... %s
-             checking for jar... %s
-             checking for jarsigner... %s
-             checking for keytool... %s
-             checking for javac... %s
-             checking for javac version... 1.8
-        ''' % (java, javah, jar, jarsigner, keytool, javac)))
 
         # An alternative valid set of tools referred to by JAVA_HOME.
         alt_java = mozpath.abspath('/usr/local/bin/java')
         alt_javah = mozpath.abspath('/usr/local/bin/javah')
         alt_javac = mozpath.abspath('/usr/local/bin/javac')
         alt_jar = mozpath.abspath('/usr/local/bin/jar')
         alt_jarsigner = mozpath.abspath('/usr/local/bin/jarsigner')
         alt_keytool = mozpath.abspath('/usr/local/bin/keytool')
         alt_java_home = mozpath.dirname(mozpath.dirname(alt_java))
 
         paths.update({
-            alt_java: None,
+            alt_java: mock_valid_java,
             alt_javah: None,
             alt_javac: mock_valid_javac,
             alt_jar: None,
             alt_jarsigner: None,
             alt_keytool: None,
         })
 
         config, out, status = self.get_result(includes=includes,
                                               extra_paths=paths,
                                               environ={
                                                   'JAVA_HOME': alt_java_home,
-                                                  'PATH': mozpath.dirname(java)
+                                                  'PATH': mozpath.dirname(java),
+                                                  'PROGUARD_JAR': proguard_jar,
                                               })
-        self.assertEqual(status, 0)
-        self.assertEqual(config, {
-            'JAVA': alt_java,
-            'JAVAH': alt_javah,
-            'JAVAC': alt_javac,
-            'JAR': alt_jar,
-            'JARSIGNER': alt_jarsigner,
-            'KEYTOOL': alt_keytool,
-        })
         self.assertEqual(out, textwrap.dedent('''\
              checking for java... %s
              checking for javah... %s
              checking for jar... %s
              checking for jarsigner... %s
              checking for keytool... %s
              checking for javac... %s
              checking for javac version... 1.8
+             checking for proguard.jar version... %s
         ''' % (alt_java, alt_javah, alt_jar, alt_jarsigner,
-               alt_keytool, alt_javac)))
+               alt_keytool, alt_javac, proguard_jar)))
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {
+            'JAVA': alt_java,
+            'JAVAH': alt_javah,
+            'JAVAC': alt_javac,
+            'JAR': alt_jar,
+            'JARSIGNER': alt_jarsigner,
+            'KEYTOOL': alt_keytool,
+            'PROGUARD_JAR': proguard_jar,
+        })
 
         # We can use --with-java-bin-path instead of JAVA_HOME to similar
         # effect.
         config, out, status = self.get_result(
             args=['--with-java-bin-path=%s' % mozpath.dirname(alt_java)],
             includes=includes,
             extra_paths=paths,
             environ={
-                'PATH': mozpath.dirname(java)
+                'PATH': mozpath.dirname(java),
+                'PROGUARD_JAR': proguard_jar,
             })
+        self.assertEqual(out, textwrap.dedent('''\
+             checking for java... %s
+             checking for javah... %s
+             checking for jar... %s
+             checking for jarsigner... %s
+             checking for keytool... %s
+             checking for javac... %s
+             checking for javac version... 1.8
+             checking for proguard.jar version... %s
+        ''' % (alt_java, alt_javah, alt_jar, alt_jarsigner,
+               alt_keytool, alt_javac, proguard_jar)))
         self.assertEqual(status, 0)
         self.assertEqual(config, {
             'JAVA': alt_java,
             'JAVAH': alt_javah,
             'JAVAC': alt_javac,
             'JAR': alt_jar,
             'JARSIGNER': alt_jarsigner,
             'KEYTOOL': alt_keytool,
+            'PROGUARD_JAR': proguard_jar,
         })
-        self.assertEqual(out, textwrap.dedent('''\
-             checking for java... %s
-             checking for javah... %s
-             checking for jar... %s
-             checking for jarsigner... %s
-             checking for keytool... %s
-             checking for javac... %s
-             checking for javac version... 1.8
-        ''' % (alt_java, alt_javah, alt_jar, alt_jarsigner,
-               alt_keytool, alt_javac)))
 
         # If --with-java-bin-path and JAVA_HOME are both set,
         # --with-java-bin-path takes precedence.
         config, out, status = self.get_result(
             args=['--with-java-bin-path=%s' % mozpath.dirname(alt_java)],
             includes=includes,
             extra_paths=paths,
             environ={
                 'PATH': mozpath.dirname(java),
                 'JAVA_HOME': mozpath.dirname(mozpath.dirname(java)),
+                'PROGUARD_JAR': proguard_jar,
             })
+        self.assertEqual(out, textwrap.dedent('''\
+             checking for java... %s
+             checking for javah... %s
+             checking for jar... %s
+             checking for jarsigner... %s
+             checking for keytool... %s
+             checking for javac... %s
+             checking for javac version... 1.8
+             checking for proguard.jar version... %s
+        ''' % (alt_java, alt_javah, alt_jar, alt_jarsigner,
+               alt_keytool, alt_javac, proguard_jar)))
         self.assertEqual(status, 0)
         self.assertEqual(config, {
             'JAVA': alt_java,
             'JAVAH': alt_javah,
             'JAVAC': alt_javac,
             'JAR': alt_jar,
             'JARSIGNER': alt_jarsigner,
             'KEYTOOL': alt_keytool,
+            'PROGUARD_JAR': proguard_jar,
         })
+
+        def mock_old_javac(_, args):
+            if len(args) == 1 and args[0] == '-version':
+                return 0, '1.6.9', ''
+            self.fail("Unexpected arguments to mock_old_javac: %s" % args)
+
+        # An old proguard JAR is fatal.
+        config, out, status = self.get_result(includes=includes,
+                                              extra_paths=paths,
+                                              environ={
+                                                  'PATH': mozpath.dirname(java),
+                                                  'PROGUARD_JAR': old_proguard_jar,
+                                              })
         self.assertEqual(out, textwrap.dedent('''\
              checking for java... %s
              checking for javah... %s
              checking for jar... %s
              checking for jarsigner... %s
              checking for keytool... %s
              checking for javac... %s
              checking for javac version... 1.8
-        ''' % (alt_java, alt_javah, alt_jar, alt_jarsigner,
-               alt_keytool, alt_javac)))
-
-        def mock_old_javac(_, args):
-            if len(args) == 1 and args[0] == '-version':
-                return 0, '1.6.9', ''
-            self.fail("Unexpected arguments to mock_old_javac: %s" % args)
-
-        # An old javac is fatal.
-        paths[javac] = mock_old_javac
-        config, out, status = self.get_result(includes=includes,
-                                              extra_paths=paths,
-                                              environ={
-                                                  'PATH': mozpath.dirname(java)
-                                              })
+             checking for proguard.jar version... 
+             ERROR: proguard.jar 5.3.3 or higher is required (looked for %s). Run |mach artifact install --from-build proguard-jar| or add `export PROGUARD_JAR=/path/to/proguard.jar` to your mozconfig.
+        ''' % (java, javah, jar, jarsigner, keytool, javac, old_proguard_jar)))
         self.assertEqual(status, 1)
         self.assertEqual(config, {
             'JAVA': java,
             'JAVAH': javah,
             'JAVAC': javac,
             'JAR': jar,
             'JARSIGNER': jarsigner,
             'KEYTOOL': keytool,
         })
+
+        # An old javac is fatal.
+        paths[javac] = mock_old_javac
+        config, out, status = self.get_result(includes=includes,
+                                              extra_paths=paths,
+                                              environ={
+                                                  'PATH': mozpath.dirname(java),
+                                                  'PROGUARD_JAR': proguard_jar,
+                                              })
         self.assertEqual(out, textwrap.dedent('''\
              checking for java... %s
              checking for javah... %s
              checking for jar... %s
              checking for jarsigner... %s
              checking for keytool... %s
              checking for javac... %s
              checking for javac version... 
              ERROR: javac 1.8 or higher is required (found 1.6.9). Check the JAVA_HOME environment variable.
         ''' % (java, javah, jar, jarsigner, keytool, javac)))
+        self.assertEqual(status, 1)
+        self.assertEqual(config, {
+            'JAVA': java,
+            'JAVAH': javah,
+            'JAVAC': javac,
+            'JAR': jar,
+            'JARSIGNER': jarsigner,
+            'KEYTOOL': keytool,
+        })
 
         # Any missing tool is fatal when these checks run.
         del paths[jarsigner]
         config, out, status = self.get_result(includes=includes,
                                               extra_paths=paths,
                                               environ={
-                                                  'PATH': mozpath.dirname(java)
+                                                  'PATH': mozpath.dirname(java),
+                                                  'PROGUARD_JAR': proguard_jar,
                                               })
         self.assertEqual(status, 1)
         self.assertEqual(config, {
             'JAVA': java,
             'JAVAH': javah,
             'JAR': jar,
             'JARSIGNER': ':',
         })
--- a/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
@@ -1536,16 +1536,22 @@ class RustTest(BaseConfigureTest):
             'sparc64-unknown-linux-gnu',
             'i686-unknown-linux-gnu',
             'i686-apple-darwin',
             'x86_64-apple-darwin',
             'aarch64-apple-ios',
             'armv7s-apple-ios',
             'i386-apple-ios',
             'x86_64-apple-ios',
+            'mips-unknown-linux-gnu',
+            'mipsel-unknown-linux-gnu',
+            'mips64-unknown-linux-gnuabi64',
+            'mips64el-unknown-linux-gnuabi64',
+            'powerpc64-unknown-linux-gnu',
+            'powerpc64le-unknown-linux-gnu',
         ):
             self.assertEqual(self.get_rust_target(straightforward), straightforward)
 
         # Cases where the output of config.sub is different
         for autoconf, rust in (
             ('aarch64-unknown-linux-android', 'aarch64-linux-android'),
             ('arm-unknown-linux-androideabi', 'armv7-linux-androideabi'),
             ('armv7-unknown-linux-androideabi', 'armv7-linux-androideabi'),
--- a/services/sync/modules/engines/passwords.js
+++ b/services/sync/modules/engines/passwords.js
@@ -46,16 +46,24 @@ function isSyncableChange(oldLogin, newL
 }
 
 this.LoginRec = function LoginRec(collection, id) {
   CryptoWrapper.call(this, collection, id);
 }
 LoginRec.prototype = {
   __proto__: CryptoWrapper.prototype,
   _logName: "Sync.Record.Login",
+
+  cleartextToString() {
+    let o = Object.assign({}, this.cleartext);
+    if (o.password) {
+      o.password = "X".repeat(o.password.length)
+    }
+    return JSON.stringify(o);
+  }
 };
 
 Utils.deferGetSet(LoginRec, "cleartext", [
     "hostname", "formSubmitURL",
     "httpRealm", "username", "password", "usernameField", "passwordField",
     "timeCreated", "timePasswordChanged",
     ]);
 
--- a/services/sync/tests/unit/test_password_store.js
+++ b/services/sync/tests/unit/test_password_store.js
@@ -136,16 +136,21 @@ async function test_apply_same_record_wi
   timePasswordChanged = await changePassword("A", "http://a.tn", "password2", 1, 500,
                                        100, 1536213005222, timePasswordChanged,
                                        true, true);
   timePasswordChanged = await changePassword("A", "http://a.tn", "password2", 1, 500,
                                        100, 800, timePasswordChanged, true, true);
   /* eslint-enable no-unsed-vars */
 }
 
+async function test_LoginRec_toString(store, recordData) {
+  let rec = await store.createRecord(recordData.id);
+  ok(rec);
+  ok(!rec.toString().includes(rec.password));
+}
 
 add_task(async function run_test() {
   initTestLogging("Trace");
   Log.repository.getLogger("Sync.Engine.Passwords").level = Log.Level.Trace;
   Log.repository.getLogger("Sync.Store.Passwords").level = Log.Level.Trace;
 
   const BOGUS_GUID_A = "zzzzzzzzzzzz";
   const BOGUS_GUID_B = "yyyyyyyyyyyy";
@@ -185,16 +190,18 @@ add_task(async function run_test() {
     _("Count: " + badCount.value + ", " + goodCount.value);
 
     do_check_eq(goodCount.value, 1);
     do_check_eq(badCount.value, 0);
 
     do_check_true(!!(await store.getAllIDs())[BOGUS_GUID_B]);
     do_check_true(!(await store.getAllIDs())[BOGUS_GUID_A]);
 
+    await test_LoginRec_toString(store, recordB);
+
     await test_apply_records_with_times("http://afoo.baz.com", undefined, undefined);
     await test_apply_records_with_times("http://bfoo.baz.com", 1000, undefined);
     await test_apply_records_with_times("http://cfoo.baz.com", undefined, 2000);
     await test_apply_records_with_times("http://dfoo.baz.com", 1000, 2000);
 
     await test_apply_multiple_records_with_times();
 
     await test_apply_same_record_with_different_times();
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -321,16 +321,17 @@ name = "canvas_traits"
 version = "0.0.1"
 dependencies = [
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nonzero 0.0.1",
  "offscreen_gl_context 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "webrender_api 0.52.1 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "caseless"
@@ -467,16 +468,17 @@ dependencies = [
  "euclid 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
+ "nonzero 0.0.1",
  "profile_traits 0.0.1",
  "script_traits 0.0.1",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.52.1 (git+https://github.com/servo/webrender)",
@@ -1559,16 +1561,17 @@ dependencies = [
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "layout 0.0.1",
  "layout_traits 0.0.1",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "metrics 0.0.1",
  "msg 0.0.1",
  "net_traits 0.0.1",
+ "nonzero 0.0.1",
  "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "profile_traits 0.0.1",
  "range 0.0.1",
  "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "script 0.0.1",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.19.0",
@@ -1901,16 +1904,17 @@ dependencies = [
 
 [[package]]
 name = "msg"
 version = "0.0.1"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nonzero 0.0.1",
  "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_api 0.52.1 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "msg_tests"
 version = "0.0.1"
 dependencies = [
@@ -2041,16 +2045,23 @@ dependencies = [
 ]
 
 [[package]]
 name = "nom"
 version = "1.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "nonzero"
+version = "0.0.1"
+dependencies = [
+ "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "nsstring_vendor"
 version = "0.1.0"
 dependencies = [
  "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "num-integer"
@@ -2659,16 +2670,17 @@ dependencies = [
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "metrics 0.0.1",
  "msg 0.0.1",
  "net_traits 0.0.1",
+ "nonzero 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.19.0",
  "servo_arc 0.0.1",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
@@ -2977,16 +2989,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "servo_remutex"
 version = "0.0.1"
 dependencies = [
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nonzero 0.0.1",
 ]
 
 [[package]]
 name = "servo_remutex_tests"
 version = "0.0.1"
 dependencies = [
  "servo_remutex 0.0.1",
 ]
--- a/servo/components/canvas_traits/Cargo.toml
+++ b/servo/components/canvas_traits/Cargo.toml
@@ -11,12 +11,13 @@ path = "lib.rs"
 
 [dependencies]
 cssparser = "0.22.0"
 euclid = "0.15"
 heapsize = "0.4"
 heapsize_derive = "0.1"
 ipc-channel = "0.8"
 lazy_static = "0.2"
+nonzero = {path = "../nonzero"}
 offscreen_gl_context = { version = "0.11", features = ["serde"] }
 serde = "1.0"
 servo_config = {path = "../config"}
 webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/canvas_traits/lib.rs
+++ b/servo/components/canvas_traits/lib.rs
@@ -1,25 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #![crate_name = "canvas_traits"]
 #![crate_type = "rlib"]
-#![feature(nonzero)]
 
 #![deny(unsafe_code)]
 
-extern crate core;
 extern crate cssparser;
 extern crate euclid;
 extern crate heapsize;
 #[macro_use] extern crate heapsize_derive;
 extern crate ipc_channel;
 #[macro_use] extern crate lazy_static;
+extern crate nonzero;
 extern crate offscreen_gl_context;
 #[macro_use] extern crate serde;
 extern crate servo_config;
 extern crate webrender_api;
 
 pub mod canvas;
 pub mod webgl;
 mod webgl_channel;
--- a/servo/components/canvas_traits/webgl.rs
+++ b/servo/components/canvas_traits/webgl.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use core::nonzero::NonZero;
 use euclid::Size2D;
+use nonzero::NonZeroU32;
 use offscreen_gl_context::{GLContextAttributes, GLLimits};
 use std::fmt;
 use webrender_api;
 
 /// Sender type used in WebGLCommands.
 pub use ::webgl_channel::WebGLSender;
 /// Receiver type used in WebGLCommands.
 pub use ::webgl_channel::WebGLReceiver;
@@ -237,23 +237,23 @@ pub enum WebGLCommand {
     CreateVertexArray(WebGLSender<Option<WebGLVertexArrayId>>),
     DeleteVertexArray(WebGLVertexArrayId),
     BindVertexArray(Option<WebGLVertexArrayId>),
 }
 
 macro_rules! define_resource_id_struct {
     ($name:ident) => {
         #[derive(Clone, Copy, Eq, Hash, PartialEq)]
-        pub struct $name(NonZero<u32>);
+        pub struct $name(NonZeroU32);
 
         impl $name {
             #[allow(unsafe_code)]
             #[inline]
             pub unsafe fn new(id: u32) -> Self {
-                $name(NonZero::new_unchecked(id))
+                $name(NonZeroU32::new_unchecked(id))
             }
 
             #[inline]
             pub fn get(self) -> u32 {
                 self.0.get()
             }
         }
 
--- a/servo/components/compositing/Cargo.toml
+++ b/servo/components/compositing/Cargo.toml
@@ -13,17 +13,18 @@ path = "lib.rs"
 euclid = "0.15"
 gfx_traits = {path = "../gfx_traits"}
 gleam = "0.4"
 image = "0.16"
 ipc-channel = "0.8"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
+nonzero = {path = "../nonzero"}
 profile_traits = {path = "../profile_traits"}
 script_traits = {path = "../script_traits"}
 servo_config = {path = "../config"}
-servo_geometry = {path = "../geometry", features = ["servo"]}
+servo_geometry = {path = "../geometry"}
 servo_url = {path = "../url"}
 style_traits = {path = "../style_traits"}
 time = "0.1.17"
 webrender = {git = "https://github.com/servo/webrender"}
 webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/compositing/compositor.rs
+++ b/servo/components/compositing/compositor.rs
@@ -1,24 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use CompositionPipeline;
 use SendableFrameTree;
 use compositor_thread::{CompositorProxy, CompositorReceiver};
 use compositor_thread::{InitialCompositorState, Msg, RenderListener};
-use core::nonzero::NonZero;
 use euclid::{Point2D, TypedPoint2D, TypedVector2D, ScaleFactor};
 use gfx_traits::Epoch;
 use gleam::gl;
 use image::{DynamicImage, ImageFormat, RgbImage};
 use ipc_channel::ipc::{self, IpcSharedMemory};
 use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId};
 use net_traits::image::base::{Image, PixelFormat};
+use nonzero::NonZeroU32;
 use profile_traits::time::{self, ProfilerCategory, profile};
 use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg};
 use script_traits::{ConstellationMsg, LayoutControlMsg, MouseButton};
 use script_traits::{MouseEventType, ScrollState};
 use script_traits::{TouchpadPressurePhase, TouchEventType, TouchId, WindowSizeData, WindowSizeType};
 use script_traits::CompositorEvent::{self, MouseMoveEvent, MouseButtonEvent, TouchEvent, TouchpadPressureEvent};
 use servo_config::opts;
 use servo_config::prefs::PREFS;
@@ -57,17 +57,17 @@ const MIN_ZOOM: f32 = 0.1;
 trait ConvertPipelineIdFromWebRender {
     fn from_webrender(&self) -> PipelineId;
 }
 
 impl ConvertPipelineIdFromWebRender for webrender_api::PipelineId {
     fn from_webrender(&self) -> PipelineId {
         PipelineId {
             namespace_id: PipelineNamespaceId(self.0),
-            index: PipelineIndex(NonZero::new(self.1).expect("Webrender pipeline zero?")),
+            index: PipelineIndex(NonZeroU32::new(self.1).expect("Webrender pipeline zero?")),
         }
     }
 }
 
 /// Holds the state when running reftests that determines when it is
 /// safe to save the output image.
 #[derive(Clone, Copy, PartialEq)]
 enum ReadyState {
--- a/servo/components/compositing/lib.rs
+++ b/servo/components/compositing/lib.rs
@@ -1,25 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #![deny(unsafe_code)]
-#![feature(nonzero)]
 
-extern crate core;
 extern crate euclid;
 extern crate gfx_traits;
 extern crate gleam;
 extern crate image;
 extern crate ipc_channel;
 #[macro_use]
 extern crate log;
 extern crate msg;
 extern crate net_traits;
+extern crate nonzero;
 extern crate profile_traits;
 extern crate script_traits;
 extern crate servo_config;
 extern crate servo_geometry;
 extern crate servo_url;
 extern crate style_traits;
 extern crate time;
 extern crate webrender;
--- a/servo/components/constellation/constellation.rs
+++ b/servo/components/constellation/constellation.rs
@@ -767,48 +767,82 @@ impl<Message, LTF, STF> Constellation<Me
 
     /// Get an iterator for the browsing contexts in a tree.
     fn all_browsing_contexts_iter(&self, top_level_browsing_context_id: TopLevelBrowsingContextId)
                                   -> AllBrowsingContextsIterator
     {
         self.all_descendant_browsing_contexts_iter(BrowsingContextId::from(top_level_browsing_context_id))
     }
 
+    #[cfg(feature = "unstable")]
     /// The joint session future is the merge of the session future of every
     /// browsing_context, sorted chronologically.
     fn joint_session_future<'a>(&'a self, top_level_browsing_context_id: TopLevelBrowsingContextId)
                                 -> impl Iterator<Item = &'a SessionHistoryEntry> + 'a
     {
         self.all_browsing_contexts_iter(top_level_browsing_context_id)
             .map(|browsing_context| browsing_context.next.iter().rev())
             .kmerge_by(|a, b| a.instant.cmp(&b.instant) == Ordering::Less)
     }
 
+    #[cfg(not(feature = "unstable"))]
+    /// The joint session future is the merge of the session future of every
+    /// browsing_context, sorted chronologically.
+    fn joint_session_future<'a>(&'a self, top_level_browsing_context_id: TopLevelBrowsingContextId)
+                                -> Box<Iterator<Item = &'a SessionHistoryEntry> + 'a>
+    {
+        Box::new(
+            self.all_browsing_contexts_iter(top_level_browsing_context_id)
+                .map(|browsing_context| browsing_context.next.iter().rev())
+                .kmerge_by(|a, b| a.instant.cmp(&b.instant) == Ordering::Less)
+        )
+    }
+
     /// Is the joint session future empty?
     fn joint_session_future_is_empty(&self, top_level_browsing_context_id: TopLevelBrowsingContextId) -> bool {
         self.all_browsing_contexts_iter(top_level_browsing_context_id)
             .all(|browsing_context| browsing_context.next.is_empty())
     }
 
+    #[cfg(feature = "unstable")]
     /// The joint session past is the merge of the session past of every
     /// browsing_context, sorted reverse chronologically.
     fn joint_session_past<'a>(&'a self, top_level_browsing_context_id: TopLevelBrowsingContextId)
                               -> impl Iterator<Item = &'a SessionHistoryEntry> + 'a
     {
         self.all_browsing_contexts_iter(top_level_browsing_context_id)
             .map(|browsing_context| browsing_context.prev.iter().rev()
                  .scan(browsing_context.instant, |prev_instant, entry| {
                      let instant = *prev_instant;
                      *prev_instant = entry.instant;
                      Some((instant, entry))
                  }))
             .kmerge_by(|a, b| a.0.cmp(&b.0) == Ordering::Greater)
             .map(|(_, entry)| entry)
     }
 
+    #[cfg(not(feature = "unstable"))]
+    /// The joint session past is the merge of the session past of every
+    /// browsing_context, sorted reverse chronologically.
+    fn joint_session_past<'a>(&'a self, top_level_browsing_context_id: TopLevelBrowsingContextId)
+                              -> Box<Iterator<Item = &'a SessionHistoryEntry> + 'a>
+    {
+        Box::new(
+            self.all_browsing_contexts_iter(top_level_browsing_context_id)
+                .map(|browsing_context| browsing_context.prev.iter().rev()
+                     .scan(browsing_context.instant, |prev_instant, entry| {
+                         let instant = *prev_instant;
+                         *prev_instant = entry.instant;
+                         Some((instant, entry))
+                     }))
+                .kmerge_by(|a, b| a.0.cmp(&b.0) == Ordering::Greater)
+                .map(|(_, entry)| entry)
+        )
+    }
+
     /// Is the joint session past empty?
     fn joint_session_past_is_empty(&self, top_level_browsing_context_id: TopLevelBrowsingContextId) -> bool {
         self.all_browsing_contexts_iter(top_level_browsing_context_id)
             .all(|browsing_context| browsing_context.prev.is_empty())
     }
 
     /// Create a new browsing context and update the internal bookkeeping.
     fn new_browsing_context(&mut self,
--- a/servo/components/constellation/lib.rs
+++ b/servo/components/constellation/lib.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #![deny(unsafe_code)]
-#![feature(conservative_impl_trait)]
+#![cfg_attr(feature = "unstable", feature(conservative_impl_trait))]
 #![feature(mpsc_select)]
 
 extern crate backtrace;
 extern crate bluetooth_traits;
 extern crate canvas;
 extern crate canvas_traits;
 extern crate clipboard;
 extern crate compositing;
--- a/servo/components/geometry/Cargo.toml
+++ b/servo/components/geometry/Cargo.toml
@@ -4,16 +4,12 @@ version = "0.0.1"
 authors = ["The Servo Project Developers"]
 license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "servo_geometry"
 path = "lib.rs"
 
-[features]
-# servo as opposed to geckolib
-servo = ["euclid/unstable"]
-
 [dependencies]
 app_units = "0.5"
 euclid = "0.15"
 heapsize = "0.4"
--- a/servo/components/gfx/Cargo.toml
+++ b/servo/components/gfx/Cargo.toml
@@ -5,16 +5,19 @@ version = "0.0.1"
 authors = ["The Servo Project Developers"]
 license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "gfx"
 path = "lib.rs"
 
+[features]
+unstable = ["simd"]
+
 [dependencies]
 app_units = "0.5"
 bitflags = "0.7"
 euclid = "0.15"
 fnv = "1.0"
 fontsan = {git = "https://github.com/servo/fontsan"}
 gfx_traits = {path = "../gfx_traits"}
 harfbuzz-sys = "0.1"
@@ -53,13 +56,13 @@ freetype = "0.3"
 
 [target.'cfg(target_os = "linux")'.dependencies]
 servo-fontconfig = "0.2.1"
 
 [target.'cfg(target_os = "android")'.dependencies]
 xml5ever = {version = "0.10"}
 
 [target.'cfg(any(target_feature = "sse2", target_feature = "neon"))'.dependencies]
-simd = "0.2.0"
+simd = {version = "0.2.0", optional = true}
 
 [target.'cfg(target_os = "windows")'.dependencies]
 dwrote = "0.4"
 truetype = "0.26"
--- a/servo/components/gfx/lib.rs
+++ b/servo/components/gfx/lib.rs
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // For SIMD
-#![cfg_attr(any(target_os = "linux", target_os = "android"), feature(allocator_api))]
-#![feature(cfg_target_feature)]
+#![cfg_attr(feature = "unstable", feature(cfg_target_feature))]
 
 #![deny(unsafe_code)]
 
 extern crate app_units;
 #[macro_use]
 extern crate bitflags;
 
 // Mac OS-specific library dependencies
@@ -48,16 +47,17 @@ extern crate msg;
 extern crate net_traits;
 extern crate ordered_float;
 extern crate range;
 #[macro_use] extern crate serde;
 extern crate servo_arc;
 extern crate servo_geometry;
 extern crate servo_url;
 #[macro_use] extern crate servo_atoms;
+#[cfg(feature = "unstable")]
 #[cfg(any(target_feature = "sse2", target_feature = "neon"))]
 extern crate simd;
 extern crate smallvec;
 extern crate style;
 extern crate style_traits;
 extern crate time;
 extern crate unicode_bidi;
 extern crate unicode_script;
--- a/servo/components/gfx/platform/freetype/font_context.rs
+++ b/servo/components/gfx/platform/freetype/font_context.rs
@@ -4,72 +4,85 @@
 
 use freetype::freetype::FT_Add_Default_Modules;
 use freetype::freetype::FT_Done_Library;
 use freetype::freetype::FT_Library;
 use freetype::freetype::FT_Memory;
 use freetype::freetype::FT_MemoryRec_;
 use freetype::freetype::FT_New_Library;
 use heapsize::{HeapSizeOf, heap_size_of};
-use std::heap::{Heap, Alloc, Layout};
+use std::mem;
 use std::os::raw::{c_long, c_void};
 use std::ptr;
 use std::rc::Rc;
 
 // We pass a |User| struct -- via an opaque |void*| -- to FreeType each time a new instance is
 // created. FreeType passes it back to the ft_alloc/ft_realloc/ft_free callbacks. We use it to
 // record the memory usage of each FreeType instance.
 pub struct User {
     size: usize,
 }
 
 // FreeType doesn't require any particular alignment for allocations.
 const FT_ALIGNMENT: usize = 1;
 
 extern fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void {
+    assert!(FT_ALIGNMENT == 1);
+    let mut vec = Vec::<u8>::with_capacity(req_size as usize);
+    let ptr = vec.as_mut_ptr() as *mut c_void;
+    mem::forget(vec);
+
     unsafe {
-        let layout = Layout::from_size_align(req_size as usize, FT_ALIGNMENT).unwrap();
-        let ptr = Heap.alloc(layout).unwrap() as *mut c_void;
         let actual_size = heap_size_of(ptr as *const _);
-
         let user = (*mem).user as *mut User;
         (*user).size += actual_size;
+    }
 
-        ptr
-    }
+    ptr
 }
 
 extern fn ft_free(mem: FT_Memory, ptr: *mut c_void) {
     unsafe {
         let actual_size = heap_size_of(ptr as *const _);
-
         let user = (*mem).user as *mut User;
         (*user).size -= actual_size;
 
-        let layout = Layout::from_size_align(actual_size, FT_ALIGNMENT).unwrap();
-        Heap.dealloc(ptr as *mut u8, layout);
+        assert!(FT_ALIGNMENT == 1);
+        mem::drop(Vec::<u8>::from_raw_parts(ptr as *mut u8, actual_size, 0))
     }
 }
 
 extern fn ft_realloc(mem: FT_Memory, _cur_size: c_long, new_req_size: c_long,
                      old_ptr: *mut c_void) -> *mut c_void {
+    let old_actual_size;
+    let mut vec;
     unsafe {
-        let old_actual_size = heap_size_of(old_ptr as *const _);
-        let old_layout = Layout::from_size_align(old_actual_size, FT_ALIGNMENT).unwrap();
-        let new_layout = Layout::from_size_align(new_req_size as usize, FT_ALIGNMENT).unwrap();
-        let result = Heap.realloc(old_ptr as *mut u8, old_layout, new_layout);
-        let new_ptr = result.unwrap() as *mut c_void;
+        old_actual_size = heap_size_of(old_ptr as *const _);
+        vec = Vec::<u8>::from_raw_parts(old_ptr as *mut u8, old_actual_size, old_actual_size);
+    };
+
+    let new_req_size = new_req_size as usize;
+    if new_req_size > old_actual_size {
+        vec.reserve_exact(new_req_size - old_actual_size)
+    } else if new_req_size < old_actual_size {
+        vec.truncate(new_req_size);
+        vec.shrink_to_fit()
+    }
+
+    let new_ptr = vec.as_mut_ptr() as *mut c_void;
+    mem::forget(vec);
+
+    unsafe {
         let new_actual_size = heap_size_of(new_ptr as *const _);
-
         let user = (*mem).user as *mut User;
         (*user).size += new_actual_size;
         (*user).size -= old_actual_size;
+    }
 
-        new_ptr
-    }
+    new_ptr
 }
 
 // A |*mut User| field in a struct triggers a "use of `#[derive]` with a raw pointer" warning from
 // rustc. But using a typedef avoids this, so...
 pub type UserPtr = *mut User;
 
 // WARNING: We need to be careful how we use this struct. See the comment about Rc<> in
 // FontContextHandle.
--- a/servo/components/gfx/text/glyph.rs
+++ b/servo/components/gfx/text/glyph.rs
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use app_units::Au;
 use euclid::Point2D;
 use range::{self, EachIndex, Range, RangeIndex};
-#[cfg(any(target_feature = "sse2", target_feature = "neon"))]
+#[cfg(all(feature = "unstable", any(target_feature = "sse2", target_feature = "neon")))]
 use simd::u32x4;
 use std::{fmt, mem, u16};
 use std::cmp::{Ordering, PartialOrd};
 use std::vec::Vec;
 
 pub use gfx_traits::ByteIndex;
 
 /// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
@@ -69,16 +69,17 @@ impl GlyphEntry {
 }
 
 /// The id of a particular glyph within a font
 pub type GlyphId = u32;
 
 // TODO: make this more type-safe.
 
 const FLAG_CHAR_IS_SPACE: u32       = 0x40000000;
+#[cfg(feature = "unstable")]
 #[cfg(any(target_feature = "sse2", target_feature = "neon"))]
 const FLAG_CHAR_IS_SPACE_SHIFT: u32 = 30;
 const FLAG_IS_SIMPLE_GLYPH: u32     = 0x80000000;
 
 // glyph advance; in Au's.
 const GLYPH_ADVANCE_MASK: u32       = 0x3FFF0000;
 const GLYPH_ADVANCE_SHIFT: u32      = 16;
 const GLYPH_ID_MASK: u32            = 0x0000FFFF;
@@ -586,16 +587,17 @@ impl<'a> GlyphStore {
                     advance + glyph.advance() + extra_word_spacing
                 } else {
                     advance + glyph.advance()
                 }
             })
     }
 
     #[inline]
+    #[cfg(feature = "unstable")]
     #[cfg(any(target_feature = "sse2", target_feature = "neon"))]
     fn advance_for_byte_range_simple_glyphs(&self, range: &Range<ByteIndex>, extra_word_spacing: Au) -> Au {
         let advance_mask = u32x4::splat(GLYPH_ADVANCE_MASK);
         let space_flag_mask = u32x4::splat(FLAG_CHAR_IS_SPACE);
         let mut simd_advance = u32x4::splat(0);
         let mut simd_spaces = u32x4::splat(0);
         let begin = range.begin().to_usize();
         let len = range.length().to_usize();
@@ -629,23 +631,24 @@ impl<'a> GlyphStore {
                 leftover_spaces += 1;
             }
         }
         Au::new(advance) + leftover_advance + extra_word_spacing * (spaces + leftover_spaces)
     }
 
     /// When SIMD isn't available, fallback to the slow path.
     #[inline]
-    #[cfg(not(any(target_feature = "sse2", target_feature = "neon")))]
+    #[cfg(not(all(feature = "unstable", any(target_feature = "sse2", target_feature = "neon"))))]
     fn advance_for_byte_range_simple_glyphs(&self, range: &Range<ByteIndex>, extra_word_spacing: Au) -> Au {
         self.advance_for_byte_range_slow_path(range, extra_word_spacing)
     }
 
     /// Used for SIMD.
     #[inline]
+    #[cfg(feature = "unstable")]
     #[cfg(any(target_feature = "sse2", target_feature = "neon"))]
     #[allow(unsafe_code)]
     fn transmute_entry_buffer_to_u32_buffer(&self) -> &[u32] {
         unsafe { mem::transmute(self.entry_buffer.as_slice()) }
     }
 
     pub fn char_is_space(&self, i: ByteIndex) -> bool {
         assert!(i < self.len());
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -16,17 +16,17 @@ use canvas_traits::canvas::{CanvasMsg, F
 use context::LayoutContext;
 use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, TypedSize2D};
 use euclid::Vector2D;
 use flex::FlexFlow;
 use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
 use flow_ref::FlowRef;
 use fnv::FnvHashMap;
 use fragment::{CanvasFragmentSource, CoordinateSystem, Fragment, ImageFragmentInfo, ScannedTextFragmentInfo};
-use fragment::{SpecificFragmentInfo, TruncatedFragmentInfo};
+use fragment::SpecificFragmentInfo;
 use gfx::display_list;
 use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails, BorderDisplayItem};
 use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClipScrollNode};
 use gfx::display_list::{ClipScrollNodeType, ClippingRegion, DisplayItem, DisplayItemMetadata};
 use gfx::display_list::{DisplayList, DisplayListSection, GradientDisplayItem, IframeDisplayItem};
 use gfx::display_list::{ImageBorder, ImageDisplayItem, LineDisplayItem, NormalBorder, OpaqueNode};
 use gfx::display_list::{PopTextShadowDisplayItem, PushTextShadowDisplayItem};
 use gfx::display_list::{RadialGradientDisplayItem, SolidColorDisplayItem, StackingContext};
@@ -2007,34 +2007,49 @@ impl FragmentDisplayListBuilding for Fra
                                            radii.to_border_radius(),
                  ))
             } else {
                 LocalClip::Rect(stacking_relative_border_box.to_rectf())
             }
         };
 
         match self.specific {
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: Some(ref text_fragment),
-                ..
-            }) |
-            SpecificFragmentInfo::ScannedText(box ref text_fragment) => {
+            SpecificFragmentInfo::TruncatedFragment(ref truncated_fragment)
+            if truncated_fragment.text_info.is_some() => {
+                let text_fragment = truncated_fragment.text_info.as_ref().unwrap();
                 // Create the main text display item.
                 self.build_display_list_for_text_fragment(state,
-                                                          &*text_fragment,
+                                                          &text_fragment,
                                                           &stacking_relative_content_box,
                                                           &self.style.get_inheritedtext().text_shadow.0,
                                                           clip);
 
                 if opts::get().show_debug_fragment_borders {
                     self.build_debug_borders_around_text_fragments(state,
                                                                    self.style(),
                                                                    stacking_relative_border_box,
                                                                    &stacking_relative_content_box,
-                                                                   &*text_fragment,
+                                                                   &text_fragment,
+                                                                   clip);
+                }
+            }
+            SpecificFragmentInfo::ScannedText(ref text_fragment) => {
+                // Create the main text display item.
+                self.build_display_list_for_text_fragment(state,
+                                                          &text_fragment,
+                                                          &stacking_relative_content_box,
+                                                          &self.style.get_inheritedtext().text_shadow.0,
+                                                          clip);
+
+                if opts::get().show_debug_fragment_borders {
+                    self.build_debug_borders_around_text_fragments(state,
+                                                                   self.style(),
+                                                                   stacking_relative_border_box,
+                                                                   &stacking_relative_content_box,
+                                                                   &text_fragment,
                                                                    clip);
                 }
             }
             SpecificFragmentInfo::Generic |
             SpecificFragmentInfo::GeneratedContent(..) |
             SpecificFragmentInfo::Table |
             SpecificFragmentInfo::TableCell |
             SpecificFragmentInfo::TableRow |
--- a/servo/components/layout/flow.rs
+++ b/servo/components/layout/flow.rs
@@ -27,29 +27,29 @@
 
 use app_units::Au;
 use block::{BlockFlow, FormattingContextType};
 use context::LayoutContext;
 use display_list_builder::{DisplayListBuildState, StackingContextCollectionState};
 use euclid::{Transform3D, Point2D, Vector2D, Rect, Size2D};
 use flex::FlexFlow;
 use floats::{Floats, SpeculatedFloatPlacement};
-use flow_list::{FlowList, MutFlowListIterator};
+use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
 use flow_ref::{FlowRef, WeakFlowRef};
 use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx_traits::StackingContextId;
 use gfx_traits::print_tree::PrintTree;
 use inline::InlineFlow;
 use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
 use msg::constellation_msg::PipelineId;
 use multicol::MulticolFlow;
 use parallel::FlowParallelInfo;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 use servo_geometry::{au_rect_to_f32_rect, f32_rect_to_au_rect, max_rect};
-use std::{fmt, mem, raw};
+use std::{fmt, mem};
 use std::iter::Zip;
 use std::slice::IterMut;
 use std::sync::Arc;
 use std::sync::atomic::Ordering;
 use style::computed_values::{clear, float, overflow_x, position, text_align};
 use style::context::SharedStyleContext;
 use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
 use style::properties::ComputedValues;
@@ -448,31 +448,31 @@ pub trait Flow: fmt::Debug + Sync + Send
 }
 
 // Base access
 
 #[inline(always)]
 #[allow(unsafe_code)]
 pub fn base<T: ?Sized + Flow>(this: &T) -> &BaseFlow {
     unsafe {
-        let obj = mem::transmute::<&&T, &raw::TraitObject>(&this);
+        let obj = mem::transmute::<&&T, &::TraitObject>(&this);
         mem::transmute::<*mut (), &BaseFlow>(obj.data)
     }
 }
 
 /// Iterates over the children of this immutable flow.
-pub fn child_iter<'a>(flow: &'a Flow) -> impl Iterator<Item = &'a Flow> {
+pub fn child_iter<'a>(flow: &'a Flow) -> FlowListIterator {
     base(flow).children.iter()
 }
 
 #[inline(always)]
 #[allow(unsafe_code)]
 pub fn mut_base<T: ?Sized + Flow>(this: &mut T) -> &mut BaseFlow {
     unsafe {
-        let obj = mem::transmute::<&&mut T, &raw::TraitObject>(&this);
+        let obj = mem::transmute::<&&mut T, &::TraitObject>(&this);
         mem::transmute::<*mut (), &mut BaseFlow>(obj.data)
     }
 }
 
 /// Iterates over the children of this flow.
 pub fn child_iter_mut<'a>(flow: &'a mut Flow) -> MutFlowListIterator<'a> {
     mut_base(flow).children.iter_mut()
 }
@@ -1417,13 +1417,13 @@ impl ContainingBlockLink {
 /// equality with other such pointer addresses, never dereferenced.
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub struct OpaqueFlow(pub usize);
 
 impl OpaqueFlow {
     #[allow(unsafe_code)]
     pub fn from_flow(flow: &Flow) -> OpaqueFlow {
         unsafe {
-            let object = mem::transmute::<&Flow, raw::TraitObject>(flow);
+            let object = mem::transmute::<&Flow, ::TraitObject>(flow);
             OpaqueFlow(object.data as usize)
         }
     }
 }
--- a/servo/components/layout/flow_list.rs
+++ b/servo/components/layout/flow_list.rs
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use flow::{Flow, FlowClass};
 use flow_ref::FlowRef;
 use serde::ser::{Serialize, SerializeSeq, Serializer};
 use serde_json::{Map, Value, to_value};
 use std::collections::{LinkedList, linked_list};
+use std::ops::Deref;
 use std::sync::Arc;
 
 /// This needs to be reworked now that we have dynamically-sized types in Rust.
 /// Until then, it's just a wrapper around LinkedList.
 ///
 /// SECURITY-NOTE(pcwalton): It is very important that `FlowRef` values not leak directly to
 /// layout. Layout code must only interact with `&Flow` or `&mut Flow` values. Otherwise, layout
 /// could stash `FlowRef` values in random places unknown to the system and thereby cause data
@@ -48,16 +49,20 @@ impl Serialize for FlowList {
         serializer.end()
     }
 }
 
 pub struct MutFlowListIterator<'a> {
     it: linked_list::IterMut<'a, FlowRef>,
 }
 
+pub struct FlowListIterator<'a> {
+    it: linked_list::Iter<'a, FlowRef>,
+}
+
 impl FlowList {
     /// Add an element last in the list
     ///
     /// O(1)
     pub fn push_back(&mut self, new_tail: FlowRef) {
         self.flows.push_back(new_tail);
     }
 
@@ -96,18 +101,20 @@ impl FlowList {
         }
     }
 
     /// Provide a forward iterator.
     ///
     /// SECURITY-NOTE(pcwalton): This does not hand out `FlowRef`s by design. Do not add a method
     /// to do so! See the comment above in `FlowList`.
     #[inline]
-    pub fn iter<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a Flow> {
-        self.flows.iter().map(|flow| &**flow)
+    pub fn iter<'a>(&'a self) -> FlowListIterator {
+        FlowListIterator {
+            it: self.flows.iter(),
+        }
     }
 
     /// Provide a forward iterator with mutable references
     ///
     /// SECURITY-NOTE(pcwalton): This does not hand out `FlowRef`s by design. Do not add a method
     /// to do so! See the comment above in `FlowList`.
     #[inline]
     pub fn iter_mut(&mut self) -> MutFlowListIterator {
@@ -145,22 +152,41 @@ impl FlowList {
     #[inline]
     pub fn split_off(&mut self, i: usize) -> Self {
         FlowList {
             flows: self.flows.split_off(i)
         }
     }
 }
 
+impl<'a> DoubleEndedIterator for FlowListIterator<'a> {
+    fn next_back(&mut self) -> Option<&'a Flow> {
+        self.it.next_back().map(Deref::deref)
+    }
+}
+
 impl<'a> DoubleEndedIterator for MutFlowListIterator<'a> {
     fn next_back(&mut self) -> Option<&'a mut Flow> {
         self.it.next_back().map(FlowRef::deref_mut)
     }
 }
 
+impl<'a> Iterator for FlowListIterator<'a> {
+    type Item = &'a Flow;
+    #[inline]
+    fn next(&mut self) -> Option<&'a Flow> {
+        self.it.next().map(Deref::deref)
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.it.size_hint()
+    }
+}
+
 impl<'a> Iterator for MutFlowListIterator<'a> {
     type Item = &'a mut Flow;
     #[inline]
     fn next(&mut self) -> Option<&'a mut Flow> {
         self.it.next().map(FlowRef::deref_mut)
     }
 
     #[inline]
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -1455,18 +1455,20 @@ impl Fragment {
     /// `white-space: pre` or `white-space: nowrap` is set.
     pub fn can_split(&self) -> bool {
         self.is_scanned_text_fragment() && self.white_space().allow_wrap()
     }
 
     /// Returns true if and only if this fragment is a generated content fragment.
     pub fn is_unscanned_generated_content(&self) -> bool {
         match self.specific {
-            SpecificFragmentInfo::GeneratedContent(box GeneratedContentInfo::Empty) => false,
-            SpecificFragmentInfo::GeneratedContent(..) => true,
+            SpecificFragmentInfo::GeneratedContent(ref content) => match **content {
+                GeneratedContentInfo::Empty => false,
+                _ => true,
+            },
             _ => false,
         }
     }
 
     /// Returns true if and only if this is a scanned text fragment.
     pub fn is_scanned_text_fragment(&self) -> bool {
         match self.specific {
             SpecificFragmentInfo::ScannedText(..) => true,
@@ -1531,51 +1533,55 @@ impl Fragment {
                 inline_size = size_constraint.clamp(inline_size);
 
                 result.union_block(&IntrinsicISizes {
                     minimum_inline_size: inline_size,
                     preferred_inline_size: inline_size,
                 });
             }
 
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: Some(ref text_fragment_info),
-                ..
-            }) |
-            SpecificFragmentInfo::ScannedText(box ref text_fragment_info) => {
-                let range = &text_fragment_info.range;
-
-                // See http://dev.w3.org/csswg/css-sizing/#max-content-inline-size.
-                // TODO: Account for soft wrap opportunities.
-                let max_line_inline_size = text_fragment_info.run
-                                                             .metrics_for_range(range)
-                                                             .advance_width;
-
-                let min_line_inline_size = if self.white_space().allow_wrap() {
-                    text_fragment_info.run.min_width_for_range(range)
-                } else {
-                    max_line_inline_size
-                };
-
-                result.union_block(&IntrinsicISizes {
-                    minimum_inline_size: min_line_inline_size,
-                    preferred_inline_size: max_line_inline_size,
-                })
+            SpecificFragmentInfo::TruncatedFragment(ref t) if t.text_info.is_some() => {
+                let text_fragment_info = t.text_info.as_ref().unwrap();
+                handle_text(text_fragment_info, self, &mut result)
+            }
+            SpecificFragmentInfo::ScannedText(ref text_fragment_info) => {
+                handle_text(text_fragment_info, self, &mut result)
             }
 
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: None,
-                ..
-            }) => return IntrinsicISizesContribution::new(),
+            SpecificFragmentInfo::TruncatedFragment(_) => {
+                return IntrinsicISizesContribution::new()
+            }
 
             SpecificFragmentInfo::UnscannedText(..) => {
                 panic!("Unscanned text fragments should have been scanned by now!")
             }
         };
 
+        fn handle_text(text_fragment_info: &ScannedTextFragmentInfo, self_: &Fragment,
+                       result: &mut IntrinsicISizesContribution) {
+            let range = &text_fragment_info.range;
+
+            // See http://dev.w3.org/csswg/css-sizing/#max-content-inline-size.
+            // TODO: Account for soft wrap opportunities.
+            let max_line_inline_size = text_fragment_info.run
+                                                         .metrics_for_range(range)
+                                                         .advance_width;
+
+            let min_line_inline_size = if self_.white_space().allow_wrap() {
+                text_fragment_info.run.min_width_for_range(range)
+            } else {
+                max_line_inline_size
+            };
+
+            result.union_block(&IntrinsicISizes {
+                minimum_inline_size: min_line_inline_size,
+                preferred_inline_size: max_line_inline_size,
+            })
+        }
+
         // Take borders and padding for parent inline fragments into account.
         let writing_mode = self.style.writing_mode;
         if let Some(ref context) = self.inline_context {
             for node in &context.nodes {
                 let mut border_width = node.style.logical_border_width();
                 let mut padding = model::padding_from_style(&*node.style, Au(0), writing_mode);
                 let mut margin = model::specified_margin_from_style(&*node.style, writing_mode);
                 if !node.flags.contains(FIRST_FRAGMENT_OF_ELEMENT) {
@@ -1600,21 +1606,21 @@ impl Fragment {
         result
     }
 
     /// Returns the narrowest inline-size that the first splittable part of this fragment could
     /// possibly be split to. (In most cases, this returns the inline-size of the first word in
     /// this fragment.)
     pub fn minimum_splittable_inline_size(&self) -> Au {
         match self.specific {
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: Some(ref text),
-                ..
-            }) |
-            SpecificFragmentInfo::ScannedText(box ref text) => {
+            SpecificFragmentInfo::TruncatedFragment(ref t) if t.text_info.is_some() => {
+                let text = t.text_info.as_ref().unwrap();
+                text.run.minimum_splittable_inline_size(&text.range)
+            }
+            SpecificFragmentInfo::ScannedText(ref text) => {
                 text.run.minimum_splittable_inline_size(&text.range)
             }
             _ => Au(0),
         }
     }
 
     /// Returns the dimensions of the content box.
     ///
@@ -1909,20 +1915,17 @@ impl Fragment {
     }
 
     /// Assigns replaced inline-size, padding, and margins for this fragment only if it is replaced
     /// content per CSS 2.1 § 10.3.2.
     pub fn assign_replaced_inline_size_if_necessary(&mut self,
                                                     container_inline_size: Au,
                                                     container_block_size: Option<Au>) {
         match self.specific {
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: None,
-                ..
-            }) |
+            SpecificFragmentInfo::TruncatedFragment(ref t) if t.text_info.is_none() => return,
             SpecificFragmentInfo::Generic |
             SpecificFragmentInfo::GeneratedContent(_) |
             SpecificFragmentInfo::Table |
             SpecificFragmentInfo::TableCell |
             SpecificFragmentInfo::TableRow |
             SpecificFragmentInfo::TableWrapper |
             SpecificFragmentInfo::Multicol |
             SpecificFragmentInfo::MulticolColumn => return,
@@ -1966,21 +1969,24 @@ impl Fragment {
                 self.border_box.size.inline =
                     max(block_flow.base.intrinsic_inline_sizes.minimum_inline_size,
                         block_flow.base.intrinsic_inline_sizes.preferred_inline_size);
                 block_flow.base.block_container_inline_size = self.border_box.size.inline;
                 block_flow.base.block_container_writing_mode = self.style.writing_mode;
             }
 
             // Text
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: Some(ref info),
-                ..
-            }) |
-            SpecificFragmentInfo::ScannedText(box ref info) => {
+            SpecificFragmentInfo::TruncatedFragment(ref t) if t.text_info.is_some() => {
+                let info = t.text_info.as_ref().unwrap();
+                // Scanned text fragments will have already had their content inline-sizes assigned
+                // by this point.
+                self.border_box.size.inline = info.content_size.inline +
+                    self.border_padding.inline_start_end();
+            }
+            SpecificFragmentInfo::ScannedText(ref info) => {
                 // Scanned text fragments will have already had their content inline-sizes assigned
                 // by this point.
                 self.border_box.size.inline = info.content_size.inline +
                     self.border_padding.inline_start_end();
             }
 
             // Replaced elements
             _ if self.is_replaced() => {
@@ -1995,20 +2001,17 @@ impl Fragment {
     }
 
     /// Assign block-size for this fragment if it is replaced content. The inline-size must have
     /// been assigned first.
     ///
     /// Ideally, this should follow CSS 2.1 § 10.6.2.
     pub fn assign_replaced_block_size_if_necessary(&mut self) {
         match self.specific {
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: None,
-                ..
-            }) |
+            SpecificFragmentInfo::TruncatedFragment(ref t) if t.text_info.is_none() => return,
             SpecificFragmentInfo::Generic |
             SpecificFragmentInfo::GeneratedContent(_) |
             SpecificFragmentInfo::Table |
             SpecificFragmentInfo::TableCell |
             SpecificFragmentInfo::TableRow |
             SpecificFragmentInfo::TableWrapper |
             SpecificFragmentInfo::Multicol |
             SpecificFragmentInfo::MulticolColumn => return,
@@ -2020,30 +2023,30 @@ impl Fragment {
             }
             SpecificFragmentInfo::Canvas(_) |
             SpecificFragmentInfo::Iframe(_) |
             SpecificFragmentInfo::Image(_) |
             SpecificFragmentInfo::InlineBlock(_) |
             SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
             SpecificFragmentInfo::InlineAbsolute(_) |
             SpecificFragmentInfo::ScannedText(_) |
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: Some(_),
-                ..
-            }) |
+            SpecificFragmentInfo::TruncatedFragment(_) |
             SpecificFragmentInfo::Svg(_) => {}
         }
 
         match self.specific {
             // Text
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: Some(ref info),
-                ..
-            }) |
-            SpecificFragmentInfo::ScannedText(box ref info) => {
+            SpecificFragmentInfo::TruncatedFragment(ref t) if t.text_info.is_some() => {
+                let info = t.text_info.as_ref().unwrap();
+                // Scanned text fragments' content block-sizes are calculated by the text run
+                // scanner during flow construction.
+                self.border_box.size.block = info.content_size.block +
+                    self.border_padding.block_start_end();
+            }
+            SpecificFragmentInfo::ScannedText(ref info) => {
                 // Scanned text fragments' content block-sizes are calculated by the text run
                 // scanner during flow construction.
                 self.border_box.size.block = info.content_size.block +
                     self.border_padding.block_start_end();
             }
 
             // Inline blocks
             SpecificFragmentInfo::InlineBlock(ref mut info) => {
@@ -2110,59 +2113,61 @@ impl Fragment {
             SpecificFragmentInfo::Generic | SpecificFragmentInfo::GeneratedContent(_) => {
                 let ascent = self.border_box.size.block + self.margin.block_end;
                 InlineMetrics {
                     space_above_baseline: ascent + self.margin.block_start,
                     space_below_baseline: Au(0),
                     ascent: ascent,
                 }
             }
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: Some(ref info),
-                ..
-            }) |
-            SpecificFragmentInfo::ScannedText(box ref info) => {
-                // Fragments with no glyphs don't contribute any inline metrics.
-                // TODO: Filter out these fragments during flow construction?
-                if info.insertion_point.is_none() && info.content_size.inline == Au(0) {
-                    return InlineMetrics::new(Au(0), Au(0), Au(0));
-                }
-                // See CSS 2.1 § 10.8.1.
-                let font_metrics = with_thread_local_font_context(layout_context, |font_context| {
-                    text::font_metrics_for_style(font_context, self.style.clone_font())
-                });
-                let line_height = text::line_height_from_style(&*self.style, &font_metrics);
-                InlineMetrics::from_font_metrics(&info.run.font_metrics, line_height)
+            SpecificFragmentInfo::TruncatedFragment(ref t) if t.text_info.is_some() => {
+                let info = t.text_info.as_ref().unwrap();
+                inline_metrics_of_text(info, self, layout_context)
+            }
+            SpecificFragmentInfo::ScannedText(ref info) => {
+                inline_metrics_of_text(info, self, layout_context)
             }
             SpecificFragmentInfo::InlineBlock(ref info) => {
                 inline_metrics_of_block(&info.flow_ref, &*self.style)
             }
             SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => {
                 inline_metrics_of_block(&info.flow_ref, &*self.style)
             }
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: None,
-                ..
-            }) |
+            SpecificFragmentInfo::TruncatedFragment(..) |
             SpecificFragmentInfo::InlineAbsolute(_) => {
                 InlineMetrics::new(Au(0), Au(0), Au(0))
             }
             SpecificFragmentInfo::Table |
             SpecificFragmentInfo::TableCell |
             SpecificFragmentInfo::TableColumn(_) |
             SpecificFragmentInfo::TableRow |
             SpecificFragmentInfo::TableWrapper |
             SpecificFragmentInfo::Multicol |
             SpecificFragmentInfo::MulticolColumn |
             SpecificFragmentInfo::UnscannedText(_) => {
                 unreachable!("Shouldn't see fragments of this type here!")
             }
         };
         return inline_metrics;
 
+        fn inline_metrics_of_text(info: &ScannedTextFragmentInfo, self_: &Fragment,
+                                  layout_context: &LayoutContext) -> InlineMetrics {
+            // Fragments with no glyphs don't contribute any inline metrics.
+            // TODO: Filter out these fragments during flow construction?
+            if info.insertion_point.is_none() && info.content_size.inline == Au(0) {
+                return InlineMetrics::new(Au(0), Au(0), Au(0));
+            }
+            // See CSS 2.1 § 10.8.1.
+            let font_metrics = with_thread_local_font_context(layout_context, |font_context| {
+                text::font_metrics_for_style(font_context, self_.style.clone_font())
+            });
+            let line_height = text::line_height_from_style(&*self_.style, &font_metrics);
+            InlineMetrics::from_font_metrics(&info.run.font_metrics, line_height)
+        }
+
         fn inline_metrics_of_block(flow: &FlowRef, style: &ComputedValues) -> InlineMetrics {
             // CSS 2.1 § 10.8: "The height of each inline-level box in the line box is calculated.
             // For replaced elements, inline-block elements, and inline-table elements, this is the
             // height of their margin box."
             //
             // CSS 2.1 § 10.8.1: "The baseline of an 'inline-block' is the baseline of its last
             // line box in the normal flow, unless it has either no in-flow line boxes or if its
             // 'overflow' property has a computed value other than 'visible', in which case the
@@ -2607,54 +2612,39 @@ impl Fragment {
 
         // FIXME(pcwalton): Sometimes excessively fancy glyphs can make us draw outside our border
         // box too.
         overflow
     }
 
     pub fn requires_line_break_afterward_if_wrapping_on_newlines(&self) -> bool {
         match self.specific {
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: Some(ref scanned_text),
-                ..
-            }) |
-            SpecificFragmentInfo::ScannedText(box ref scanned_text) => {
-                scanned_text.requires_line_break_afterward_if_wrapping_on_newlines()
+            SpecificFragmentInfo::TruncatedFragment(ref t) if t.text_info.is_some() => {
+                let text = t.text_info.as_ref().unwrap();
+                text.requires_line_break_afterward_if_wrapping_on_newlines()
+            }
+            SpecificFragmentInfo::ScannedText(ref text) => {
+                text.requires_line_break_afterward_if_wrapping_on_newlines()
             }
             _ => false,
         }
     }
 
     pub fn strip_leading_whitespace_if_necessary(&mut self) -> WhitespaceStrippingResult {
         if self.white_space().preserve_spaces() {
             return WhitespaceStrippingResult::RetainFragment
         }
 
-        match self.specific {
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: Some(ref mut scanned_text_fragment_info),
-                ..
-            }) |
-            SpecificFragmentInfo::ScannedText(box ref mut scanned_text_fragment_info) => {
-                let leading_whitespace_byte_count = scanned_text_fragment_info.text()
-                    .find(|c| !char_is_whitespace(c))
-                    .unwrap_or(scanned_text_fragment_info.text().len());
-
-                let whitespace_len = ByteIndex(leading_whitespace_byte_count as isize);
-                let whitespace_range = Range::new(scanned_text_fragment_info.range.begin(),
-                                                  whitespace_len);
-                let text_bounds =
-                    scanned_text_fragment_info.run.metrics_for_range(&whitespace_range).bounding_box;
-                self.border_box.size.inline = self.border_box.size.inline - text_bounds.size.width;
-                scanned_text_fragment_info.content_size.inline =
-                    scanned_text_fragment_info.content_size.inline - text_bounds.size.width;
-
-                scanned_text_fragment_info.range.adjust_by(whitespace_len, -whitespace_len);
-
-                WhitespaceStrippingResult::RetainFragment
+        return match self.specific {
+            SpecificFragmentInfo::TruncatedFragment(ref mut t) if t.text_info.is_some() => {
+                let scanned_text_fragment_info = t.text_info.as_mut().unwrap();
+                scanned_text(scanned_text_fragment_info, &mut self.border_box)
+            }
+            SpecificFragmentInfo::ScannedText(ref mut scanned_text_fragment_info) => {
+                scanned_text(scanned_text_fragment_info, &mut self.border_box)
             }
             SpecificFragmentInfo::UnscannedText(ref mut unscanned_text_fragment_info) => {
                 let mut new_text_string = String::new();
                 let mut modified = false;
                 for (i, character) in unscanned_text_fragment_info.text.char_indices() {
                     if gfx::text::util::is_bidi_control(character) {
                         new_text_string.push(character);
                         continue
@@ -2672,51 +2662,53 @@ impl Fragment {
                 if modified {
                     unscanned_text_fragment_info.text = new_text_string.into_boxed_str();
                 }
 
                 WhitespaceStrippingResult::from_unscanned_text_fragment_info(
                     &unscanned_text_fragment_info)
             }
             _ => WhitespaceStrippingResult::RetainFragment,
+        };
+
+        fn scanned_text(scanned_text_fragment_info: &mut ScannedTextFragmentInfo,
+                        border_box: &mut LogicalRect<Au>)
+                        -> WhitespaceStrippingResult {
+            let leading_whitespace_byte_count = scanned_text_fragment_info.text()
+                .find(|c| !char_is_whitespace(c))
+                .unwrap_or(scanned_text_fragment_info.text().len());
+
+            let whitespace_len = ByteIndex(leading_whitespace_byte_count as isize);
+            let whitespace_range = Range::new(scanned_text_fragment_info.range.begin(),
+                                              whitespace_len);
+            let text_bounds =
+                scanned_text_fragment_info.run.metrics_for_range(&whitespace_range).bounding_box;
+            border_box.size.inline = border_box.size.inline - text_bounds.size.width;
+            scanned_text_fragment_info.content_size.inline =
+                scanned_text_fragment_info.content_size.inline - text_bounds.size.width;
+
+            scanned_text_fragment_info.range.adjust_by(whitespace_len, -whitespace_len);
+
+            WhitespaceStrippingResult::RetainFragment
         }
     }
 
     /// Returns true if the entire fragment was stripped.
     pub fn strip_trailing_whitespace_if_necessary(&mut self) -> WhitespaceStrippingResult {
         if self.white_space().preserve_spaces() {
             return WhitespaceStrippingResult::RetainFragment
         }
 
-        match self.specific {
-            SpecificFragmentInfo::TruncatedFragment(box TruncatedFragmentInfo {
-                text_info: Some(ref mut scanned_text_fragment_info),
-                ..
-            }) |
-            SpecificFragmentInfo::ScannedText(box ref mut scanned_text_fragment_info) => {
-                let mut trailing_whitespace_start_byte = 0;
-                for (i, c) in scanned_text_fragment_info.text().char_indices().rev() {
-                    if !char_is_whitespace(c) {
-                        trailing_whitespace_start_byte = i + c.len_utf8();
-                        break;
-                    }
-                }
-                let whitespace_start = ByteIndex(trailing_whitespace_start_byte as isize);
-                let whitespace_len = scanned_text_fragment_info.range.length() - whitespace_start;
-                let mut whitespace_range = Range::new(whitespace_start, whitespace_len);
-                whitespace_range.shift_by(scanned_text_fragment_info.range.begin());
-
-                let text_bounds = scanned_text_fragment_info.run
-                                                        .metrics_for_range(&whitespace_range)
-                                                        .bounding_box;
-                self.border_box.size.inline -= text_bounds.size.width;
-                scanned_text_fragment_info.content_size.inline -= text_bounds.size.width;
-
-                scanned_text_fragment_info.range.extend_by(-whitespace_len);
-                WhitespaceStrippingResult::RetainFragment
+        return match self.specific {
+            SpecificFragmentInfo::TruncatedFragment(ref mut t) if t.text_info.is_some() => {
+                let scanned_text_fragment_info = t.text_info.as_mut().unwrap();
+                scanned_text(scanned_text_fragment_info, &mut self.border_box)
+            }
+            SpecificFragmentInfo::ScannedText(ref mut scanned_text_fragment_info) => {
+                scanned_text(scanned_text_fragment_info, &mut self.border_box)
             }
             SpecificFragmentInfo::UnscannedText(ref mut unscanned_text_fragment_info) => {
                 let mut trailing_bidi_control_characters_to_retain = Vec::new();
                 let (mut modified, mut last_character_index) = (true, 0);
                 for (i, character) in unscanned_text_fragment_info.text.char_indices().rev() {
                     if gfx::text::util::is_bidi_control(character) {
                         trailing_bidi_control_characters_to_retain.push(character);
                         continue
@@ -2736,16 +2728,41 @@ impl Fragment {
                     }
                     unscanned_text_fragment_info.text = text.into_boxed_str();
                 }
 
                 WhitespaceStrippingResult::from_unscanned_text_fragment_info(
                     &unscanned_text_fragment_info)
             }
             _ => WhitespaceStrippingResult::RetainFragment,
+        };
+
+        fn scanned_text(scanned_text_fragment_info: &mut ScannedTextFragmentInfo,
+                        border_box: &mut LogicalRect<Au>)
+                        -> WhitespaceStrippingResult {
+                let mut trailing_whitespace_start_byte = 0;
+                for (i, c) in scanned_text_fragment_info.text().char_indices().rev() {
+                    if !char_is_whitespace(c) {
+                        trailing_whitespace_start_byte = i + c.len_utf8();
+                        break;
+                    }
+                }
+                let whitespace_start = ByteIndex(trailing_whitespace_start_byte as isize);
+                let whitespace_len = scanned_text_fragment_info.range.length() - whitespace_start;
+                let mut whitespace_range = Range::new(whitespace_start, whitespace_len);
+                whitespace_range.shift_by(scanned_text_fragment_info.range.begin());
+
+                let text_bounds = scanned_text_fragment_info.run
+                                                        .metrics_for_range(&whitespace_range)
+                                                        .bounding_box;
+                border_box.size.inline -= text_bounds.size.width;
+                scanned_text_fragment_info.content_size.inline -= text_bounds.size.width;
+
+                scanned_text_fragment_info.range.extend_by(-whitespace_len);
+                WhitespaceStrippingResult::RetainFragment
         }
     }
 
     pub fn inline_styles(&self) -> InlineStyleIterator {
         InlineStyleIterator::new(self)
     }
 
     /// Returns the inline-size of this fragment's margin box.
--- a/servo/components/layout/lib.rs
+++ b/servo/components/layout/lib.rs
@@ -1,17 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #![deny(unsafe_code)]
-#![feature(box_patterns)]
-#![feature(conservative_impl_trait)]
-#![feature(nonzero)]
-#![feature(raw)]
 
 extern crate app_units;
 extern crate atomic_refcell;
 #[macro_use]
 extern crate bitflags;
 extern crate canvas_traits;
 extern crate euclid;
 extern crate fnv;
@@ -89,8 +85,17 @@ pub mod wrapper;
 // For unit tests:
 pub use fragment::Fragment;
 pub use fragment::SpecificFragmentInfo;
 pub use self::data::LayoutData;
 
 // We can't use servo_arc for everything in layout, because the Flow stuff uses
 // weak references.
 use servo_arc::Arc as ServoArc;
+
+/// Stable copy of std::raw::TraitObject
+/// test/unit/layout/lib.rs asserts that the memory layout matches.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct TraitObject {
+    pub data: *mut (),
+    pub vtable: *mut (),
+}
--- a/servo/components/layout_thread/Cargo.toml
+++ b/servo/components/layout_thread/Cargo.toml
@@ -4,16 +4,19 @@ version = "0.0.1"
 authors = ["The Servo Project Developers"]
 license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "layout_thread"
 path = "lib.rs"
 
+[features]
+unstable = ["parking_lot/nightly", "nonzero/unstable"]
+
 [dependencies]
 app_units = "0.5"
 atomic_refcell = "0.1"
 euclid = "0.15"
 fnv = "1.0"
 gfx = {path = "../gfx"}
 gfx_traits = {path = "../gfx_traits"}
 heapsize = "0.4"
@@ -21,17 +24,18 @@ html5ever = "0.20.0"
 ipc-channel = "0.8"
 layout = {path = "../layout"}
 layout_traits = {path = "../layout_traits"}
 lazy_static = "0.2"
 log = "0.3.5"
 metrics = {path = "../metrics"}
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
-parking_lot = {version = "0.4", features = ["nightly"]}
+nonzero = {path = "../nonzero"}
+parking_lot = "0.4"
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
 rayon = "0.8"
 script = {path = "../script"}
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = { path = "../selectors" }
 serde_json = "1.0"
--- a/servo/components/layout_thread/dom_wrapper.rs
+++ b/servo/components/layout_thread/dom_wrapper.rs
@@ -26,22 +26,22 @@
 //!   o Instead of `get_attr()`, use `.get_attr_val_for_layout()`.
 //!
 //!   o Instead of `html_element_in_html_document()`, use
 //!     `html_element_in_html_document_for_layout()`.
 
 #![allow(unsafe_code)]
 
 use atomic_refcell::{AtomicRef, AtomicRefMut, AtomicRefCell};
-use core::nonzero::NonZero;
 use gfx_traits::ByteIndex;
 use html5ever::{LocalName, Namespace};
 use layout::data::StyleAndLayoutData;
 use layout::wrapper::GetRawData;
 use msg::constellation_msg::{BrowsingContextId, PipelineId};
+use nonzero::NonZeroUsize;
 use range::Range;
 use script::layout_exports::{CAN_BE_FRAGMENTED, HAS_DIRTY_DESCENDANTS, IS_IN_DOC};
 use script::layout_exports::{CharacterDataTypeId, ElementTypeId, HTMLElementTypeId, NodeTypeId};
 use script::layout_exports::{Document, Element, Node, Text};
 use script::layout_exports::{HANDLED_SNAPSHOT, HAS_SNAPSHOT};
 use script::layout_exports::{LayoutCharacterDataHelpers, LayoutDocumentHelpers};
 use script::layout_exports::{LayoutElementHelpers, LayoutNodeHelpers, RawLayoutElementHelpers};
 use script::layout_exports::LayoutDom;
@@ -74,17 +74,17 @@ use style::element_state::*;
 use style::font_metrics::ServoMetricsProvider;
 use style::properties::{ComputedValues, PropertyDeclarationBlock};
 use style::selector_parser::{AttrValue as SelectorAttrValue, NonTSPseudoClass, PseudoClassStringArg};
 use style::selector_parser::{PseudoElement, SelectorImpl, extended_filtering};
 use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
 use style::str::is_whitespace;
 
 pub unsafe fn drop_style_and_layout_data(data: OpaqueStyleAndLayoutData) {
-    let ptr: *mut StyleData = data.ptr.get();
+    let ptr = data.ptr.get() as *mut StyleData;
     let non_opaque: *mut StyleAndLayoutData = ptr as *mut _;
     let _ = Box::from_raw(non_opaque);
 }
 
 #[derive(Clone, Copy)]
 pub struct ServoLayoutNode<'a> {
     /// The wrapped node.
     node: LayoutDom<Node>,
@@ -230,17 +230,18 @@ impl<'ln> LayoutNode for ServoLayoutNode
         self.script_type_id().into()
     }
 
     unsafe fn initialize_data(&self) {
         if self.get_raw_data().is_none() {
             let ptr: *mut StyleAndLayoutData =
                 Box::into_raw(Box::new(StyleAndLayoutData::new()));
             let opaque = OpaqueStyleAndLayoutData {
-                ptr: NonZero::new_unchecked(ptr as *mut StyleData),
+                ptr: NonZeroUsize::new_unchecked(ptr as usize),
+                phantom: PhantomData,
             };
             self.init_style_and_layout_data(opaque);
         };
     }
 
     unsafe fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) {
         self.get_jsmanaged().init_style_and_layout_data(data);
     }
@@ -466,17 +467,17 @@ impl<'le> TElement for ServoLayoutElemen
     unsafe fn ensure_data(&self) -> AtomicRefMut<ElementData> {
         self.as_node().initialize_data();
         self.mutate_data().unwrap()
     }
 
     fn get_data(&self) -> Option<&AtomicRefCell<ElementData>> {
         unsafe {
             self.get_style_and_layout_data().map(|d| {
-                &(*d.ptr.get()).element_data
+                &(*(d.ptr.get() as *mut StyleData)).element_data
             })
         }
     }
 
     fn skip_root_and_item_based_display_fixup(&self) -> bool {
         false
     }
 
@@ -578,17 +579,17 @@ impl<'le> ServoLayoutElement<'le> {
     fn get_attr(&self, namespace: &Namespace, name: &LocalName) -> Option<&str> {
         unsafe {
             (*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
         }
     }
 
     fn get_style_data(&self) -> Option<&StyleData> {
         unsafe {
-            self.get_style_and_layout_data().map(|d| &*d.ptr.get())
+            self.get_style_and_layout_data().map(|d| &*(d.ptr.get() as *mut StyleData))
         }
     }
 
     pub unsafe fn unset_snapshot_flags(&self) {
         self.as_node().node.set_flag(HAS_SNAPSHOT | HANDLED_SNAPSHOT, false);
     }
 
     pub unsafe fn set_has_snapshot(&self) {
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -1,21 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! The layout thread. Performs layout on the DOM, builds display lists and sends them to be
 //! painted.
 
 #![feature(mpsc_select)]
-#![feature(nonzero)]
 
 extern crate app_units;
 extern crate atomic_refcell;
-extern crate core;
 extern crate euclid;
 extern crate fnv;
 extern crate gfx;
 extern crate gfx_traits;
 extern crate heapsize;
 #[macro_use]
 extern crate html5ever;
 extern crate ipc_channel;
@@ -24,16 +22,17 @@ extern crate layout;
 extern crate layout_traits;
 #[macro_use]
 extern crate lazy_static;
 #[macro_use]
 extern crate log;
 extern crate metrics;
 extern crate msg;
 extern crate net_traits;
+extern crate nonzero;
 extern crate parking_lot;
 #[macro_use]
 extern crate profile_traits;
 extern crate range;
 extern crate rayon;
 extern crate script;
 extern crate script_layout_interface;
 extern crate script_traits;
--- a/servo/components/msg/Cargo.toml
+++ b/servo/components/msg/Cargo.toml
@@ -4,14 +4,18 @@ version = "0.0.1"
 authors = ["The Servo Project Developers"]
 license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "msg"
 path = "lib.rs"
 
+[features]
+unstable = ["nonzero/unstable"]
+
 [dependencies]
 bitflags = "0.7"
 heapsize = "0.4"
 heapsize_derive = "0.1"
-serde = { version = "1.0.14", features = [ "unstable" ] }
+nonzero = {path = "../nonzero"}
+serde = "1.0.14"
 webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/msg/constellation_msg.rs
+++ b/servo/components/msg/constellation_msg.rs
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! The high-level interface from script to constellation. Using this abstract interface helps
 //! reduce coupling between these two components.
 
-use core::nonzero::NonZero;
+use nonzero::NonZeroU32;
 use std::cell::Cell;
 use std::fmt;
 use webrender_api;
 
 #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
 pub enum KeyState {
     Pressed,
     Released,
@@ -190,19 +190,19 @@ impl PipelineNamespace {
             assert!(tls.get().is_none());
             tls.set(Some(PipelineNamespace {
                 id: namespace_id,
                 index: 0,
             }));
         });
     }
 
-    fn next_index(&mut self) -> NonZero<u32> {
+    fn next_index(&mut self) -> NonZeroU32 {
         self.index += 1;
-        NonZero::new(self.index).expect("pipeline id index wrapped!")
+        NonZeroU32::new(self.index).expect("pipeline id index wrapped!")
     }
 
     fn next_pipeline_id(&mut self) -> PipelineId {
         PipelineId {
             namespace_id: self.id,
             index: PipelineIndex(self.next_index()),
         }
     }
@@ -216,17 +216,17 @@ impl PipelineNamespace {
 }
 
 thread_local!(pub static PIPELINE_NAMESPACE: Cell<Option<PipelineNamespace>> = Cell::new(None));
 
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, HeapSizeOf, Ord, PartialEq, PartialOrd, Serialize)]
 pub struct PipelineNamespaceId(pub u32);
 
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
-pub struct PipelineIndex(pub NonZero<u32>);
+pub struct PipelineIndex(pub NonZeroU32);
 known_heap_size!(0, PipelineIndex);
 
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, HeapSizeOf, Ord, PartialEq, PartialOrd, Serialize)]
 pub struct PipelineId {
     pub namespace_id: PipelineNamespaceId,
     pub index: PipelineIndex
 }
 
@@ -259,17 +259,17 @@ impl fmt::Display for PipelineId {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let PipelineNamespaceId(namespace_id) = self.namespace_id;
         let PipelineIndex(index) = self.index;
         write!(fmt, "({},{})", namespace_id, index.get())
     }
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
-pub struct BrowsingContextIndex(pub NonZero<u32>);
+pub struct BrowsingContextIndex(pub NonZeroU32);
 known_heap_size!(0, BrowsingContextIndex);
 
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, HeapSizeOf, Ord, PartialEq, PartialOrd, Serialize)]
 pub struct BrowsingContextId {
     pub namespace_id: PipelineNamespaceId,
     pub index: BrowsingContextIndex,
 }
 
@@ -334,21 +334,25 @@ impl PartialEq<BrowsingContextId> for To
     fn eq(&self, rhs: &BrowsingContextId) -> bool {
         self.0.eq(rhs)
     }
 }
 
 // We provide ids just for unit testing.
 pub const TEST_NAMESPACE: PipelineNamespaceId = PipelineNamespaceId(1234);
 #[allow(unsafe_code)]
-pub const TEST_PIPELINE_INDEX: PipelineIndex = unsafe { PipelineIndex(NonZero::new_unchecked(5678)) };
+#[cfg(feature = "unstable")]
+pub const TEST_PIPELINE_INDEX: PipelineIndex = unsafe { PipelineIndex(NonZeroU32::new_unchecked(5678)) };
+#[cfg(feature = "unstable")]
 pub const TEST_PIPELINE_ID: PipelineId = PipelineId { namespace_id: TEST_NAMESPACE, index: TEST_PIPELINE_INDEX };
 #[allow(unsafe_code)]
+#[cfg(feature = "unstable")]
 pub const TEST_BROWSING_CONTEXT_INDEX: BrowsingContextIndex =
-    unsafe { BrowsingContextIndex(NonZero::new_unchecked(8765)) };
+    unsafe { BrowsingContextIndex(NonZeroU32::new_unchecked(8765)) };
+#[cfg(feature = "unstable")]
 pub const TEST_BROWSING_CONTEXT_ID: BrowsingContextId =
     BrowsingContextId { namespace_id: TEST_NAMESPACE, index: TEST_BROWSING_CONTEXT_INDEX };
 
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, HeapSizeOf, PartialEq, Serialize)]
 pub enum FrameType {
     IFrame,
     MozBrowserIFrame,
 }
--- a/servo/components/msg/lib.rs
+++ b/servo/components/msg/lib.rs
@@ -1,18 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#![feature(const_fn)]
-#![feature(const_nonzero_new)]
-#![feature(nonzero)]
 #![deny(unsafe_code)]
 
 #[macro_use]
 extern crate bitflags;
-extern crate core;
 #[macro_use] extern crate heapsize;
 #[macro_use] extern crate heapsize_derive;
+extern crate nonzero;
 #[macro_use] extern crate serde;
 extern crate webrender_api;
 
 pub mod constellation_msg;
new file mode 100644
--- /dev/null
+++ b/servo/components/nonzero/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "nonzero"
+version = "0.0.1"
+authors = ["The Servo Project Developers"]
+license = "MPL-2.0"
+publish = false
+
+[lib]
+path = "lib.rs"
+
+[features]
+unstable = ["serde/unstable"]
+
+[dependencies]
+serde = "1.0.14"
new file mode 100644
--- /dev/null
+++ b/servo/components/nonzero/lib.rs
@@ -0,0 +1,121 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//! `NonZero*` types that are either `core::nonzero::NonZero<_>`
+//! or some stable types with an equivalent API (but no memory layout optimization).
+
+#![cfg_attr(feature = "unstable", feature(nonzero))]
+#![cfg_attr(feature = "unstable", feature(const_fn))]
+#![cfg_attr(feature = "unstable", feature(const_nonzero_new))]
+
+#[macro_use]
+extern crate serde;
+
+pub use imp::*;
+
+#[cfg(feature = "unstable")]
+mod imp {
+    extern crate core;
+    use self::core::nonzero::NonZero;
+
+    #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
+    pub struct NonZeroU32(NonZero<u32>);
+
+    #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
+    pub struct NonZeroUsize(NonZero<usize>);
+
+    impl NonZeroU32 {
+        #[inline] pub const unsafe fn new_unchecked(x: u32) -> Self { NonZeroU32(NonZero::new_unchecked(x)) }
+        #[inline] pub fn new(x: u32) -> Option<Self> { NonZero::new(x).map(NonZeroU32) }
+        #[inline] pub fn get(self) -> u32 { self.0.get() }
+    }
+
+    impl NonZeroUsize {
+        #[inline] pub const unsafe fn new_unchecked(x: usize) -> Self { NonZeroUsize(NonZero::new_unchecked(x)) }
+        #[inline] pub fn new(x: usize) -> Option<Self> { NonZero::new(x).map(NonZeroUsize) }
+        #[inline] pub fn get(self) -> usize { self.0.get() }
+    }
+}
+
+#[cfg(not(feature = "unstable"))]
+mod imp {
+    use std::cmp;
+    use std::hash;
+
+    #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
+    pub struct NonZeroU32(u32);
+
+    impl NonZeroU32 {
+        #[inline]
+        pub fn new(x: u32) -> Option<Self> {
+            if x != 0 {
+                Some(NonZeroU32(x))
+            } else {
+                None
+            }
+        }
+
+        #[inline]
+        pub unsafe fn new_unchecked(x: u32) -> Self {
+            NonZeroU32(x)
+        }
+
+        #[inline]
+        pub fn get(self) -> u32 {
+            self.0
+        }
+    }
+
+    #[derive(Clone, Copy, Debug, Eq)]
+    pub struct NonZeroUsize(&'static ());
+
+    impl NonZeroUsize {
+        #[inline]
+        pub fn new(x: usize) -> Option<Self> {
+            if x != 0 {
+                Some(unsafe { Self::new_unchecked(x) })
+            } else {
+                None
+            }
+        }
+
+        #[inline]
+        pub unsafe fn new_unchecked(x: usize) -> Self {
+            NonZeroUsize(&*(x as *const ()))
+        }
+
+        #[inline]
+        pub fn get(self) -> usize {
+            self.0 as *const () as usize
+        }
+    }
+
+    impl PartialEq for NonZeroUsize {
+        #[inline]
+        fn eq(&self, other: &Self) -> bool {
+            self.get() == other.get()
+        }
+    }
+
+    impl PartialOrd for NonZeroUsize {
+        #[inline]
+        fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+            self.get().partial_cmp(&other.get())
+        }
+    }
+
+    impl Ord for NonZeroUsize {
+        #[inline]
+        fn cmp(&self, other: &Self) -> cmp::Ordering {
+            self.get().cmp(&other.get())
+        }
+    }
+
+    impl hash::Hash for NonZeroUsize {
+        #[inline]
+        fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
+            self.get().hash(hasher)
+        }
+    }
+}
--- a/servo/components/profile/Cargo.toml
+++ b/servo/components/profile/Cargo.toml
@@ -4,16 +4,19 @@ version = "0.0.1"
 authors = ["The Servo Project Developers"]
 license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "profile"
 path = "lib.rs"
 
+[features]
+unstable = []
+
 [dependencies]
 profile_traits = {path = "../profile_traits"}
 influent = "0.4"
 ipc-channel = "0.8"
 heartbeats-simple = "0.4"
 log = "0.3.5"
 serde = "1.0"
 serde_json = "1.0"
--- a/servo/components/profile/lib.rs
+++ b/servo/components/profile/lib.rs
@@ -1,22 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#![cfg_attr(not(target_os = "windows"), feature(alloc_jemalloc))]
+#![cfg_attr(all(feature = "unstable", not(target_os = "windows")), feature(alloc_jemalloc))]
 
 #![deny(unsafe_code)]
 
 #[allow(unused_extern_crates)]
-#[cfg(not(target_os = "windows"))]
+#[cfg(all(feature = "unstable", not(target_os = "windows")))]
 extern crate alloc_jemalloc;
 extern crate heartbeats_simple;
 extern crate influent;
 extern crate ipc_channel;
+#[allow(unused_extern_crates)]
 #[cfg(not(target_os = "windows"))]
 extern crate libc;
 #[macro_use]
 extern crate log;
 #[macro_use]
 extern crate profile_traits;
 #[cfg(target_os = "linux")]
 extern crate regex;
--- a/servo/components/profile/mem.rs
+++ b/servo/components/profile/mem.rs
@@ -348,24 +348,26 @@ impl ReportsForest {
             }
         }
     }
 }
 
 //---------------------------------------------------------------------------
 
 mod system_reporter {
-    #[cfg(not(target_os = "windows"))]
-    use libc::{c_char, c_int, c_void, size_t};
+    #[cfg(all(feature = "unstable", not(target_os = "windows")))]
+    use libc::{c_char, c_void, size_t};
+    #[cfg(target_os = "linux")]
+    use libc::c_int;
     use profile_traits::mem::{Report, ReportKind, ReporterRequest};
-    #[cfg(not(target_os = "windows"))]
+    #[cfg(all(feature = "unstable", not(target_os = "windows")))]
     use std::ffi::CString;
-    #[cfg(not(target_os = "windows"))]
+    #[cfg(all(feature = "unstable", not(target_os = "windows")))]
     use std::mem::size_of;
-    #[cfg(not(target_os = "windows"))]
+    #[cfg(all(feature = "unstable", not(target_os = "windows")))]
     use std::ptr::null_mut;
     use super::{JEMALLOC_HEAP_ALLOCATED_STR, SYSTEM_HEAP_ALLOCATED_STR};
     #[cfg(target_os = "macos")]
     use task_info::task_basic_info::{virtual_size, resident_size};
 
     /// Collects global measurements from the OS and heap allocators.
     pub fn collect_reports(request: ReporterRequest) {
         let mut reports = vec![];
@@ -452,24 +454,24 @@ mod system_reporter {
         }
     }
 
     #[cfg(not(target_os = "linux"))]
     fn system_heap_allocated() -> Option<usize> {
         None
     }
 
-    #[cfg(not(target_os = "windows"))]
+    #[cfg(all(feature = "unstable", not(target_os = "windows")))]
     extern {
         #[cfg_attr(any(target_os = "macos", target_os = "android"), link_name = "je_mallctl")]
         fn mallctl(name: *const c_char, oldp: *mut c_void, oldlenp: *mut size_t,
-                   newp: *mut c_void, newlen: size_t) -> c_int;
+                   newp: *mut c_void, newlen: size_t) -> ::libc::c_int;
     }
 
-    #[cfg(not(target_os = "windows"))]
+    #[cfg(all(feature = "unstable", not(target_os = "windows")))]
     fn jemalloc_stat(value_name: &str) -> Option<usize> {
         // Before we request the measurement of interest, we first send an "epoch"
         // request. Without that jemalloc gives cached statistics(!) which can be
         // highly inaccurate.
         let epoch_name = "epoch";
         let epoch_c_name = CString::new(epoch_name).unwrap();
         let mut epoch: u64 = 0;
         let epoch_ptr = &mut epoch as *mut _ as *mut c_void;
@@ -495,17 +497,17 @@ mod system_reporter {
         };
         if rv != 0 {
             return None;
         }
 
         Some(value as usize)
     }
 
-    #[cfg(target_os = "windows")]
+    #[cfg(any(target_os = "windows", not(feature = "unstable")))]
     fn jemalloc_stat(_value_name: &str) -> Option<usize> {
         None
     }
 
     #[cfg(target_os = "linux")]
     fn page_size() -> usize {
         unsafe {
             ::libc::sysconf(::libc::_SC_PAGESIZE) as usize
--- a/servo/components/remutex/Cargo.toml
+++ b/servo/components/remutex/Cargo.toml
@@ -7,8 +7,9 @@ publish = false
 
 [lib]
 name = "servo_remutex"
 path = "lib.rs"
 
 [dependencies]
 lazy_static = "0.2"
 log = "0.3.5"
+nonzero = {path = "../nonzero"}
--- a/servo/components/remutex/lib.rs
+++ b/servo/components/remutex/lib.rs
@@ -5,42 +5,40 @@
 //! An implementation of re-entrant mutexes.
 //!
 //! Re-entrant mutexes are like mutexes, but where it is expected
 //! that a single thread may own a lock more than once.
 
 //! It provides the same interface as https://github.com/rust-lang/rust/blob/master/src/libstd/sys/common/remutex.rs
 //! so if those types are ever exported, we should be able to replace this implemtation.
 
-#![feature(nonzero)]
-
-extern crate core;
+extern crate nonzero;
 #[macro_use] extern crate lazy_static;
 #[macro_use] extern crate log;
 
-use core::nonzero::NonZero;
+use nonzero::NonZeroUsize;
 use std::cell::{Cell, UnsafeCell};
 use std::ops::Deref;
 use std::sync::{LockResult, Mutex, MutexGuard, PoisonError, TryLockError, TryLockResult};
 use std::sync::atomic::{AtomicUsize, Ordering};
 
 /// A type for thread ids.
 
 // TODO: can we use the thread-id crate for this?
 
 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
-pub struct ThreadId(NonZero<usize>);
+pub struct ThreadId(NonZeroUsize);
 
 lazy_static!{ static ref THREAD_COUNT: AtomicUsize = AtomicUsize::new(1); }
 
 impl ThreadId {
     #[allow(unsafe_code)]
     fn new() -> ThreadId {
         let number = THREAD_COUNT.fetch_add(1, Ordering::SeqCst);
-        ThreadId(NonZero::new(number).unwrap())
+        ThreadId(NonZeroUsize::new(number).unwrap())
     }
     pub fn current() -> ThreadId {
         THREAD_ID.with(|tls| tls.clone())
     }
 }
 
 thread_local!{ static THREAD_ID: ThreadId = ThreadId::new() }
 
@@ -54,23 +52,23 @@ impl AtomicOptThreadId {
     }
     pub fn store(&self, value: Option<ThreadId>, ordering: Ordering) {
         let number = value.map(|id| id.0.get()).unwrap_or(0);
         self.0.store(number, ordering);
     }
     #[allow(unsafe_code)]
     pub fn load(&self, ordering: Ordering) -> Option<ThreadId> {
         let number = self.0.load(ordering);
-        NonZero::new(number).map(ThreadId)
+        NonZeroUsize::new(number).map(ThreadId)
     }
     #[allow(unsafe_code)]
     pub fn swap(&self, value: Option<ThreadId>, ordering: Ordering) -> Option<ThreadId> {
         let number = value.map(|id| id.0.get()).unwrap_or(0);
         let number = self.0.swap(number, ordering);
-        NonZero::new(number).map(ThreadId)
+        NonZeroUsize::new(number).map(ThreadId)
     }
 }
 
 /// A type for hand-over-hand mutexes.
 ///
 /// These support `lock` and `unlock` functions. `lock` blocks waiting to become the
 /// mutex owner. `unlock` can only be called by the lock owner, and panics otherwise.
 /// They have the same happens-before and poisoning semantics as `Mutex`.
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -102,16 +102,17 @@ use std::default::Default;
 use std::fmt;
 use std::mem;
 use std::rc::Rc;
 use std::str::FromStr;
 use style::CaseSensitivityExt;
 use style::applicable_declarations::ApplicableDeclarationBlock;
 use style::attr::{AttrValue, LengthOrPercentageOrAuto};
 use style::context::QuirksMode;
+use style::dom_apis;
 use style::element_state::*;
 use style::invalidation::element::restyle_hints::RESTYLE_SELF;
 use style::properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
 use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size, overflow_x};
 use style::rule_tree::CascadeLevel;
 use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser};
 use style::selector_parser::extended_filtering;
 use style::shared_lock::{SharedRwLock, Locked};
@@ -2192,57 +2193,47 @@ impl ElementMethods for Element {
 
     // https://dom.spec.whatwg.org/#dom-childnode-remove
     fn Remove(&self) {
         self.upcast::<Node>().remove_self();
     }
 
     // https://dom.spec.whatwg.org/#dom-element-matches
     fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
-        match SelectorParser::parse_author_origin_no_namespace(&selectors) {
-            Err(_) => Err(Error::Syntax),
-            Ok(selectors) => {
-                let quirks_mode = document_from_node(self).quirks_mode();
-                let root = DomRoot::from_ref(self);
-                // FIXME(bholley): Consider an nth-index cache here.
-                let mut ctx = MatchingContext::new(MatchingMode::Normal, None, None,
-                                                   quirks_mode);
-                ctx.scope_element = Some(root.opaque());
-                Ok(matches_selector_list(&selectors, &root, &mut ctx))
-            }
-        }
+        let selectors =
+            match SelectorParser::parse_author_origin_no_namespace(&selectors) {
+                Err(_) => return Err(Error::Syntax),
+                Ok(selectors) => selectors,
+            };
+
+        let quirks_mode = document_from_node(self).quirks_mode();
+        let element = DomRoot::from_ref(self);
+
+        Ok(dom_apis::element_matches(&element, &selectors, quirks_mode))
     }
 
     // https://dom.spec.whatwg.org/#dom-element-webkitmatchesselector
     fn WebkitMatchesSelector(&self, selectors: DOMString) -> Fallible<bool> {
         self.Matches(selectors)
     }
 
     // https://dom.spec.whatwg.org/#dom-element-closest
     fn Closest(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
-        match SelectorParser::parse_author_origin_no_namespace(&selectors) {
-            Err(_) => Err(Error::Syntax),
-            Ok(selectors) => {
-                let self_root = DomRoot::from_ref(self);
-                let root = self.upcast::<Node>();
-                for element in root.inclusive_ancestors() {
-                    if let Some(element) = DomRoot::downcast::<Element>(element) {
-                        let quirks_mode = document_from_node(self).quirks_mode();
-                        // FIXME(bholley): Consider an nth-index cache here.
-                        let mut ctx = MatchingContext::new(MatchingMode::Normal, None, None,
-                                                           quirks_mode);
-                        ctx.scope_element = Some(self_root.opaque());
-                        if matches_selector_list(&selectors, &element, &mut ctx) {
-                            return Ok(Some(element));
-                        }
-                    }
-                }
-                Ok(None)
-            }
-        }
+        let selectors =
+            match SelectorParser::parse_author_origin_no_namespace(&selectors) {
+                Err(_) => return Err(Error::Syntax),
+                Ok(selectors) => selectors,
+            };
+
+        let quirks_mode = document_from_node(self).quirks_mode();
+        Ok(dom_apis::element_closest(
+            DomRoot::from_ref(self),
+            &selectors,
+            quirks_mode,
+        ))
     }
 
     // https://dom.spec.whatwg.org/#dom-element-insertadjacentelement
     fn InsertAdjacentElement(&self, where_: DOMString, element: &Element)
                              -> Fallible<Option<DomRoot<Element>>> {
         let where_ = where_.parse::<AdjacentPosition>()?;
         let inserted_node = self.insert_adjacent(where_, element.upcast())?;
         Ok(inserted_node.map(|node| DomRoot::downcast(node).unwrap()))
--- a/servo/components/script_layout_interface/Cargo.toml
+++ b/servo/components/script_layout_interface/Cargo.toml
@@ -20,16 +20,17 @@ heapsize = "0.4"
 heapsize_derive = "0.1"
 html5ever = "0.20.0"
 ipc-channel = "0.8"
 libc = "0.2"
 log = "0.3.5"
 metrics = {path = "../metrics"}
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
+nonzero = {path = "../nonzero"}
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
 script_traits = {path = "../script_traits"}
 selectors = { path = "../selectors" }
 servo_arc = {path = "../servo_arc"}
 servo_atoms = {path = "../atoms"}
 servo_url = {path = "../url"}
 style = {path = "../style"}
--- a/servo/components/script_layout_interface/lib.rs
+++ b/servo/components/script_layout_interface/lib.rs
@@ -2,35 +2,34 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! This module contains traits in script used generically in the rest of Servo.
 //! The traits are here instead of in script so that these modules won't have
 //! to depend on script.
 
 #![deny(unsafe_code)]
-#![feature(nonzero)]
 
 extern crate app_units;
 extern crate atomic_refcell;
 extern crate canvas_traits;
-extern crate core;
 extern crate cssparser;
 extern crate euclid;
 extern crate gfx_traits;
 extern crate heapsize;
 #[macro_use] extern crate heapsize_derive;
 #[macro_use] extern crate html5ever;
 extern crate ipc_channel;
 extern crate libc;
 #[macro_use]
 extern crate log;
 extern crate metrics;
 extern crate msg;
 extern crate net_traits;
+extern crate nonzero;
 extern crate profile_traits;
 extern crate range;
 extern crate script_traits;
 extern crate selectors;
 extern crate servo_arc;
 extern crate servo_atoms;
 extern crate servo_url;
 extern crate style;
@@ -38,22 +37,23 @@ extern crate webrender_api;
 
 pub mod message;
 pub mod reporter;
 pub mod rpc;
 pub mod wrapper_traits;
 
 use atomic_refcell::AtomicRefCell;
 use canvas_traits::canvas::CanvasMsg;
-use core::nonzero::NonZero;
 use ipc_channel::ipc::IpcSender;
 use libc::c_void;
 use net_traits::image_cache::PendingImageId;
+use nonzero::NonZeroUsize;
 use script_traits::UntrustedNodeAddress;
 use servo_url::ServoUrl;
+use std::marker::PhantomData;
 use std::sync::atomic::AtomicIsize;
 use style::data::ElementData;
 
 #[repr(C)]
 pub struct StyleData {
     /// Data that the style system associates with a node. When the
     /// style system is being used standalone, this is all that hangs
     /// off the node. This must be first to permit the various
@@ -73,17 +73,18 @@ impl StyleData {
     }
 }
 
 #[derive(Clone, Copy, HeapSizeOf)]
 pub struct OpaqueStyleAndLayoutData {
     // NB: We really store a `StyleAndLayoutData` here, so be careful!
     #[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but \
                              the type lives in layout"]
-    pub ptr: NonZero<*mut StyleData>
+    pub ptr: NonZeroUsize,
+    pub phantom: PhantomData<*mut StyleData>,
 }
 
 #[allow(unsafe_code)]
 unsafe impl Send for OpaqueStyleAndLayoutData {}
 
 /// Information that we need stored in each DOM node.
 #[derive(HeapSizeOf)]
 pub struct DomParallelInfo {
--- a/servo/components/selectors/Cargo.toml
+++ b/servo/components/selectors/Cargo.toml
@@ -15,17 +15,17 @@ build = "build.rs"
 [lib]
 name = "selectors"
 path = "lib.rs"
 # https://github.com/servo/servo/issues/16710
 doctest = false
 
 [features]
 gecko_like_types = []
-unstable = []
+bench = []
 
 [dependencies]
 bitflags = "0.7"
 matches = "0.1"
 cssparser = "0.22.0"
 log = "0.3"
 fnv = "1.0"
 malloc_size_of = { path = "../malloc_size_of" }
--- a/servo/components/selectors/bloom.rs
+++ b/servo/components/selectors/bloom.rs
@@ -341,17 +341,17 @@ fn create_and_insert_some_stuff() {
 
     bf.clear();
 
     for i in 0_usize .. 2000 {
         assert!(!bf.might_contain(&i));
     }
 }
 
-#[cfg(feature = "unstable")]
+#[cfg(feature = "bench")]
 #[cfg(test)]
 mod bench {
     extern crate test;
     use super::BloomFilter;
 
     #[derive(Default)]
     struct HashGenerator(u32);
 
--- a/servo/components/selectors/lib.rs
+++ b/servo/components/selectors/lib.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Make |cargo bench| work.
-#![cfg_attr(feature = "unstable", feature(test))]
+#![cfg_attr(feature = "bench", feature(test))]
 
 #[macro_use] extern crate bitflags;
 #[macro_use] extern crate cssparser;
 #[macro_use] extern crate log;
 #[macro_use] extern crate matches;
 extern crate fnv;
 extern crate malloc_size_of;
 #[macro_use] extern crate malloc_size_of_derive;
--- a/servo/components/servo/Cargo.toml
+++ b/servo/components/servo/Cargo.toml
@@ -7,23 +7,28 @@ license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "servo"
 path = "lib.rs"
 crate-type = ["rlib"]
 
 [features]
-default = ["webdriver", "max_log_level"]
 max_log_level = ["log/release_max_level_info"]
 webdriver = ["webdriver_server"]
 energy-profiling = ["profile_traits/energy-profiling"]
 debugmozjs = ["script/debugmozjs"]
 googlevr = ["webvr/googlevr"]
 oculusvr = ["webvr/oculusvr"]
+unstable = [
+    "euclid/unstable",
+    "gfx/unstable",
+    "msg/unstable",
+    "profile/unstable",
+]
 
 [dependencies]
 bluetooth_traits = {path = "../bluetooth_traits"}
 bluetooth = {path = "../bluetooth"}
 canvas = {path = "../canvas"}
 canvas_traits = {path = "../canvas_traits"}
 compositing = {path = "../compositing"}
 constellation = {path = "../constellation"}
new file mode 100644
--- /dev/null
+++ b/servo/components/style/dom_apis.rs
@@ -0,0 +1,59 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//! Generic implementations of some DOM APIs so they can be shared between Servo
+//! and Gecko.
+
+use context::QuirksMode;
+use selectors::{Element, NthIndexCache, SelectorList};
+use selectors::matching::{self, MatchingContext, MatchingMode};
+
+/// https://dom.spec.whatwg.org/#dom-element-matches
+pub fn element_matches<E>(
+    element: &E,
+    selector_list: &SelectorList<E::Impl>,
+    quirks_mode: QuirksMode,
+) -> bool
+where
+    E: Element,
+{
+    let mut context = MatchingContext::new(
+        MatchingMode::Normal,
+        None,
+        None,
+        quirks_mode,
+    );
+    context.scope_element = Some(element.opaque());
+    matching::matches_selector_list(selector_list, element, &mut context)
+}
+
+/// https://dom.spec.whatwg.org/#dom-element-closest
+pub fn element_closest<E>(
+    element: E,
+    selector_list: &SelectorList<E::Impl>,
+    quirks_mode: QuirksMode,
+) -> Option<E>
+where
+    E: Element,
+{
+    let mut nth_index_cache = NthIndexCache::default();
+
+    let mut context = MatchingContext::new(
+        MatchingMode::Normal,
+        None,
+        Some(&mut nth_index_cache),
+        quirks_mode,
+    );
+    context.scope_element = Some(element.opaque());
+
+    let mut current = Some(element);
+    while let Some(element) = current.take() {
+        if matching::matches_selector_list(selector_list, &element, &mut context) {
+            return Some(element);
+        }
+        current = element.parent_element();
+    }
+
+    return None;
+}
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -2922,20 +2922,16 @@ extern "C" {
                                 was_restyled: *mut bool) -> u32;
 }
 extern "C" {
     pub fn Servo_ResolveStyle(element: RawGeckoElementBorrowed,
                               set: RawServoStyleSetBorrowed)
      -> ServoStyleContextStrong;
 }
 extern "C" {
-    pub fn Servo_ResolveStyleAllowStale(element: RawGeckoElementBorrowed)
-     -> ServoStyleContextStrong;
-}
-extern "C" {
     pub fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
                                     pseudo_type: CSSPseudoElementType,
                                     is_probe: bool,
                                     inherited_style:
                                         ServoStyleContextBorrowedOrNull,
                                     set: RawServoStyleSetBorrowed)
      -> ServoStyleContextStrong;
 }
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -102,16 +102,17 @@ pub mod applicable_declarations;
 #[cfg(feature = "servo")] pub mod attr;
 pub mod bezier;
 pub mod bloom;
 pub mod context;
 pub mod counter_style;
 pub mod custom_properties;
 pub mod data;
 pub mod dom;
+pub mod dom_apis;
 pub mod driver;
 pub mod element_state;
 #[cfg(feature = "servo")] mod encoding_support;
 pub mod error_reporting;
 pub mod font_face;
 pub mod font_metrics;
 #[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko;
 #[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
--- a/servo/components/style/properties/declaration_block.rs
+++ b/servo/components/style/properties/declaration_block.rs
@@ -1011,25 +1011,27 @@ pub fn parse_style_attribute<R>(input: &
     let mut input = ParserInput::new(input);
     parse_property_declaration_list(&context, &error_context, &mut Parser::new(&mut input))
 }
 
 /// Parse a given property declaration. Can result in multiple
 /// `PropertyDeclaration`s when expanding a shorthand, for example.
 ///
 /// This does not attempt to parse !important at all.
-pub fn parse_one_declaration_into<R>(declarations: &mut SourcePropertyDeclaration,
-                                     id: PropertyId,
-                                     input: &str,
-                                     url_data: &UrlExtraData,
-                                     error_reporter: &R,
-                                     parsing_mode: ParsingMode,
-                                     quirks_mode: QuirksMode)
-                                     -> Result<(), ()>
-    where R: ParseErrorReporter
+pub fn parse_one_declaration_into<R>(
+    declarations: &mut SourcePropertyDeclaration,
+    id: PropertyId,
+    input: &str,
+    url_data: &UrlExtraData,
+    error_reporter: &R,
+    parsing_mode: ParsingMode,
+    quirks_mode: QuirksMode
+) -> Result<(), ()>
+where
+    R: ParseErrorReporter
 {
     let context = ParserContext::new(Origin::Author,
                                      url_data,
                                      Some(CssRuleType::Style),
                                      parsing_mode,
                                      quirks_mode);
     let mut input = ParserInput::new(input);
     let mut parser = Parser::new(&mut input);
@@ -1097,21 +1099,23 @@ impl<'a, 'b, 'i> DeclarationParser<'i> f
         input.expect_exhausted()?;
         Ok(importance)
     }
 }
 
 
 /// Parse a list of property declarations and return a property declaration
 /// block.
-pub fn parse_property_declaration_list<R>(context: &ParserContext,
-                                          error_context: &ParserErrorContext<R>,
-                                          input: &mut Parser)
-                                          -> PropertyDeclarationBlock
-    where R: ParseErrorReporter
+pub fn parse_property_declaration_list<R>(
+    context: &ParserContext,
+    error_context: &ParserErrorContext<R>,
+    input: &mut Parser,
+) -> PropertyDeclarationBlock
+where
+    R: ParseErrorReporter
 {
     let mut declarations = SourcePropertyDeclaration::new();
     let mut block = PropertyDeclarationBlock::new();
     let parser = PropertyDeclarationParser {
         context: context,
         declarations: &mut declarations,
     };
     let mut iter = DeclarationListParser::new(input, parser);
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -864,19 +864,22 @@ impl ShorthandId {
                     % for flag in property.flags:
                         ${flag} |
                     % endfor
                     PropertyFlags::empty(),
             % endfor
         }
     }
 
-    fn parse_into<'i, 't>(&self, declarations: &mut SourcePropertyDeclaration,
-                          context: &ParserContext, input: &mut Parser<'i, 't>)
-                          -> Result<(), ParseError<'i>> {
+    fn parse_into<'i, 't>(
+        &self,
+        declarations: &mut SourcePropertyDeclaration,
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<(), ParseError<'i>> {
         match *self {
             % for shorthand in data.shorthands_except_all():
                 ShorthandId::${shorthand.camel_case} => {
                     shorthands::${shorthand.ident}::parse_into(declarations, context, input)
                 }
             % endfor
             // 'all' accepts no value other than CSS-wide keywords
             ShorthandId::All => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
@@ -1623,20 +1626,23 @@ impl PropertyDeclaration {
     /// https://drafts.csswg.org/css-animations/#keyframes
     /// > The <declaration-list> inside of <keyframe-block> accepts any CSS property
     /// > except those defined in this specification,
     /// > but does accept the `animation-play-state` property and interprets it specially.
     ///
     /// This will not actually parse Importance values, and will always set things
     /// to Importance::Normal. Parsing Importance values is the job of PropertyDeclarationParser,
     /// we only set them here so that we don't have to reallocate
-    pub fn parse_into<'i, 't>(declarations: &mut SourcePropertyDeclaration,
-                              id: PropertyId, name: CowRcStr<'i>,
-                              context: &ParserContext, input: &mut Parser<'i, 't>)
-                              -> Result<(), ParseError<'i>> {
+    pub fn parse_into<'i, 't>(
+        declarations: &mut SourcePropertyDeclaration,
+        id: PropertyId,
+        name: CowRcStr<'i>,
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<(), ParseError<'i>> {
         assert!(declarations.is_empty());
         let start = input.state();
         match id {
             PropertyId::Custom(property_name) => {
                 // FIXME: fully implement https://github.com/w3c/csswg-drafts/issues/774
                 // before adding skip_whitespace here.
                 // This probably affects some test results.
                 let value = match input.try(|i| CSSWideKeyword::parse(i)) {
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cssparser::{Parser, ParserInput};
 use cssparser::ToCss as ParserToCss;
 use env_logger::LogBuilder;
 use malloc_size_of::MallocSizeOfOps;
-use selectors::{self, Element, NthIndexCache};
+use selectors::Element;
 use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
 use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
 use std::cell::RefCell;
 use std::env;
 use std::fmt::Write;
 use std::iter;
 use std::mem;
 use std::ptr;
@@ -1521,58 +1521,40 @@ pub extern "C" fn Servo_StyleRule_Select
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn Servo_SelectorList_Closest<'a>(
     element: RawGeckoElementBorrowed<'a>,
     selectors: RawServoSelectorListBorrowed,
 ) -> RawGeckoElementBorrowedOrNull<'a> {
     use std::borrow::Borrow;
-
-    let mut nth_index_cache = NthIndexCache::default();
+    use style::dom_apis;
 
     let element = GeckoElement(element);
-    let mut context = MatchingContext::new(
-        MatchingMode::Normal,
-        None,
-        Some(&mut nth_index_cache),
-        element.owner_document_quirks_mode(),
-    );
-    context.scope_element = Some(element.opaque());
-
     let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
-    let mut current = Some(element);
-    while let Some(element) = current.take() {
-        if selectors::matching::matches_selector_list(&selectors, &element, &mut context) {
-            return Some(element.0);
-        }
-        current = element.parent_element();
-    }
-
-    return None;
+
+    dom_apis::element_closest(element, &selectors, element.owner_document_quirks_mode())
+        .map(|e| e.0)
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn Servo_SelectorList_Matches(
     element: RawGeckoElementBorrowed,
     selectors: RawServoSelectorListBorrowed,
 ) -> bool {
     use std::borrow::Borrow;
+    use style::dom_apis;
 
     let element = GeckoElement(element);
-    let mut context = MatchingContext::new(
-        MatchingMode::Normal,
-        None,
-        None,
+    let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
+    dom_apis::element_matches(
+        &element,
+        &selectors,
         element.owner_document_quirks_mode(),
-    );
-    context.scope_element = Some(element.opaque());
-
-    let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
-    selectors::matching::matches_selector_list(&selectors, &element, &mut context)
+    )
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ImportRule_GetHref(rule: RawServoImportRuleBorrowed, result: *mut nsAString) {
     read_locked_arc(rule, |rule: &ImportRule| {
         write!(unsafe { &mut *result }, "{}", rule.url.as_str()).unwrap();
     })
 }
@@ -2160,25 +2142,27 @@ pub extern "C" fn Servo_StyleSet_CompatM
     let quirks_mode = unsafe {
         (*data.stylist.device().pres_context().mDocument.raw::<nsIDocument>())
             .mCompatMode
     };
 
     data.stylist.set_quirks_mode(quirks_mode.into());
 }
 
-fn parse_property_into<R>(declarations: &mut SourcePropertyDeclaration,
-                          property_id: PropertyId,
-                          value: *const nsACString,
-                          data: *mut URLExtraData,
-                          parsing_mode: structs::ParsingMode,
-                          quirks_mode: QuirksMode,
-                          reporter: &R)
-                          -> Result<(), ()>
-    where R: ParseErrorReporter
+fn parse_property_into<R>(
+    declarations: &mut SourcePropertyDeclaration,
+    property_id: PropertyId,
+    value: *const nsACString,
+    data: *mut URLExtraData,
+    parsing_mode: structs::ParsingMode,
+    quirks_mode: QuirksMode,
+    reporter: &R
+) -> Result<(), ()>
+where
+    R: ParseErrorReporter
 {
     use style_traits::ParsingMode;
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
     let url_data = unsafe { RefPtr::from_ptr_ref(&data) };
     let parsing_mode = ParsingMode::from_bits_truncate(parsing_mode);
 
     parse_one_declaration_into(
         declarations,
@@ -2186,22 +2170,23 @@ fn parse_property_into<R>(declarations: 
         value,
         url_data,
         reporter,
         parsing_mode,
         quirks_mode)
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_ParseProperty(property: nsCSSPropertyID, value: *const nsACString,
-                                      data: *mut URLExtraData,
-                                      parsing_mode: structs::ParsingMode,
-                                      quirks_mode: nsCompatibility,
-                                      loader: *mut Loader)
-                                      -> RawServoDeclarationBlockStrong {
+pub extern "C" fn Servo_ParseProperty(
+    property: nsCSSPropertyID, value: *const nsACString,
+    data: *mut URLExtraData,
+    parsing_mode: structs::ParsingMode,
+    quirks_mode: nsCompatibility,
+    loader: *mut Loader,
+) -> RawServoDeclarationBlockStrong {
     let id = get_property_id_from_nscsspropertyid!(property,
                                                    RawServoDeclarationBlockStrong::null());
     let mut declarations = SourcePropertyDeclaration::new();
     let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
     match parse_property_into(&mut declarations, id, value, data,
                               parsing_mode, quirks_mode.into(), &reporter) {
         Ok(()) => {
             let global_style_data = &*GLOBAL_STYLE_DATA;
@@ -2209,20 +2194,21 @@ pub extern "C" fn Servo_ParseProperty(pr
             block.extend(declarations.drain(), Importance::Normal);
             Arc::new(global_style_data.shared_lock.wrap(block)).into_strong()
         }
         Err(_) => RawServoDeclarationBlockStrong::null()
     }
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_ParseEasing(easing: *const nsAString,
-                                    data: *mut URLExtraData,
-                                    output: nsTimingFunctionBorrowedMut)
-                                    -> bool {
+pub extern "C" fn Servo_ParseEasing(
+    easing: *const nsAString,
+    data: *mut URLExtraData,
+    output: nsTimingFunctionBorrowedMut
+) -> bool {
     use style::properties::longhands::transition_timing_function;
 
     let url_data = unsafe { RefPtr::from_ptr_ref(&data) };
     let context = ParserContext::new(Origin::Author,
                                      url_data,
                                      Some(CssRuleType::Style),
                                      PARSING_MODE_DEFAULT,
                                      QuirksMode::NoQuirks);
@@ -2294,21 +2280,22 @@ pub extern "C" fn Servo_MatrixTransform_
     } else if progress < 0.5 {
         *output = from.clone().into();
     } else {
         *output = to.clone().into();
     }
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_ParseStyleAttribute(data: *const nsACString,
-                                            raw_extra_data: *mut URLExtraData,
-                                            quirks_mode: nsCompatibility,
-                                            loader: *mut Loader)
-                                            -> RawServoDeclarationBlockStrong {
+pub extern "C" fn Servo_ParseStyleAttribute(
+    data: *const nsACString,
+    raw_extra_data: *mut URLExtraData,
+    quirks_mode: nsCompatibility,
+    loader: *mut Loader,
+) -> RawServoDeclarationBlockStrong {
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let value = unsafe { data.as_ref().unwrap().as_str_unchecked() };
     let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data);
     let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) };
     Arc::new(global_style_data.shared_lock.wrap(
         GeckoElement::parse_style_attribute(value, url_data, quirks_mode.into(), &reporter)))
         .into_strong()
 }
@@ -2326,19 +2313,20 @@ pub extern "C" fn Servo_DeclarationBlock
     let guard = global_style_data.shared_lock.read();
     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
     Arc::new(global_style_data.shared_lock.wrap(
         declarations.read_with(&guard).clone()
     )).into_strong()
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed,
-                                                b: RawServoDeclarationBlockBorrowed)
-                                                -> bool {
+pub extern "C" fn Servo_DeclarationBlock_Equals(
+    a: RawServoDeclarationBlockBorrowed,
+    b: RawServoDeclarationBlockBorrowed,
+) -> bool {
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     *Locked::<PropertyDeclarationBlock>::as_arc(&a).read_with(&guard).declarations() ==
     *Locked::<PropertyDeclarationBlock>::as_arc(&b).read_with(&guard).declarations()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclarationBlockBorrowed,
@@ -2348,18 +2336,18 @@ pub extern "C" fn Servo_DeclarationBlock
     })
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
     declarations: RawServoDeclarationBlockBorrowed,
     property_id: nsCSSPropertyID, buffer: *mut nsAString,
     computed_values: ServoStyleContextBorrowedOrNull,
-    custom_properties: RawServoDeclarationBlockBorrowedOrNull)
-{
+    custom_properties: RawServoDeclarationBlockBorrowedOrNull,
+) {
     let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
 
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let decls = Locked::<PropertyDeclarationBlock>::as_arc(&declarations).read_with(&guard);
 
     let mut string = String::new();
 
@@ -2371,17 +2359,18 @@ pub extern "C" fn Servo_DeclarationBlock
 
     let buffer = unsafe { buffer.as_mut().unwrap() };
     buffer.assign_utf8(&string);
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_SerializeFontValueForCanvas(
     declarations: RawServoDeclarationBlockBorrowed,
-    buffer: *mut nsAString) {
+    buffer: *mut nsAString,
+) {
     use style::properties::shorthands::font;
 
     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
         let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) {
             Ok(l) => l,
             Err(()) => {
                 warn!("Unexpected property!");
                 return;
@@ -2400,18 +2389,21 @@ pub extern "C" fn Servo_SerializeFontVal
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_Count(declarations: RawServoDeclarationBlockBorrowed) -> u32 {
     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
         decls.declarations().len() as u32
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(declarations: RawServoDeclarationBlockBorrowed,
-                                                        index: u32, result: *mut nsAString) -> bool {
+pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(
+    declarations: RawServoDeclarationBlockBorrowed,
+    index: u32,
+    result: *mut nsAString,
+) -> bool {
     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
         if let Some(decl) = decls.declarations().get(index as usize) {
             let result = unsafe { result.as_mut().unwrap() };
             result.assign_utf8(&decl.id().name());
             true
         } else {
             false
         }
@@ -2469,21 +2461,26 @@ pub unsafe extern "C" fn Servo_Declarati
     property: *const nsACString,
 ) -> bool {
     let property_id = get_property_id_from_property!(property, false);
     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
         decls.property_priority(&property_id).important()
     })
 }
 
-fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId,
-                value: *const nsACString, is_important: bool, data: *mut URLExtraData,
-                parsing_mode: structs::ParsingMode,
-                quirks_mode: QuirksMode,
-                loader: *mut Loader) -> bool {
+fn set_property(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property_id: PropertyId,
+    value: *const nsACString,
+    is_important: bool,
+    data: *mut URLExtraData,
+    parsing_mode: structs::ParsingMode,
+    quirks_mode: QuirksMode,
+    loader: *mut Loader
+) -> bool {
     let mut source_declarations = SourcePropertyDeclaration::new();
     let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
     match parse_property_into(&mut source_declarations, property_id, value, data,
                               parsing_mode, quirks_mode, &reporter) {
         Ok(()) => {
             let importance = if is_important { Importance::Important } else { Importance::Normal };
             write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
                 decls.extend_reset(source_declarations.drain(), importance)
@@ -2570,28 +2567,31 @@ pub extern "C" fn Servo_MediaList_DeepCl
     let global_style_data = &*GLOBAL_STYLE_DATA;
     read_locked_arc(list, |list: &MediaList| {
         Arc::new(global_style_data.shared_lock.wrap(list.clone()))
             .into_strong()
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_MediaList_Matches(list: RawServoMediaListBorrowed,
-                                          raw_data: RawServoStyleSetBorrowed)
-                                          -> bool {
+pub extern "C" fn Servo_MediaList_Matches(
+    list: RawServoMediaListBorrowed,
+    raw_data: RawServoStyleSetBorrowed,
+) -> bool {
     let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
     read_locked_arc(list, |list: &MediaList| {
         list.evaluate(per_doc_data.stylist.device(), per_doc_data.stylist.quirks_mode())
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword(declarations: RawServoDeclarationBlockBorrowed,
-                                                           property: nsCSSPropertyID) -> bool {
+pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+) -> bool {
     let property_id = get_property_id_from_nscsspropertyid!(property, false);
     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
         decls.has_css_wide_keyword(&property_id)
     })
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_GetText(list: RawServoMediaListBorrowed, result: *mut nsAString) {
@@ -2615,44 +2615,51 @@ pub extern "C" fn Servo_MediaList_SetTex
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_GetLength(list: RawServoMediaListBorrowed) -> u32 {
     read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32)
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_MediaList_GetMediumAt(list: RawServoMediaListBorrowed, index: u32,
-                                              result: *mut nsAString) -> bool {
+pub extern "C" fn Servo_MediaList_GetMediumAt(
+    list: RawServoMediaListBorrowed,
+    index: u32,
+    result: *mut nsAString,
+) -> bool {
     read_locked_arc(list, |list: &MediaList| {
         if let Some(media_query) = list.media_queries.get(index as usize) {
             media_query.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
             true
         } else {
             false
         }
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_MediaList_AppendMedium(list: RawServoMediaListBorrowed,
-                                               new_medium: *const nsACString) {
+pub extern "C" fn Servo_MediaList_AppendMedium(
+    list: RawServoMediaListBorrowed,
+    new_medium: *const nsACString,
+) {
     let new_medium = unsafe { new_medium.as_ref().unwrap().as_str_unchecked() };
     let url_data = unsafe { dummy_url_data() };
     let context = ParserContext::new_for_cssom(url_data, Some(CssRuleType::Media),
                                                PARSING_MODE_DEFAULT,
                                                QuirksMode::NoQuirks);
     write_locked_arc(list, |list: &mut MediaList| {
         list.append_medium(&context, new_medium);
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_MediaList_DeleteMedium(list: RawServoMediaListBorrowed,
-                                               old_medium: *const nsACString) -> bool {
+pub extern "C" fn Servo_MediaList_DeleteMedium(
+    list: RawServoMediaListBorrowed,
+    old_medium: *const nsACString,
+) -> bool {
     let old_medium = unsafe { old_medium.as_ref().unwrap().as_str_unchecked() };
     let url_data = unsafe { dummy_url_data() };
     let context = ParserContext::new_for_cssom(url_data, Some(CssRuleType::Media),
                                                PARSING_MODE_DEFAULT,
                                                QuirksMode::NoQuirks);
     write_locked_arc(list, |list: &mut MediaList| list.delete_medium(&context, old_medium))
 }
 
@@ -2686,40 +2693,40 @@ pub extern "C" fn Servo_DeclarationBlock
                                                        property: nsCSSPropertyID)
         -> bool {
     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
         decls.contains(get_longhand_from_id!(property))
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(declarations:
-                                                             RawServoDeclarationBlockBorrowed,
-                                                             property:
-                                                             nsCSSPropertyID,
-                                                             value:
-                                                             *mut nsAtom) {
+pub extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+    value: *mut nsAtom,
+) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::_x_lang::computed_value::T as Lang;
 
     let long = get_longhand_from_id!(property);
     let prop = match_wrap_declared! { long,
         XLang => Lang(Atom::from(value)),
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 #[no_mangle]
 #[allow(unreachable_code)]
-pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations:
-                                                         RawServoDeclarationBlockBorrowed,
-                                                         property: nsCSSPropertyID,
-                                                         value: i32) {
+pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+    value: i32
+) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands;
     use style::values::specified::BorderStyle;
 
     let long = get_longhand_from_id!(property);
     let value = value as u32;
 
     let prop = match_wrap_declared! { long,
@@ -2750,39 +2757,42 @@ pub extern "C" fn Servo_DeclarationBlock
         BorderLeftStyle => BorderStyle::from_gecko_keyword(value),
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetIntValue(declarations: RawServoDeclarationBlockBorrowed,
-                                                     property: nsCSSPropertyID,
-                                                     value: i32) {
+pub extern "C" fn Servo_DeclarationBlock_SetIntValue(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+    value: i32
+) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::_moz_script_level::SpecifiedValue as MozScriptLevel;
     use style::properties::longhands::_x_span::computed_value::T as Span;
 
     let long = get_longhand_from_id!(property);
     let prop = match_wrap_declared! { long,
         XSpan => Span(value),
         // Gecko uses Integer values to signal that it is relative
         MozScriptLevel => MozScriptLevel::Relative(value),
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations:
-                                                       RawServoDeclarationBlockBorrowed,
-                                                       property: nsCSSPropertyID,
-                                                       value: f32) {
+pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+    value: f32
+) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
     use style::properties::longhands::height::SpecifiedValue as Height;
     use style::properties::longhands::width::SpecifiedValue as Width;
     use style::values::specified::{BorderSideWidth, MozLength, BorderCornerRadius};
     use style::values::specified::length::{NoCalcLength, NonNegativeLength, LengthOrPercentage};
 
     let long = get_longhand_from_id!(property);
@@ -2826,21 +2836,22 @@ pub extern "C" fn Servo_DeclarationBlock
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(declarations:
-                                                        RawServoDeclarationBlockBorrowed,
-                                                        property: nsCSSPropertyID,
-                                                        value: f32,
-                                                        unit: structs::nsCSSUnit) {
+pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+    value: f32,
+    unit: structs::nsCSSUnit,
+) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::_moz_script_min_size::SpecifiedValue as MozScriptMinSize;
     use style::properties::longhands::width::SpecifiedValue as Width;
     use style::values::specified::MozLength;
     use style::values::specified::length::{AbsoluteLength, FontRelativeLength, PhysicalLength};
     use style::values::specified::length::{LengthOrPercentage, NoCalcLength};
 
     let long = get_longhand_from_id!(property);
@@ -2864,40 +2875,42 @@ pub extern "C" fn Servo_DeclarationBlock
         MozScriptMinSize => MozScriptMinSize(nocalc),
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetNumberValue(declarations:
-                                                       RawServoDeclarationBlockBorrowed,
-                                                       property: nsCSSPropertyID,
-                                                       value: f32) {
+pub extern "C" fn Servo_DeclarationBlock_SetNumberValue(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+    value: f32,
+) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::_moz_script_level::SpecifiedValue as MozScriptLevel;
 
     let long = get_longhand_from_id!(property);
 
     let prop = match_wrap_declared! { long,
         MozScriptSizeMultiplier => value,
         // Gecko uses Number values to signal that it is absolute
         MozScriptLevel => MozScriptLevel::Absolute(value as i32),
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations:
-                                                         RawServoDeclarationBlockBorrowed,
-                                                         property: nsCSSPropertyID,
-                                                         value: f32) {
+pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+    value: f32,
+) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::height::SpecifiedValue as Height;
     use style::properties::longhands::width::SpecifiedValue as Width;
     use style::values::computed::Percentage;
     use style::values::specified::MozLength;
     use style::values::specified::length::LengthOrPercentage;
 
     let long = get_longhand_from_id!(property);
@@ -2913,19 +2926,20 @@ pub extern "C" fn Servo_DeclarationBlock
         FontSize => LengthOrPercentage::from(pc).into(),
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations:
-                                                      RawServoDeclarationBlockBorrowed,
-                                                      property: nsCSSPropertyID) {
+pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::height::SpecifiedValue as Height;
     use style::properties::longhands::width::SpecifiedValue as Width;
     use style::values::specified::LengthOrPercentageOrAuto;
 
     let long = get_longhand_from_id!(property);
     let auto = LengthOrPercentageOrAuto::Auto;
 
@@ -2938,19 +2952,20 @@ pub extern "C" fn Servo_DeclarationBlock
         MarginLeft => auto,
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations:
-                                                         RawServoDeclarationBlockBorrowed,
-                                                         property: nsCSSPropertyID) {
+pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::values::specified::Color;
 
     let long = get_longhand_from_id!(property);
     let cc = Color::currentcolor();
 
     let prop = match_wrap_declared! { long,
         BorderTopColor => cc,
@@ -2959,20 +2974,21 @@ pub extern "C" fn Servo_DeclarationBlock
         BorderLeftColor => cc,
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations:
-                                                       RawServoDeclarationBlockBorrowed,
-                                                       property: nsCSSPropertyID,
-                                                       value: structs::nscolor) {
+pub extern "C" fn Servo_DeclarationBlock_SetColorValue(
+    declarations: RawServoDeclarationBlockBorrowed,
+    property: nsCSSPropertyID,
+    value: structs::nscolor,
+) {
     use style::gecko::values::convert_nscolor_to_rgba;
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands;
     use style::values::specified::Color;
 
     let long = get_longhand_from_id!(property);
     let rgba = convert_nscolor_to_rgba(value);
     let color = Color::rgba(rgba);
@@ -2986,19 +3002,20 @@ pub extern "C" fn Servo_DeclarationBlock
         BackgroundColor => color,
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(prop, Importance::Normal);
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(declarations:
-                                                       RawServoDeclarationBlockBorrowed,
-                                                       value: *const nsAString) {
+pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(
+    declarations: RawServoDeclarationBlockBorrowed,
+    value: *const nsAString,
+) {
     use cssparser::{Parser, ParserInput};
     use style::properties::PropertyDeclaration;
     use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
 
     let string = unsafe { (*value).to_string() };
     let mut input = ParserInput::new(&string);
     let mut parser = Parser::new(&mut input);
     let result = FontFamily::parse(&mut parser);
@@ -3008,20 +3025,21 @@ pub extern "C" fn Servo_DeclarationBlock
             write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
                 decls.push(decl, Importance::Normal);
             })
         }
     }
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(declarations:
-                                                            RawServoDeclarationBlockBorrowed,
-                                                            value: *const nsAString,
-                                                            raw_extra_data: *mut URLExtraData) {
+pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(
+    declarations: RawServoDeclarationBlockBorrowed,
+    value: *const nsAString,
+    raw_extra_data: *mut URLExtraData,
+) {
     use style::properties::PropertyDeclaration;
     use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
     use style::values::Either;
     use style::values::generics::image::Image;
     use style::values::specified::url::SpecifiedUrl;
 
     let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) };
     let string = unsafe { (*value).to_string() };
@@ -3035,18 +3053,19 @@ pub extern "C" fn Servo_DeclarationBlock
         ));
         write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
             decls.push(decl, Importance::Normal);
         })
     }
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(declarations:
-                                                                RawServoDeclarationBlockBorrowed) {
+pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(
+    declarations: RawServoDeclarationBlockBorrowed,
+) {
     use style::properties::PropertyDeclaration;
     use style::properties::longhands::text_decoration_line;
 
     let mut decoration = text_decoration_line::computed_value::none;
     decoration |= text_decoration_line::COLOR_OVERRIDE;
     let decl = PropertyDeclaration::TextDecorationLine(decoration);
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(decl, Importance::Normal);
@@ -3091,26 +3110,29 @@ pub extern "C" fn Servo_CSSSupports(cond
             );
         cond.eval(&context)
     } else {
         false
     }
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed,
-                                          restyle_hint: nsRestyleHint,
-                                          change_hint: nsChangeHint) {
+pub extern "C" fn Servo_NoteExplicitHints(
+    element: RawGeckoElementBorrowed,
+    restyle_hint: nsRestyleHint,
+    change_hint: nsChangeHint,
+) {
     GeckoElement(element).note_explicit_hints(restyle_hint, change_hint);
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_TakeChangeHint(element: RawGeckoElementBorrowed,
-                                       was_restyled: *mut bool) -> u32
-{
+pub extern "C" fn Servo_TakeChangeHint(
+    element: RawGeckoElementBorrowed,
+    was_restyled: *mut bool
+) -> u32 {
     let was_restyled =  unsafe { was_restyled.as_mut().unwrap() };
     let element = GeckoElement(element);
 
     let damage = match element.mutate_data() {
         Some(mut data) => {
             *was_restyled = data.is_restyle();
 
             let damage = data.damage;
@@ -3127,53 +3149,41 @@ pub extern "C" fn Servo_TakeChangeHint(e
     debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
     // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
     // work as return values with the Linux 32-bit ABI at the moment because
     // they wrap the value in a struct, so for now just unwrap it.
     damage.as_change_hint().0
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed,
-                                     _raw_data: RawServoStyleSetBorrowed)
-                                     -> ServoStyleContextStrong
-{
+pub extern "C" fn Servo_ResolveStyle(
+    element: RawGeckoElementBorrowed,
+    _raw_data: RawServoStyleSetBorrowed,
+) -> ServoStyleContextStrong {
     let element = GeckoElement(element);
     debug!("Servo_ResolveStyle: {:?}", element);
     let data =
         element.borrow_data().expect("Resolving style on unstyled element");
 
     // TODO(emilio): Downgrade to debug assertions when close to release.
     assert!(data.has_styles(), "Resolving style on unstyled element");
     debug_assert!(element.has_current_styles(&*data),
                   "Resolving style on {:?} without current styles: {:?}", element, data);
     data.styles.primary().clone().into()
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_ResolveStyleAllowStale(element: RawGeckoElementBorrowed)
-                                               -> ServoStyleContextStrong
-{
-    let element = GeckoElement(element);
-    debug!("Servo_ResolveStyleAllowStale: {:?}", element);
-    let data =
-        element.borrow_data().expect("Resolving style on unstyled element");
-    assert!(data.has_styles(), "Resolving style on unstyled element");
-    data.styles.primary().clone().into()
-}
-
-#[no_mangle]
-pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
-                                           pseudo_type: CSSPseudoElementType,
-                                           rule_inclusion: StyleRuleInclusion,
-                                           snapshots: *const ServoElementSnapshotTable,
-                                           raw_data: RawServoStyleSetBorrowed,
-                                           ignore_existing_styles: bool)
-     -> ServoStyleContextStrong
-{
+pub extern "C" fn Servo_ResolveStyleLazily(
+    element: RawGeckoElementBorrowed,
+    pseudo_type: CSSPseudoElementType,
+    rule_inclusion: StyleRuleInclusion,
+    snapshots: *const ServoElementSnapshotTable,
+    raw_data: RawServoStyleSetBorrowed,
+    ignore_existing_styles: bool
+) -> ServoStyleContextStrong {
     debug_assert!(!snapshots.is_null());
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let element = GeckoElement(element);
     let doc_data = PerDocumentStyleData::from_ffi(raw_data);
     let data = doc_data.borrow();
     let rule_inclusion = RuleInclusion::from(rule_inclusion);
     let pseudo = PseudoElement::from_pseudo_type(pseudo_type);
@@ -3239,24 +3249,24 @@ pub extern "C" fn Servo_ResolveStyleLazi
     );
 
     finish(&styles, /* is_probe = */ false)
         .expect("We're not probing, so we should always get a style back")
         .into()
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_ReparentStyle(style_to_reparent: ServoStyleContextBorrowed,
-                                      parent_style: ServoStyleContextBorrowed,
-                                      parent_style_ignoring_first_line: ServoStyleContextBorrowed,
-                                      layout_parent_style: ServoStyleContextBorrowed,
-                                      element: RawGeckoElementBorrowedOrNull,
-                                      raw_data: RawServoStyleSetBorrowed)
-     -> ServoStyleContextStrong
-{
+pub extern "C" fn Servo_ReparentStyle(
+    style_to_reparent: ServoStyleContextBorrowed,
+    parent_style: ServoStyleContextBorrowed,
+    parent_style_ignoring_first_line: ServoStyleContextBorrowed,
+    layout_parent_style: ServoStyleContextBorrowed,
+    element: RawGeckoElementBorrowedOrNull,
+    raw_data: RawServoStyleSetBorrowed,
+) -> ServoStyleContextStrong {
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
     let inputs = CascadeInputs::new_from_style(style_to_reparent);
     let metrics = get_metrics_provider_for_product();
     let pseudo = style_to_reparent.pseudo();
     let element = element.map(GeckoElement);
 
@@ -3378,22 +3388,23 @@ impl<'a> Iterator for PrioritizedPropert
             return None
         }
         self.curr += 1;
         Some(&self.properties[self.sorted_property_indices[self.curr - 1].index])
     }
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeListBorrowed,
-                                                  element: RawGeckoElementBorrowed,
-                                                  style: ServoStyleContextBorrowed,
-                                                  raw_data: RawServoStyleSetBorrowed,
-                                                  computed_keyframes: RawGeckoComputedKeyframeValuesListBorrowedMut)
-{
+pub extern "C" fn Servo_GetComputedKeyframeValues(
+    keyframes: RawGeckoKeyframeListBorrowed,
+    element: RawGeckoElementBorrowed,
+    style: ServoStyleContextBorrowed,
+    raw_data: RawServoStyleSetBorrowed,
+    computed_keyframes: RawGeckoComputedKeyframeValuesListBorrowedMut
+) {
     use std::mem;
     use style::properties::LonghandIdSet;
 
     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
     let metrics = get_metrics_provider_for_product();
 
     let element = GeckoElement(element);
     let parent_element = element.inheritance_parent();
@@ -3489,21 +3500,23 @@ pub extern "C" fn Servo_GetComputedKeyfr
                 let id = value.id();
                 maybe_append_animation_value(id, Some(value));
             }
         }
     }
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_GetAnimationValues(declarations: RawServoDeclarationBlockBorrowed,
-                                           element: RawGeckoElementBorrowed,
-                                           style: ServoStyleContextBorrowed,
-                                           raw_data: RawServoStyleSetBorrowed,
-                                           animation_values: RawGeckoServoAnimationValueListBorrowedMut) {
+pub extern "C" fn Servo_GetAnimationValues(
+    declarations: RawServoDeclarationBlockBorrowed,
+    element: RawGeckoElementBorrowed,
+    style: ServoStyleContextBorrowed,