Merge m-c to fx-team. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 02 Oct 2014 13:16:26 -0400
changeset 208636 948719006fe8983a4a5cd7b2c96a98026dd5973f
parent 208635 279afba13f4c109111417b3987205d6fe0f0eaed (current diff)
parent 208472 b85c260821abced52c1ffb6fc45aeef42f0db9bc (diff)
child 208637 7b8254083c17ffaa5a70cb06687a04e830c6d5b6
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmerge
milestone35.0a1
Merge m-c to fx-team. a=merge
python/mozbuild/mozbuild/test/frontend/data/traversal-tier-fails-in-subdir/foo/moz.build
python/mozbuild/mozbuild/test/frontend/data/traversal-tier-fails-in-subdir/moz.build
python/mozbuild/mozbuild/test/frontend/data/traversal-tier-simple/bar/moz.build
python/mozbuild/mozbuild/test/frontend/data/traversal-tier-simple/baz/moz.build
python/mozbuild/mozbuild/test/frontend/data/traversal-tier-simple/foo/biz/moz.build
python/mozbuild/mozbuild/test/frontend/data/traversal-tier-simple/foo/moz.build
python/mozbuild/mozbuild/test/frontend/data/traversal-tier-simple/foo_static/moz.build
python/mozbuild/mozbuild/test/frontend/data/traversal-tier-simple/moz.build
--- a/b2g/app.mozbuild
+++ b/b2g/app.mozbuild
@@ -1,15 +1,17 @@
 # vim: set filetype=python:
 # 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/.
 
 if not CONFIG['LIBXUL_SDK']:
     include('/toolkit/toolkit.mozbuild')
 elif CONFIG['ENABLE_TESTS']:
-    add_tier_dir('testharness', 'testing/mochitest')
+    DIRS += ['/testing/mochitest']
 
 if CONFIG['MOZ_EXTENSIONS']:
-    add_tier_dir('app', 'extensions')
+    DIRS += ['/extensions']
 
-add_tier_dir('app', CONFIG['MOZ_BRANDING_DIRECTORY'])
-add_tier_dir('app', 'b2g')
+DIRS += [
+    '/%s' % CONFIG['MOZ_BRANDING_DIRECTORY'],
+    '/b2g',
+]
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "52f7b7099a47ab3904a70d9a295ab0ed927ad59e", 
+    "revision": "3e43be9b8c24802b40fdfbcf17895c4355e6d238", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/dev/app.mozbuild
+++ b/b2g/dev/app.mozbuild
@@ -2,24 +2,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/.
 
 if not CONFIG['LIBXUL_SDK']:
     include('/toolkit/toolkit.mozbuild')
 
 if CONFIG['MOZ_EXTENSIONS']:
-    add_tier_dir('app', 'extensions')
+    DIRS += ['/extensions']
 
-add_tier_dir('app', [CONFIG['MOZ_BRANDING_DIRECTORY']])
+DIRS += ['/%s' % CONFIG['MOZ_BRANDING_DIRECTORY']]
 
 if CONFIG['MOZ_WEBAPP_RUNTIME']:
-    add_tier_dir('app', 'webapprt')
-
-add_tier_dir('app', 'b2g/chrome')
-add_tier_dir('app', 'b2g/components')
+    DIRS += ['/webapprt']
 
-add_tier_dir('app', 'b2g/dev/app')
+DIRS += [
+    '/b2g/chrome',
+    '/b2g/components',
+    '/b2g/dev/app',
 
-# Never add tier dirs after browser because they apparently won't get
-# packaged properly on Mac.
-add_tier_dir('app', 'browser')
-
+    # Never add dirs after browser because they apparently won't get
+    # packaged properly on Mac.
+    '/browser',
+]
--- a/browser/app.mozbuild
+++ b/browser/app.mozbuild
@@ -2,19 +2,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/.
 
 if not CONFIG['LIBXUL_SDK']:
     include('/toolkit/toolkit.mozbuild')
 
 if CONFIG['MOZ_EXTENSIONS']:
-    add_tier_dir('app', 'extensions')
+    DIRS += ['/extensions']
 
-add_tier_dir('app', [CONFIG['MOZ_BRANDING_DIRECTORY']])
+DIRS += ['/%s' % CONFIG['MOZ_BRANDING_DIRECTORY']]
 
 if CONFIG['MOZ_WEBAPP_RUNTIME']:
-    add_tier_dir('app', 'webapprt')
+    DIRS += ['/webapprt']
 
-# Never add tier dirs after browser because they apparently won't get
+# Never add dirs after browser because they apparently won't get
 # packaged properly on Mac.
-add_tier_dir('app', 'browser')
+DIRS += ['/browser']
 
--- a/build/valgrind/cross-architecture.sup
+++ b/build/valgrind/cross-architecture.sup
@@ -68,40 +68,44 @@
 #  Other leaks  #
 #################
 
 {
    Bug 794369
    Memcheck:Leak
    fun:malloc
    fun:moz_xmalloc
+   ...
    fun:_ZN20mozJSComponentLoader10LoadModuleERN7mozilla12FileLocationE
    ...
 }
 {
    Bug 794370
    Memcheck:Leak
    fun:malloc
    fun:moz_xmalloc
+   ...
    fun:_ZN22nsComponentManagerImpl15RegisterFactoryERK4nsIDPKcS4_P10nsIFactory
    ...
 }
 {
    Bug 794372
    Memcheck:Leak
    fun:malloc
    fun:moz_xmalloc
+   ...
    fun:_ZN22nsComponentManagerImpl22RegisterCIDEntryLockedEPKN7mozilla6Module8CIDEntryEPNS_11KnownModuleE
    ...
 }
 {
    Bug 794374
    Memcheck:Leak
    fun:malloc
    fun:moz_xmalloc
+   ...
    fun:_ZN22nsComponentManagerImpl17ManifestComponentERNS_25ManifestProcessingContextEiPKPc
    ...
 }
 {
    Bug 1017112
    Memcheck:Leak
    fun:malloc
    ...
--- a/config/baseconfig.mk
+++ b/config/baseconfig.mk
@@ -96,17 +96,16 @@ else
   SDK_HEADERS \
   SDK_LIBRARY \
   SHARED_LIBRARY_LIBS \
   SHARED_LIBRARY_NAME \
   SIMPLE_PROGRAMS \
   SONAME \
   STATIC_LIBRARY_NAME \
   TEST_DIRS \
-  TIERS \
   TOOL_DIRS \
   XPCSHELL_TESTS \
   XPIDL_MODULE \
   $(NULL)
 
 _DEPRECATED_VARIABLES := \
   ANDROID_RESFILES \
   EXPORT_LIBRARY \
@@ -119,15 +118,16 @@ else
   MOCHITEST_CHROME_FILES \
   MOCHITEST_FILES \
   MOCHITEST_FILES_PARTS \
   MOCHITEST_METRO_FILES \
   MOCHITEST_ROBOCOP_FILES \
   SHORT_LIBNAME \
   TESTING_JS_MODULES \
   TESTING_JS_MODULE_DIR \
+  TIERS \
   $(NULL)
 
 # Freeze the values specified by moz.build to catch them if they fail.
 
 $(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES) $(_DEPRECATED_VARIABLES),$(eval $(var)_FROZEN := '$($(var))'))
 
 endif
--- a/config/makefiles/debugmake.mk
+++ b/config/makefiles/debugmake.mk
@@ -20,22 +20,16 @@ endef
 
 define shell_quote
 '$(subst $(CR),\$(CR),$(subst ','\'',$(1)))'
 endef
 
 echo-variable-%:
 	@echo $(call shell_quote,$($*))
 
-echo-tiers:
-	@echo $(TIERS)
-
-echo-tier-dirs:
-	@$(foreach tier,$(TIERS),echo '$(tier):'; echo '  dirs: $(tier_$(tier)_dirs)')
-
 echo-dirs:
 	@echo $(call shell_quote,$(DIRS))
 
 define print_var
 @printf '%20s = %s\n' $1 $(call shell_quote,$($1))
 
 endef
 
--- a/config/recurse.mk
+++ b/config/recurse.mk
@@ -25,22 +25,16 @@ endif
 #   make -C foo/bar
 #   make -C foo/baz
 #   make -C qux
 
 ifeq (.,$(DEPTH))
 
 include root.mk
 
-# Disable build status for mach in top directories without TIERS.
-# In practice this disables it when recursing under js/src, which confuses mach.
-ifndef TIERS
-BUILDSTATUS =
-endif
-
 # Main rules (export, compile, libs and tools) call recurse_* rules.
 # This wrapping is only really useful for build status.
 compile libs export tools::
 	$(call BUILDSTATUS,TIER_START $@)
 	+$(MAKE) recurse_$@
 	$(call BUILDSTATUS,TIER_FINISH $@)
 
 # Special rule that does install-manifests (cf. Makefile.in) + compile
@@ -65,19 +59,17 @@ CURRENT_TIER := $(subst recurse_,,$(CURR
 ifdef CURRENT_TIER
 ifeq (0,$(MAKELEVEL))
 export NO_RECURSE_MAKELEVEL=1
 else
 export NO_RECURSE_MAKELEVEL=$(word $(MAKELEVEL),2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
 endif
 endif
 
-# Get all directories traversed for all subtiers in the current tier, or use
-# directly the $(*_dirs) variables available in root.mk when there is no
-# TIERS (like for js/src).
+# Use the $(*_dirs) variables available in root.mk
 CURRENT_DIRS := $($(CURRENT_TIER)_dirs)
 
 # Need a list of compile targets because we can't use pattern rules:
 # https://savannah.gnu.org/bugs/index.php?42833
 .PHONY: $(compile_targets)
 $(compile_targets):
 	$(call SUBMAKE,$(@F),$(@D))
 
@@ -118,42 +110,30 @@ ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVE
 
 compile libs export tools::
 
 else
 #########################
 # Tier traversal handling
 #########################
 
-ifdef TIERS
-
-libs export tools::
-	$(call BUILDSTATUS,TIER_START $@)
-	$(foreach tier,$(TIERS), $(if $(filter-out libs_precompile tools_precompile,$@_$(tier)), \
-		$(foreach dir, $(tier_$(tier)_dirs), $(call TIER_DIR_SUBMAKE,$@,$(tier),$(dir),$@))))
-	$(call BUILDSTATUS,TIER_FINISH $@)
-
-else
-
 define CREATE_SUBTIER_TRAVERSAL_RULE
 .PHONY: $(1)
 
 $(1):: $$(SUBMAKEFILES)
 	$$(LOOP_OVER_DIRS)
 
 endef
 
 $(foreach subtier,export libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
 
 ifndef TOPLEVEL_BUILD
 libs:: target host
 endif
 
-endif # ifdef TIERS
-
 endif # ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL))
 
 endif # ifeq (.,$(DEPTH))
 
 recurse:
 	@$(RECURSED_COMMAND)
 	$(LOOP_OVER_DIRS)
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -643,25 +643,18 @@ MOZ_PROGRAM_LDFLAGS += $(MOZ_GLUE_PROGRA
 
 checkout:
 	$(MAKE) -C $(topsrcdir) -f client.mk checkout
 
 clean clobber realclean clobber_all::
 	-$(RM) $(ALL_TRASH)
 	-$(RM) -r $(ALL_TRASH_DIRS)
 
-ifdef TIERS
-clean clobber realclean clobber_all distclean::
-	$(foreach dir, \
-		$(foreach tier, $(TIERS), $(tier_$(tier)_dirs)), \
-		-$(call SUBMAKE,$@,$(dir)))
-else
 clean clobber realclean clobber_all distclean::
 	$(foreach dir,$(DIRS),-$(call SUBMAKE,$@,$(dir)))
-endif
 
 distclean::
 	-$(RM) -r $(ALL_TRASH_DIRS)
 	-$(RM) $(ALL_TRASH)  \
 	Makefile .HSancillary \
 	$(wildcard *.$(OBJ_SUFFIX)) $(wildcard *.ho) $(wildcard host_*.o*) \
 	$(wildcard *.$(LIB_SUFFIX)) $(wildcard *$(DLL_SUFFIX)) \
 	$(wildcard *.$(IMPORT_LIB_SUFFIX))
@@ -1631,17 +1624,16 @@ endif
 
 FREEZE_VARIABLES = \
   CSRCS \
   CPPSRCS \
   EXPORTS \
   DIRS \
   LIBRARY \
   MODULE \
-  TIERS \
   EXTRA_COMPONENTS \
   EXTRA_PP_COMPONENTS \
   $(NULL)
 
 $(foreach var,$(FREEZE_VARIABLES),$(eval $(var)_FROZEN := '$($(var))'))
 
 CHECK_FROZEN_VARIABLES = $(foreach var,$(FREEZE_VARIABLES), \
   $(if $(subst $($(var)_FROZEN),,'$($(var))'),$(error Makefile variable '$(var)' changed value after including rules.mk. Was $($(var)_FROZEN), now $($(var)).)))
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -641,16 +641,20 @@ public:
                          const nsAString& aLocalName,
                          ErrorResult& aError);
   bool HasAttribute(const nsAString& aName) const
   {
     return InternalGetExistingAttrNameFromQName(aName) != nullptr;
   }
   bool HasAttributeNS(const nsAString& aNamespaceURI,
                       const nsAString& aLocalName) const;
+  bool HasAttributes() const
+  {
+    return HasAttrs();
+  }
   Element* Closest(const nsAString& aSelector,
                    ErrorResult& aResult);
   bool Matches(const nsAString& aSelector,
                ErrorResult& aError);
   already_AddRefed<nsIHTMLCollection>
     GetElementsByTagName(const nsAString& aQualifiedName);
   already_AddRefed<nsIHTMLCollection>
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
@@ -1344,21 +1348,16 @@ inline mozilla::dom::Element* nsINode::A
 }
 
 inline const mozilla::dom::Element* nsINode::AsElement() const
 {
   MOZ_ASSERT(IsElement());
   return static_cast<const mozilla::dom::Element*>(this);
 }
 
-inline bool nsINode::HasAttributes() const
-{
-  return IsElement() && AsElement()->HasAttrs();
-}
-
 /**
  * Macros to implement Clone(). _elementName is the class for which to implement
  * Clone.
  */
 #define NS_IMPL_ELEMENT_CLONE(_elementName)                                 \
 nsresult                                                                    \
 _elementName::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const \
 {                                                                           \
@@ -1532,16 +1531,21 @@ NS_IMETHOD HasAttribute(const nsAString&
 }                                                                             \
 NS_IMETHOD HasAttributeNS(const nsAString& namespaceURI,                      \
                           const nsAString& localName,                         \
                           bool* _retval) MOZ_FINAL                            \
 {                                                                             \
   *_retval = Element::HasAttributeNS(namespaceURI, localName);                \
   return NS_OK;                                                               \
 }                                                                             \
+NS_IMETHOD HasAttributes(bool* _retval) MOZ_FINAL                             \
+{                                                                             \
+  *_retval = Element::HasAttributes();                                        \
+  return NS_OK;                                                               \
+}                                                                             \
 NS_IMETHOD GetAttributeNode(const nsAString& name,                            \
                             nsIDOMAttr** _retval) MOZ_FINAL                   \
 {                                                                             \
   NS_IF_ADDREF(*_retval = Element::GetAttributeNode(name));                   \
   return NS_OK;                                                               \
 }                                                                             \
 NS_IMETHOD SetAttributeNode(nsIDOMAttr* newAttr,                              \
                             nsIDOMAttr** _retval) MOZ_FINAL                   \
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -24,16 +24,17 @@
 #include "mozilla/GuardObjects.h"
 #include "mozilla/TimeStamp.h"
 #include "nsContentListDeclarations.h"
 #include "nsMathUtils.h"
 #include "nsTArrayForwardDeclare.h"
 #include "Units.h"
 #include "mozilla/dom/AutocompleteInfoBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/FloatingPoint.h"
 
 #if defined(XP_WIN)
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 #endif
 
 class imgICache;
 class imgIContainer;
@@ -181,16 +182,17 @@ public:
   static bool     IsImageSrcSetDisabled();
 
   static bool LookupBindingMember(JSContext* aCx, nsIContent *aContent,
                                   JS::Handle<jsid> aId,
                                   JS::MutableHandle<JSPropertyDescriptor> aDesc);
 
   /**
    * Returns the parent node of aChild crossing document boundaries.
+   * Uses the parent node in the composed document.
    */
   static nsINode* GetCrossDocParentNode(nsINode* aChild);
 
   /**
    * Do not ever pass null pointers to this method.  If one of your
    * nsIContents is null, you have to decide for yourself what
    * "IsDescendantOf" really means.
    *
@@ -211,17 +213,18 @@ public:
    * See the concept of "host-including inclusive ancestor" in the DOM
    * specification.
    */
   static bool ContentIsHostIncludingDescendantOf(
     const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
 
   /**
    * Similar to ContentIsDescendantOf except it crosses document boundaries,
-   * also crosses ShadowRoot boundaries from ShadowRoot to its host.
+   * this function uses ancestor/descendant relations in the composed document
+   * (see shadow DOM spec).
    */
   static bool ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
                                               nsINode* aPossibleAncestor);
 
   /*
    * This method fills the |aArray| with all ancestor nodes of |aNode|
    * including |aNode| at the zero index.
    */
@@ -2346,48 +2349,48 @@ public:
 
 } // namespace dom
 } // namespace mozilla
 
 #define NS_INTERFACE_MAP_ENTRY_TEAROFF(_interface, _allocator)                \
   if (aIID.Equals(NS_GET_IID(_interface))) {                                  \
     foundInterface = static_cast<_interface *>(_allocator);                   \
     if (!foundInterface) {                                                    \
-      *aInstancePtr = nullptr;                                                 \
+      *aInstancePtr = nullptr;                                                \
       return NS_ERROR_OUT_OF_MEMORY;                                          \
     }                                                                         \
   } else
 
 /*
  * In the following helper macros we exploit the fact that the result of a
  * series of additions will not be finite if any one of the operands in the
  * series is not finite.
  */
 #define NS_ENSURE_FINITE(f, rv)                                               \
-  if (!NS_finite(f)) {                                                        \
+  if (!mozilla::IsFinite(f)) {                                                \
     return (rv);                                                              \
   }
 
 #define NS_ENSURE_FINITE2(f1, f2, rv)                                         \
-  if (!NS_finite((f1)+(f2))) {                                                \
+  if (!mozilla::IsFinite((f1)+(f2))) {                                        \
     return (rv);                                                              \
   }
 
 #define NS_ENSURE_FINITE4(f1, f2, f3, f4, rv)                                 \
-  if (!NS_finite((f1)+(f2)+(f3)+(f4))) {                                      \
+  if (!mozilla::IsFinite((f1)+(f2)+(f3)+(f4))) {                              \
     return (rv);                                                              \
   }
 
 #define NS_ENSURE_FINITE5(f1, f2, f3, f4, f5, rv)                             \
-  if (!NS_finite((f1)+(f2)+(f3)+(f4)+(f5))) {                                 \
+  if (!mozilla::IsFinite((f1)+(f2)+(f3)+(f4)+(f5))) {                         \
     return (rv);                                                              \
   }
 
 #define NS_ENSURE_FINITE6(f1, f2, f3, f4, f5, f6, rv)                         \
-  if (!NS_finite((f1)+(f2)+(f3)+(f4)+(f5)+(f6))) {                            \
+  if (!mozilla::IsFinite((f1)+(f2)+(f3)+(f4)+(f5)+(f6))) {                    \
     return (rv);                                                              \
   }
 
 // Deletes a linked list iteratively to avoid blowing up the stack (bug 460444).
 #define NS_CONTENT_DELETE_LIST_MEMBER(type_, ptr_, member_)                   \
   {                                                                           \
     type_ *cur = (ptr_)->member_;                                             \
     (ptr_)->member_ = nullptr;                                                 \
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -101,16 +101,17 @@ struct CustomElementDefinition;
 class DocumentFragment;
 class DocumentType;
 class DOMImplementation;
 class DOMStringList;
 class Element;
 struct ElementRegistrationOptions;
 class Event;
 class EventTarget;
+class FontFaceSet;
 class FrameRequestCallback;
 class ImportManager;
 class OverfillCallback;
 class HTMLBodyElement;
 struct LifecycleCallbackArgs;
 class Link;
 class GlobalObject;
 class NodeFilter;
@@ -2385,16 +2386,21 @@ public:
 
     nsWeakPtr weakNode = do_GetWeakReference(node);
 
     if (weakNode) {
       mBlockedTrackingNodes.AppendElement(weakNode);
     }
   }
 
+  // FontFaceSource
+  mozilla::dom::FontFaceSet* GetFonts(mozilla::ErrorResult& aRv);
+
+  bool DidFireDOMContentLoaded() const { return mDidFireDOMContentLoaded; }
+
 private:
   uint64_t mWarnedAbout;
   SelectorCache mSelectorCache;
 
 protected:
   ~nsIDocument();
   nsPropertyTable* GetExtraPropertyTable(uint16_t aCategory);
 
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -1635,18 +1635,17 @@ public:
     const nsString& localName = LocalName();
     if (localName.IsVoid()) {
       aLocalName.SetNull();
     } else {
       aLocalName.SetStringBuffer(nsStringBuffer::FromString(localName),
                                  localName.Length());
     }
   }
-  // HasAttributes is defined inline in Element.h.
-  bool HasAttributes() const;
+
   nsDOMAttributeMap* GetAttributes();
   void SetUserData(JSContext* aCx, const nsAString& aKey,
                    JS::Handle<JS::Value> aData,
                    JS::MutableHandle<JS::Value> aRetval,
                    mozilla::ErrorResult& aError);
   void GetUserData(JSContext* aCx, const nsAString& aKey,
                    JS::MutableHandle<JS::Value> aRetval,
                    mozilla::ErrorResult& aError);
@@ -1989,22 +1988,16 @@ ToCanonicalSupports(nsINode* aPointer)
     nsINode::GetPrefix(aPrefix); \
     return NS_OK; \
   } \
   NS_IMETHOD GetLocalName(nsAString& aLocalName) __VA_ARGS__ \
   { \
     aLocalName = nsINode::LocalName(); \
     return NS_OK; \
   } \
-  using nsINode::HasAttributes; \
-  NS_IMETHOD HasAttributes(bool* aResult) __VA_ARGS__ \
-  { \
-    *aResult = nsINode::HasAttributes(); \
-    return NS_OK; \
-  } \
   NS_IMETHOD GetDOMBaseURI(nsAString& aBaseURI) __VA_ARGS__ \
   { \
     nsINode::GetBaseURI(aBaseURI); \
     return NS_OK; \
   } \
   NS_IMETHOD CompareDocumentPosition(nsIDOMNode* aOther, uint16_t* aResult) __VA_ARGS__ \
   { \
     return nsINode::CompareDocumentPosition(aOther, aResult); \
--- a/content/base/src/ChildIterator.h
+++ b/content/base/src/ChildIterator.h
@@ -117,22 +117,24 @@ protected:
   uint32_t mIndexInInserted;
 
   // A flag to let us know that we haven't started iterating yet.
   bool mIsFirst;
 };
 
 // Iterates over the flattened children of a node, which accounts for anonymous
 // children and nodes moved by insertion points. If a node has anonymous
-// children, those are iterated over.
+// children, those are iterated over.  The iterator can be initialized to start
+// at the end by providing false for aStartAtBeginning in order to start
+// iterating in reverse from the last child.
 class FlattenedChildIterator : public ExplicitChildIterator
 {
 public:
-  explicit FlattenedChildIterator(nsIContent* aParent)
-    : ExplicitChildIterator(aParent), mXBLInvolved(false)
+  explicit FlattenedChildIterator(nsIContent* aParent, bool aStartAtBeginning = true)
+    : ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
   {
     Init(false);
   }
 
   FlattenedChildIterator(FlattenedChildIterator&& aOther)
     : ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
 
   FlattenedChildIterator(const FlattenedChildIterator& aOther)
@@ -140,40 +142,43 @@ public:
 
   bool XBLInvolved() { return mXBLInvolved; }
 
 protected:
   /**
    * This constructor is a hack to help AllChildrenIterator which sometimes
    * doesn't want to consider XBL.
    */
-  FlattenedChildIterator(nsIContent* aParent, bool aIgnoreXBL)
-    : ExplicitChildIterator(aParent), mXBLInvolved(false)
+  FlattenedChildIterator(nsIContent* aParent, uint32_t aFlags, bool aStartAtBeginning = true)
+    : ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
   {
-    Init(aIgnoreXBL);
+    bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
+    Init(ignoreXBL);
   }
 
   void Init(bool aIgnoreXBL);
 
   // For certain optimizations, nsCSSFrameConstructor needs to know if the
   // child list of the element that we're iterating matches its .childNodes.
   bool mXBLInvolved;
 };
 
 /**
  * AllChildrenIterator returns the children of a element including before /
  * after content and optionally XBL children.  It assumes that no mutation of
  * the DOM or frame tree takes place during iteration, and will break horribly
- * if that is not true.
+ * if that is not true.  The iterator can be initialized to start at the end by
+ * providing false for aStartAtBeginning in order to start iterating in reverse
+ * from the last child.
  */
 class AllChildrenIterator : private FlattenedChildIterator
 {
 public:
-  AllChildrenIterator(nsIContent* aNode, uint32_t aFlags) :
-    FlattenedChildIterator(aNode, (aFlags & nsIContent::eAllButXBL)),
+  AllChildrenIterator(nsIContent* aNode, uint32_t aFlags, bool aStartAtBeginning = true) :
+    FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
     mOriginalContent(aNode), mFlags(aFlags),
     mPhase(eNeedBeforeKid) {}
 
   AllChildrenIterator(AllChildrenIterator&& aOther)
     : FlattenedChildIterator(Move(aOther)),
       mOriginalContent(aOther.mOriginalContent),
       mAnonKids(Move(aOther.mAnonKids)), mFlags(aOther.mFlags),
       mPhase(aOther.mPhase)
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -2934,31 +2934,36 @@ void
 Element::MozRequestPointerLock()
 {
   OwnerDoc()->RequestPointerLock(this);
 }
 
 void
 Element::GetAnimationPlayers(nsTArray<nsRefPtr<AnimationPlayer> >& aPlayers)
 {
+  nsIDocument* doc = GetComposedDoc();
+  if (doc) {
+    doc->FlushPendingNotifications(Flush_Style);
+  }
+
   nsIAtom* properties[] = { nsGkAtoms::transitionsProperty,
                             nsGkAtoms::animationsProperty };
   for (size_t propIdx = 0; propIdx < MOZ_ARRAY_LENGTH(properties);
        propIdx++) {
     AnimationPlayerCollection* collection =
       static_cast<AnimationPlayerCollection*>(
         GetProperty(properties[propIdx]));
     if (!collection) {
       continue;
     }
     for (size_t playerIdx = 0;
          playerIdx < collection->mPlayers.Length();
          playerIdx++) {
       AnimationPlayer* player = collection->mPlayers[playerIdx];
-      if (player->IsCurrent()) {
+      if (player->HasCurrentSource() || player->HasInEffectSource()) {
         aPlayers.AppendElement(player);
       }
     }
   }
 }
 
 NS_IMETHODIMP
 Element::GetInnerHTML(nsAString& aInnerHTML)
--- a/content/base/src/nsCSPUtils.cpp
+++ b/content/base/src/nsCSPUtils.cpp
@@ -293,62 +293,62 @@ nsCSPHostSrc::permits(nsIURI* aUri, cons
 #ifdef PR_LOGGING
   {
     nsAutoCString spec;
     aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPHostSrc::permits, aUri: %s", spec.get()));
   }
 #endif
 
-  // If the host is defined as a "*", and:
-  //  a) no scheme, and
-  //  b) no port is defined, allow the load.
-  // http://www.w3.org/TR/CSP11/#matching
-  if (mHost.EqualsASCII("*") &&
-      mScheme.IsEmpty() &&
-      mPort.IsEmpty()) {
-    return true;
-  }
+  // we are following the enforcement rules from the spec, see:
+  // http://www.w3.org/TR/CSP11/#match-source-expression
 
-  // Check if the scheme matches.
+  // 4.3) scheme matching: Check if the scheme matches.
   nsAutoCString scheme;
   nsresult rv = aUri->GetScheme(scheme);
   NS_ENSURE_SUCCESS(rv, false);
-  if (!mScheme.EqualsASCII(scheme.get())) {
+  if (!mScheme.IsEmpty() &&
+      !mScheme.EqualsASCII(scheme.get())) {
     return false;
   }
 
   // The host in nsCSpHostSrc should never be empty. In case we are enforcing
   // just a specific scheme, the parser should generate a nsCSPSchemeSource.
   NS_ASSERTION((!mHost.IsEmpty()), "host can not be the empty string");
 
-  // Extract the host part from aUri.
+  // 2) host matching: Enforce a single *
+  if (mHost.EqualsASCII("*")) {
+    return true;
+  }
+
+  // Before we can check if the host matches, we have to
+  // extract the host part from aUri.
   nsAutoCString uriHost;
   rv = aUri->GetHost(uriHost);
   NS_ENSURE_SUCCESS(rv, false);
 
-  // Check it the allowed host starts with a wilcard.
+  // 4.5) host matching: Check if the allowed host starts with a wilcard.
   if (mHost.First() == '*') {
     NS_ASSERTION(mHost[1] == '.', "Second character needs to be '.' whenever host starts with '*'");
 
     // Eliminate leading "*", but keeping the FULL STOP (.) thereafter before checking
-    // if the remaining characters match: see http://www.w3.org/TR/CSP11/#matching
+    // if the remaining characters match
     nsString wildCardHost = mHost;
     wildCardHost = Substring(wildCardHost, 1, wildCardHost.Length() - 1);
     if (!StringEndsWith(NS_ConvertUTF8toUTF16(uriHost), wildCardHost)) {
       return false;
     }
   }
-  // Check if hosts match.
+  // 4.6) host matching: Check if hosts match.
   else if (!mHost.Equals(NS_ConvertUTF8toUTF16(uriHost))) {
     return false;
   }
 
-  // If there is a path, we have to enforce path-level matching,
-  // unless the channel got redirected, see:
+  // 4.9) Path matching: If there is a path, we have to enforce
+  // path-level matching, unless the channel got redirected, see:
   // http://www.w3.org/TR/CSP11/#source-list-paths-and-redirects
   if (!aWasRedirected && !mPath.IsEmpty()) {
     // cloning uri so we can ignore the ref
     nsCOMPtr<nsIURI> uri;
     aUri->CloneIgnoringRef(getter_AddRefs(uri));
 
     nsAutoCString uriPath;
     rv = uri->GetPath(uriPath);
@@ -365,35 +365,36 @@ nsCSPHostSrc::permits(nsIURI* aUri, cons
     // check if the loading resource matches that whitelisted file.
     else {
       if (!mPath.Equals(NS_ConvertUTF8toUTF16(uriPath))) {
         return false;
       }
     }
   }
 
-  // If port uses wildcard, allow the load.
+  // 4.8) Port matching: If port uses wildcard, allow the load.
   if (mPort.EqualsASCII("*")) {
     return true;
   }
 
-  // Check if ports match
+  // Before we can check if the port matches, we have to
+  // query the port from aUri.
   int32_t uriPort;
   rv = aUri->GetPort(&uriPort);
   NS_ENSURE_SUCCESS(rv, false);
   uriPort = (uriPort > 0) ? uriPort : NS_GetDefaultPort(scheme.get());
 
-  // If mPort is empty, we have to compare default ports.
+  // 4.7) Default port matching: If mPort is empty, we have to compare default ports.
   if (mPort.IsEmpty()) {
     int32_t port = NS_GetDefaultPort(NS_ConvertUTF16toUTF8(mScheme).get());
     if (port != uriPort) {
       return false;
     }
   }
-  // Otherwise compare the ports
+  // 4.7) Port matching: Compare the ports.
   else {
     nsString portStr;
     portStr.AppendInt(uriPort);
     if (!mPort.Equals(portStr)) {
       return false;
     }
   }
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -2020,16 +2020,20 @@ nsContentUtils::LookupBindingMember(JSCo
 
 // static
 nsINode*
 nsContentUtils::GetCrossDocParentNode(nsINode* aChild)
 {
   NS_PRECONDITION(aChild, "The child is null!");
 
   nsINode* parent = aChild->GetParentNode();
+  if (parent && parent->IsContent() && aChild->IsContent()) {
+    parent = aChild->AsContent()->GetFlattenedTreeParent();
+  }
+
   if (parent || !aChild->IsNodeOfType(nsINode::eDOCUMENT))
     return parent;
 
   nsIDocument* doc = static_cast<nsIDocument*>(aChild);
   nsIDocument* parentDoc = doc->GetParentDocument();
   return parentDoc ? parentDoc->FindContentForSubDocument(doc) : nullptr;
 }
 
@@ -2078,22 +2082,16 @@ nsContentUtils::ContentIsCrossDocDescend
 {
   NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
   NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
 
   do {
     if (aPossibleDescendant == aPossibleAncestor)
       return true;
 
-    // Step over shadow root to the host node.
-    ShadowRoot* shadowRoot = ShadowRoot::FromNode(aPossibleDescendant);
-    if (shadowRoot) {
-      aPossibleDescendant = shadowRoot->GetHost();
-    }
-
     aPossibleDescendant = GetCrossDocParentNode(aPossibleDescendant);
   } while (aPossibleDescendant);
 
   return false;
 }
 
 
 // static
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -218,16 +218,17 @@
 #include "nsIDocumentEncoder.h"
 #include "nsIDocumentActivity.h"
 #include "nsIStructuredCloneContainer.h"
 #include "nsIMutableArray.h"
 #include "nsContentPermissionHelper.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "nsWindowMemoryReporter.h"
 #include "nsLocation.h"
+#include "mozilla/dom/FontFaceSet.h"
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 #include "mozilla/MediaManager.h"
 #endif // MOZ_MEDIA_NAVIGATOR
 #ifdef MOZ_WEBRTC
 #include "IPeerConnection.h"
 #endif // MOZ_WEBRTC
 
@@ -12410,8 +12411,25 @@ nsAutoSyncOperation::nsAutoSyncOperation
 nsAutoSyncOperation::~nsAutoSyncOperation()
 {
   for (int32_t i = 0; i < mDocuments.Count(); ++i) {
     mDocuments[i]->SetIsInSyncOperation(false);
   }
   nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel);
 }
 
+FontFaceSet*
+nsIDocument::GetFonts(ErrorResult& aRv)
+{
+  nsIPresShell* shell = GetShell();
+  if (!shell) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsPresContext* presContext = shell->GetPresContext();
+  if (!presContext) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  return presContext->Fonts();
+}
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -770,16 +770,19 @@ GK_ATOM(oninstall, "oninstall")
 GK_ATOM(oninvalid, "oninvalid")
 GK_ATOM(onkeydown, "onkeydown")
 GK_ATOM(onkeypress, "onkeypress")
 GK_ATOM(onkeyup, "onkeyup")
 GK_ATOM(onlanguagechange, "onlanguagechange")
 GK_ATOM(onlevelchange, "onlevelchange")
 GK_ATOM(onLoad, "onLoad")
 GK_ATOM(onload, "onload")
+GK_ATOM(onloading, "onloading")
+GK_ATOM(onloadingdone, "onloadingdone")
+GK_ATOM(onloadingerror, "onloadingerror")
 GK_ATOM(onpopstate, "onpopstate")
 GK_ATOM(only, "only")               // this one is not an event
 GK_ATOM(onmessage, "onmessage")
 GK_ATOM(onmousedown, "onmousedown")
 GK_ATOM(onmouseenter, "onmouseenter")
 GK_ATOM(onmouseleave, "onmouseleave")
 GK_ATOM(onmousemove, "onmousemove")
 GK_ATOM(onmouseout, "onmouseout")
--- a/content/base/test/TestCSPParser.cpp
+++ b/content/base/test/TestCSPParser.cpp
@@ -371,16 +371,18 @@ nsresult TestIgnorePaths() {
 nsresult TestSimplePolicies() {
 
   static const PolicyTest policies[] =
   {
     { "default-src *",
       "default-src *" },
     { "default-src https:",
       "default-src https:" },
+    { "default-src https://*",
+      "default-src https://*" },
     { "default-src *:*",
       "default-src http://*:*" },
     { "default-src *:80",
       "default-src http://*:80" },
     { "default-src http://*:80",
       "default-src http://*:80" },
     { "default-src javascript:",
       "default-src javascript:" },
--- a/content/base/test/csp/test_csp_path_matching.html
+++ b/content/base/test/csp/test_csp_path_matching.html
@@ -19,16 +19,17 @@ SimpleTest.waitForExplicitFinish();
 /* Description of the test:
  * We are loading the following url (including a fragment portion):
  * http://test1.example.com/tests/content/base/test/csp/file_csp_path_matching.js#foo
  * using different policies and verify that the applied policy is accurately enforced.
  */
 
 var policies = [
   ["allowed", "*"],
+  ["allowed", "http://*"], // test for bug 1075230, enforcing scheme and wildcard
   ["allowed", "test1.example.com"],
   ["allowed", "test1.example.com/"],
   ["allowed", "test1.example.com/tests/content/base/test/csp/"],
   ["allowed", "test1.example.com/tests/content/base/test/csp/file_csp_path_matching.js"],
 
   ["allowed", "test1.example.com?foo=val"],
   ["allowed", "test1.example.com/?foo=val"],
   ["allowed", "test1.example.com/tests/content/base/test/csp/?foo=val"],
--- a/content/html/content/test/test_video_wakelock.html
+++ b/content/html/content/test/test_video_wakelock.html
@@ -37,17 +37,17 @@ function testVideoPlayPause() {
     startDate = new Date();
 
     // The next step is to unlock the resource.
     lockState_cpu = false;
     lockState_screen = false;
     video.pause();
   });
 
-  navigator.mozPower.addWakeLockListener(function testVideoPlayPauseListener(topic, state) {
+  function testVideoPlayPauseListener(topic, state) {
     var locked = state == "locked-foreground" ||
                  state == "locked-background";
 
     if (topic == "cpu") {
       is(locked, lockState_cpu, "Video element locked the cpu - paused");
       count_cpu++;
     } else if (topic == "screen") {
       is(locked, lockState_screen, "Video element locked the screen - paused");
@@ -57,18 +57,19 @@ function testVideoPlayPause() {
     if (count_cpu == 2 && count_screen == 2) {
       var diffDate = (new Date() - startDate);
       ok(diffDate > 200, "There was at least 200 milliseconds between the stop and the wakelock release");
 
       content.removeChild(video);
       navigator.mozPower.removeWakeLockListener(testVideoPlayPauseListener);
       runTests();
     }
-  });
+  }
 
+  navigator.mozPower.addWakeLockListener(testVideoPlayPauseListener);
   video.play();
 }
 
 function testVideoPlay() {
   var lockState_cpu = true;
   var lockState_screen = true;
   var count_cpu = 0;
   var count_screen = 0;
@@ -79,17 +80,17 @@ function testVideoPlay() {
   video.src = "wakelock.ogv";
   content.appendChild(video);
 
   var startDate;
   video.addEventListener('progress', function() {
     startDate = new Date();
   });
 
-  navigator.mozPower.addWakeLockListener(function testVideoPlayListener(topic, state) {
+  function testVideoPlayListener(topic, state) {
     var locked = state == "locked-foreground" ||
                  state == "locked-background";
 
     if (topic == "cpu") {
       is(locked, lockState_cpu, "Video element locked the cpu - paused");
       count_cpu++;
     } else if (topic == "screen") {
       is(locked, lockState_screen, "Video element locked the screen - paused");
@@ -103,33 +104,37 @@ function testVideoPlay() {
     } else if (count_cpu == 2 && count_screen == 2) {
       var diffDate = (new Date() - startDate);
       ok(diffDate > 200, "There was at least milliseconds between the stop and the wakelock release");
 
       content.removeChild(video);
       navigator.mozPower.removeWakeLockListener(testVideoPlayListener);
       runTests();
     }
-  });
+  }
 
+  navigator.mozPower.addWakeLockListener(testVideoPlayListener);
   video.play();
 }
 
 var tests = [ testVideoPlayPause, testVideoPlay ];
 function runTests() {
   if (!tests.length) {
     SimpleTest.finish();
     return;
   }
 
   var test =  tests.pop();
   test();
 };
 
-SpecialPowers.addPermission("power", true, document);
-SpecialPowers.pushPrefEnv({"set": [["media.wakelock_timeout", 500]]}, runTests);
+SpecialPowers.pushPermissions(
+  [{'type': 'power', 'allow': true, 'context': document}],
+  function() {
+    SpecialPowers.pushPrefEnv({"set": [["media.wakelock_timeout", 500]]}, runTests);
+  });
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/media/TrackUnionStream.h
+++ b/content/media/TrackUnionStream.h
@@ -243,21 +243,20 @@ protected:
     MediaStream* source = map->mInputPort->GetSource();
 
     GraphTime next;
     *aOutputTrackFinished = false;
     for (GraphTime t = aFrom; t < aTo; t = next) {
       MediaInputPort::InputInterval interval = map->mInputPort->GetNextInputInterval(t);
       interval.mEnd = std::min(interval.mEnd, aTo);
       StreamTime inputEnd = source->GraphTimeToStreamTime(interval.mEnd);
-      TrackTicks inputTrackEndPoint = TRACK_TICKS_MAX;
+      TrackTicks inputTrackEndPoint = aInputTrack->GetEnd();
 
       if (aInputTrack->IsEnded() &&
           aInputTrack->GetEndTimeRoundDown() <= inputEnd) {
-        inputTrackEndPoint = aInputTrack->GetEnd();
         *aOutputTrackFinished = true;
       }
 
       if (interval.mStart >= interval.mEnd)
         break;
       next = interval.mEnd;
 
       // Ticks >= startTicks and < endTicks are in the interval
@@ -320,35 +319,46 @@ protected:
         //   <= TimeToTicksRoundDown(rate, originalInputStart) - 1 + TimeToTicksRoundDown(rate, inputEnd) - TimeToTicksRoundDown(rate, originalInputStart) + 1
         //   = TimeToTicksRoundDown(rate, inputEnd)
         //   <= inputEnd/rate
         // (now using the fact that inputEnd <= track->GetEndTimeRoundDown() for a non-ended track)
         //   <= TicksToTimeRoundDown(rate, aInputTrack->GetSegment()->GetDuration())/rate
         //   <= rate*aInputTrack->GetSegment()->GetDuration()/rate
         //   = aInputTrack->GetSegment()->GetDuration()
         // as required.
+        // Note that while the above proof appears to be generally right, if we are suffering
+        // from a lot of underrun, then in rare cases inputStartTicks >> inputTrackEndPoint.
+        // As such, we still need to verify the sanity of property #2 and use null data as
+        // appropriate.
 
         if (inputStartTicks < 0) {
           // Data before the start of the track is just null.
           // We have to add a small amount of delay to ensure that there is
           // always a sample available if we see an interval that contains a
           // tick boundary on the output stream's timeline but does not contain
           // a tick boundary on the input stream's timeline. 1 tick delay is
           // necessary and sufficient.
           segment->AppendNullData(-inputStartTicks);
           inputStartTicks = 0;
         }
         if (inputEndTicks > inputStartTicks) {
-          segment->AppendSlice(*aInputTrack->GetSegment(),
-                               std::min(inputTrackEndPoint, inputStartTicks),
-                               std::min(inputTrackEndPoint, inputEndTicks));
+          if (inputEndTicks <= inputTrackEndPoint) {
+            segment->AppendSlice(*aInputTrack->GetSegment(), inputStartTicks, inputEndTicks);
+            STREAM_LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of input data to track %d",
+                       this, ticks, outputTrack->GetID()));
+          } else {
+            if (inputStartTicks < inputTrackEndPoint) {
+              segment->AppendSlice(*aInputTrack->GetSegment(), inputStartTicks, inputTrackEndPoint);
+              ticks -= inputTrackEndPoint - inputStartTicks;
+            }
+            segment->AppendNullData(ticks);
+            STREAM_LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of input data and %lld of null data to track %d",
+                       this, inputTrackEndPoint - inputStartTicks, ticks, outputTrack->GetID()));
+          }
         }
-        STREAM_LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of input data to track %d",
-                   this, (long long)(std::min(inputTrackEndPoint, inputEndTicks) - std::min(inputTrackEndPoint, inputStartTicks)),
-                   outputTrack->GetID()));
       }
       ApplyTrackDisabling(outputTrack->GetID(), segment);
       for (uint32_t j = 0; j < mListeners.Length(); ++j) {
         MediaStreamListener* l = mListeners[j];
         l->NotifyQueuedTrackChanges(Graph(), outputTrack->GetID(),
                                     outputTrack->GetRate(), startTicks, 0,
                                     *segment);
       }
--- a/content/media/gmp/GMPSharedMemManager.cpp
+++ b/content/media/gmp/GMPSharedMemManager.cpp
@@ -35,29 +35,43 @@ GMPSharedMemManager::MgrAllocShmem(GMPSh
       return true;
     }
   }
 
   // Didn't find a buffer free with enough space; allocate one
   size_t pagesize = ipc::SharedMemory::SystemPageSize();
   aSize = (aSize + (pagesize-1)) & ~(pagesize-1); // round up to page size
   bool retval = Alloc(aSize, aType, aMem);
+  // The allocator (or NeedsShmem call) should never return less than we ask for...
+  MOZ_ASSERT(aMem->Size<uint8_t>() >= aSize);
   if (retval) {
     mData->mGmpAllocated[aClass]++;
   }
   return retval;
 }
 
 bool
 GMPSharedMemManager::MgrDeallocShmem(GMPSharedMem::GMPMemoryClasses aClass, ipc::Shmem& aMem)
 {
   mData->CheckThread();
 
   size_t size = aMem.Size<uint8_t>();
   size_t total = 0;
+
+  // XXX Bug NNNNNNN Until we put better guards on ipc::shmem, verify we
+  // weren't fed an shmem we already had.
+  for (uint32_t i = 0; i < GetGmpFreelist(aClass).Length(); i++) {
+    if (NS_WARN_IF(aMem == GetGmpFreelist(aClass)[i])) {
+      // Safest to crash in this case; should never happen in normal
+      // operation.
+      MOZ_CRASH("Deallocating Shmem we already have in our cache!");
+      //return true;
+    }
+  }
+
   // XXX This works; there are better pool algorithms.  We need to avoid
   // "falling off a cliff" with too low a number
   if (GetGmpFreelist(aClass).Length() > 10) {
     Dealloc(GetGmpFreelist(aClass)[0]);
     GetGmpFreelist(aClass).RemoveElementAt(0);
     // The allocation numbers will be fubar on the Child!
     mData->mGmpAllocated[aClass]--;
   }
--- a/content/media/gmp/GMPVideoDecoderParent.cpp
+++ b/content/media/gmp/GMPVideoDecoderParent.cpp
@@ -223,16 +223,20 @@ GMPVideoDecoderParent::ActorDestroy(Acto
 
 bool
 GMPVideoDecoderParent::RecvDecoded(const GMPVideoi420FrameData& aDecodedFrame)
 {
   if (!mCallback) {
     return false;
   }
 
+  if (!GMPVideoi420FrameImpl::CheckFrameData(aDecodedFrame)) {
+    LOG(PR_LOG_ERROR, ("%s: Decoded frame corrupt, ignoring", __FUNCTION__));
+    return false;
+  }
   auto f = new GMPVideoi420FrameImpl(aDecodedFrame, &mVideoHost);
 
   // Ignore any return code. It is OK for this to fail without killing the process.
   mCallback->Decoded(f);
 
   return true;
 }
 
--- a/content/media/gmp/GMPVideoi420FrameImpl.cpp
+++ b/content/media/gmp/GMPVideoi420FrameImpl.cpp
@@ -58,16 +58,41 @@ GMPVideoi420FrameImpl::GetFrameFormat()
 }
 
 void
 GMPVideoi420FrameImpl::Destroy()
 {
   delete this;
 }
 
+/* static */ bool
+GMPVideoi420FrameImpl::CheckFrameData(const GMPVideoi420FrameData& aFrameData)
+{
+  // We may be passed the "wrong" shmem (one smaller than the actual size).
+  // This implies a bug or serious error on the child size.  Ignore this frame if so.
+  // Note: Size() greater than expected is also an error, but with no negative consequences
+  int32_t half_width = (aFrameData.mWidth() + 1) / 2;
+  if ((aFrameData.mYPlane().mStride() <= 0) || (aFrameData.mYPlane().mSize() <= 0) ||
+      (aFrameData.mUPlane().mStride() <= 0) || (aFrameData.mUPlane().mSize() <= 0) ||
+      (aFrameData.mVPlane().mStride() <= 0) || (aFrameData.mVPlane().mSize() <= 0) ||
+      (aFrameData.mYPlane().mSize() > (int32_t) aFrameData.mYPlane().mBuffer().Size<uint8_t>()) ||
+      (aFrameData.mUPlane().mSize() > (int32_t) aFrameData.mUPlane().mBuffer().Size<uint8_t>()) ||
+      (aFrameData.mVPlane().mSize() > (int32_t) aFrameData.mVPlane().mBuffer().Size<uint8_t>()) ||
+      (aFrameData.mYPlane().mStride() < aFrameData.mWidth()) ||
+      (aFrameData.mUPlane().mStride() < half_width) ||
+      (aFrameData.mVPlane().mStride() < half_width) ||
+      (aFrameData.mYPlane().mSize() < aFrameData.mYPlane().mStride() * aFrameData.mHeight()) ||
+      (aFrameData.mUPlane().mSize() < aFrameData.mUPlane().mStride() * ((aFrameData.mHeight()+1)/2)) ||
+      (aFrameData.mVPlane().mSize() < aFrameData.mVPlane().mStride() * ((aFrameData.mHeight()+1)/2)))
+  {
+    return false;
+  }
+  return true;
+}
+
 bool
 GMPVideoi420FrameImpl::CheckDimensions(int32_t aWidth, int32_t aHeight,
                                        int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
 {
   int32_t half_width = (aWidth + 1) / 2;
   if (aWidth < 1 || aHeight < 1 || aStride_y < aWidth ||
                                    aStride_u < half_width ||
                                    aStride_v < half_width) {
--- a/content/media/gmp/GMPVideoi420FrameImpl.h
+++ b/content/media/gmp/GMPVideoi420FrameImpl.h
@@ -19,16 +19,18 @@ class GMPVideoi420FrameData;
 class GMPVideoi420FrameImpl : public GMPVideoi420Frame
 {
   friend struct IPC::ParamTraits<mozilla::gmp::GMPVideoi420FrameImpl>;
 public:
   explicit GMPVideoi420FrameImpl(GMPVideoHostImpl* aHost);
   GMPVideoi420FrameImpl(const GMPVideoi420FrameData& aFrameData, GMPVideoHostImpl* aHost);
   virtual ~GMPVideoi420FrameImpl();
 
+  static bool CheckFrameData(const GMPVideoi420FrameData& aFrameData);
+
   bool InitFrameData(GMPVideoi420FrameData& aFrameData);
   const GMPPlaneImpl* GetPlane(GMPPlaneType aType) const;
   GMPPlaneImpl* GetPlane(GMPPlaneType aType);
 
   // GMPVideoFrame
   virtual GMPVideoFrameFormat GetFrameFormat() MOZ_OVERRIDE;
   virtual void Destroy() MOZ_OVERRIDE;
 
--- a/content/media/webaudio/OscillatorNode.cpp
+++ b/content/media/webaudio/OscillatorNode.cpp
@@ -368,46 +368,54 @@ public:
   void ComputeCustom(float* aOutput,
                      TrackTicks ticks,
                      uint32_t aStart,
                      uint32_t aEnd)
   {
     MOZ_ASSERT(mPeriodicWave, "No custom waveform data");
 
     uint32_t periodicWaveSize = mPeriodicWave->periodicWaveSize();
+    // Mask to wrap wave data indices into the range [0,periodicWaveSize).
+    uint32_t indexMask = periodicWaveSize - 1;
+    MOZ_ASSERT(periodicWaveSize && (periodicWaveSize & indexMask) == 0,
+               "periodicWaveSize must be power of 2");
     float* higherWaveData = nullptr;
     float* lowerWaveData = nullptr;
     float tableInterpolationFactor;
     // Phase increment at frequency of 1 Hz.
     // mPhase runs [0,periodicWaveSize) here instead of [0,2*M_PI).
     float basePhaseIncrement =
       static_cast<float>(periodicWaveSize) / mSource->SampleRate();
 
     for (uint32_t i = aStart; i < aEnd; ++i) {
       UpdateParametersIfNeeded(ticks, i);
       mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
                                                      lowerWaveData,
                                                      higherWaveData,
                                                      tableInterpolationFactor);
-      mPhase = fmod(mPhase, periodicWaveSize);
       // Bilinear interpolation between adjacent samples in each table.
-      uint32_t j1 = floor(mPhase);
+      float floorPhase = floorf(mPhase);
+      uint32_t j1 = floorPhase;
+      j1 &= indexMask;
       uint32_t j2 = j1 + 1;
-      if (j2 >= periodicWaveSize) {
-        j2 -= periodicWaveSize;
-      }
-      float sampleInterpolationFactor = mPhase - j1;
+      j2 &= indexMask;
+
+      float sampleInterpolationFactor = mPhase - floorPhase;
+
       float lower = (1.0f - sampleInterpolationFactor) * lowerWaveData[j1] +
                     sampleInterpolationFactor * lowerWaveData[j2];
       float higher = (1.0f - sampleInterpolationFactor) * higherWaveData[j1] +
                     sampleInterpolationFactor * higherWaveData[j2];
       aOutput[i] = (1.0f - tableInterpolationFactor) * lower +
                    tableInterpolationFactor * higher;
 
-      mPhase += basePhaseIncrement * mFinalFrequency;
+      // Calculate next phase position from wrapped value j1 to avoid loss of
+      // precision at large values.
+      mPhase =
+        j1 + sampleInterpolationFactor + basePhaseIncrement * mFinalFrequency;
     }
   }
 
   void ComputeSilence(AudioChunk *aOutput)
   {
     aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
   }
 
--- a/content/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/content/media/webspeech/recognition/SpeechRecognition.cpp
@@ -703,18 +703,17 @@ SpeechRecognition::Start(const Optional<
 
   MediaStreamConstraints constraints;
   constraints.mAudio.SetAsBoolean() = true;
 
   if (aStream.WasPassed()) {
     StartRecording(&aStream.Value());
   } else {
     MediaManager* manager = MediaManager::Get();
-    manager->GetUserMedia(false,
-                          GetOwner(),
+    manager->GetUserMedia(GetOwner(),
                           constraints,
                           new GetUserMediaSuccessCallback(this),
                           new GetUserMediaErrorCallback(this));
   }
 
   nsRefPtr<SpeechEvent> event = new SpeechEvent(this, EVENT_START);
   NS_DispatchToMainThread(event);
 }
--- a/content/svg/content/src/DOMSVGLength.cpp
+++ b/content/svg/content/src/DOMSVGLength.cpp
@@ -9,16 +9,17 @@
 #include "SVGLength.h"
 #include "SVGAnimatedLengthList.h"
 #include "nsSVGElement.h"
 #include "nsSVGLength2.h"
 #include "nsIDOMSVGLength.h"
 #include "nsError.h"
 #include "nsMathUtils.h"
 #include "mozilla/dom/SVGLengthBinding.h"
+#include "mozilla/FloatingPoint.h"
 #include "nsSVGAttrTearoffTable.h"
 
 // See the architecture comment in DOMSVGAnimatedLengthList.h.
 
 namespace mozilla {
 
 static nsSVGAttrTearoffTable<nsSVGLength2, DOMSVGLength>
   sBaseSVGLengthTearOffTable,
@@ -223,17 +224,17 @@ DOMSVGLength::GetValue(ErrorResult& aRv)
     return mVal->GetBaseValue(mSVGElement);
   }
 
   if (mIsAnimValItem && HasOwner()) {
     Element()->FlushAnimations(); // May make HasOwner() == false
   }
   if (HasOwner()) {
     float value = InternalItem().GetValueInUserUnits(Element(), Axis());
-    if (!NS_finite(value)) {
+    if (!IsFinite(value)) {
       aRv.Throw(NS_ERROR_FAILURE);
     }
     return value;
   } else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
              mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
     return mValue;
   }
   // else [SVGWG issue] Can't convert this length's value to user units
@@ -271,17 +272,17 @@ DOMSVGLength::SetValue(float aUserUnitVa
   if (HasOwner()) {
     if (InternalItem().GetValueInUserUnits(Element(), Axis()) ==
         aUserUnitValue) {
       return;
     }
     float uuPerUnit = InternalItem().GetUserUnitsPerUnit(Element(), Axis());
     if (uuPerUnit > 0) {
       float newValue = aUserUnitValue / uuPerUnit;
-      if (NS_finite(newValue)) {
+      if (IsFinite(newValue)) {
         AutoChangeLengthNotifier notifier(this);
         InternalItem().SetValueAndUnit(newValue, InternalItem().GetUnit());
         return;
       }
     }
   } else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
              mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
     mValue = aUserUnitValue;
@@ -290,17 +291,17 @@ DOMSVGLength::SetValue(float aUserUnitVa
   // else [SVGWG issue] Can't convert user unit value to this length's unit
   // ReportToConsole
   aRv.Throw(NS_ERROR_FAILURE);
 }
 
 NS_IMETHODIMP
 DOMSVGLength::SetValue(float aUserUnitValue)
 {
-  if (!NS_finite(aUserUnitValue)) {
+  if (!IsFinite(aUserUnitValue)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
   ErrorResult rv;
   SetValue(aUserUnitValue, rv);
   return rv.ErrorCode();
 }
 
@@ -350,17 +351,17 @@ DOMSVGLength::SetValueInSpecifiedUnits(f
     return;
   }
   mValue = aValue;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::SetValueInSpecifiedUnits(float aValue)
 {
-  if (!NS_finite(aValue)) {
+  if (!IsFinite(aValue)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
   ErrorResult rv;
   SetValueInSpecifiedUnits(aValue, rv);
   return rv.ErrorCode();
 }
 
@@ -455,17 +456,17 @@ DOMSVGLength::NewValueSpecifiedUnits(uin
   }
   mUnit = uint8_t(aUnit);
   mValue = aValue;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::NewValueSpecifiedUnits(uint16_t aUnit, float aValue)
 {
-  if (!NS_finite(aValue)) {
+  if (!IsFinite(aValue)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
   ErrorResult rv;
   NewValueSpecifiedUnits(aUnit, aValue, rv);
   return rv.ErrorCode();
 }
 
@@ -487,25 +488,25 @@ DOMSVGLength::ConvertToSpecifiedUnits(ui
     return;
   }
   if (HasOwner()) {
     if (InternalItem().GetUnit() == aUnit) {
       return;
     }
     float val = InternalItem().GetValueInSpecifiedUnit(
                                  aUnit, Element(), Axis());
-    if (NS_finite(val)) {
+    if (IsFinite(val)) {
       AutoChangeLengthNotifier notifier(this);
       InternalItem().SetValueAndUnit(val, aUnit);
       return;
     }
   } else {
     SVGLength len(mValue, mUnit);
     float val = len.GetValueInSpecifiedUnit(aUnit, nullptr, 0);
-    if (NS_finite(val)) {
+    if (IsFinite(val)) {
       mValue = val;
       mUnit = aUnit;
       return;
     }
   }
   // else [SVGWG issue] Can't convert unit
   // ReportToConsole
   aRv.Throw(NS_ERROR_FAILURE);
--- a/content/svg/content/src/DOMSVGPoint.h
+++ b/content/svg/content/src/DOMSVGPoint.h
@@ -8,16 +8,17 @@
 
 #include "DOMSVGPointList.h"
 #include "mozilla/gfx/2D.h"
 #include "nsAutoPtr.h"
 #include "nsDebug.h"
 #include "nsISVGPoint.h"
 #include "SVGPoint.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/FloatingPoint.h"
 
 class nsSVGElement;
 
 namespace mozilla {
 
 namespace dom {
 class SVGMatrix;
 }
@@ -77,17 +78,17 @@ public:
     mPt.mY = aY;
   }
 
   explicit DOMSVGPoint(const Point& aPt)
     : nsISVGPoint()
   {
     mPt.mX = aPt.x;
     mPt.mY = aPt.y;
-    NS_ASSERTION(NS_finite(mPt.mX) && NS_finite(mPt.mX),
+    NS_ASSERTION(IsFinite(mPt.mX) && IsFinite(mPt.mX),
                  "DOMSVGPoint coords are not finite");
   }
 
 
   // WebIDL
   virtual float X();
   virtual void SetX(float aX, ErrorResult& rv);
   virtual float Y();
--- a/content/svg/content/src/SVGContentUtils.cpp
+++ b/content/svg/content/src/SVGContentUtils.cpp
@@ -20,16 +20,17 @@
 #include "nsIFrame.h"
 #include "nsIScriptError.h"
 #include "nsLayoutUtils.h"
 #include "SVGAnimationElement.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsContentUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Types.h"
+#include "mozilla/FloatingPoint.h"
 #include "nsStyleContext.h"
 #include "nsSVGPathDataParser.h"
 #include "SVGPathData.h"
 #include "SVGPathElement.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
@@ -659,17 +660,17 @@ SVGContentUtils::ParseNumber(RangedPtr<c
 {
   RangedPtr<const char16_t> iter(aIter);
 
   double value;
   if (!::ParseNumber(iter, aEnd, value)) {
     return false;
   }
   floatType floatValue = floatType(value);
-  if (!NS_finite(floatValue)) {
+  if (!IsFinite(floatValue)) {
     return false;
   }
   aValue = floatValue;
   aIter = iter;
   return true;
 }
 
 template bool
--- a/content/svg/content/src/SVGLength.cpp
+++ b/content/svg/content/src/SVGLength.cpp
@@ -119,27 +119,27 @@ SVGLength::GetValueInSpecifiedUnit(uint8
   // succeed if aElement is non-null (although that's not sufficent to
   // guarantee success).
 
   float userUnitsPerCurrentUnit = GetUserUnitsPerUnit(aElement, aAxis);
   float userUnitsPerNewUnit =
     SVGLength(0.0f, aUnit).GetUserUnitsPerUnit(aElement, aAxis);
 
   NS_ASSERTION(userUnitsPerCurrentUnit >= 0 ||
-               !NS_finite(userUnitsPerCurrentUnit),
+               !IsFinite(userUnitsPerCurrentUnit),
                "bad userUnitsPerCurrentUnit");
   NS_ASSERTION(userUnitsPerNewUnit >= 0 ||
-               !NS_finite(userUnitsPerNewUnit),
+               !IsFinite(userUnitsPerNewUnit),
                "bad userUnitsPerNewUnit");
 
   float value = mValue * userUnitsPerCurrentUnit / userUnitsPerNewUnit;
 
   // userUnitsPerCurrentUnit could be infinity, or userUnitsPerNewUnit could
   // be zero.
-  if (NS_finite(value)) {
+  if (IsFinite(value)) {
     return value;
   }
   return std::numeric_limits<float>::quiet_NaN();
 }
 
 #define INCHES_PER_MM_FLOAT float(0.0393700787)
 #define INCHES_PER_CM_FLOAT float(0.393700787)
 
--- a/content/svg/content/src/SVGLength.h
+++ b/content/svg/content/src/SVGLength.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_SVGLENGTH_H__
 #define MOZILLA_SVGLENGTH_H__
 
 #include "nsDebug.h"
 #include "nsIDOMSVGLength.h"
 #include "nsMathUtils.h"
+#include "mozilla/FloatingPoint.h"
 
 class nsSVGElement;
 
 namespace mozilla {
 
 /**
  * This SVGLength class is currently used for SVGLength *list* attributes only.
  * The class that is currently used for <length> attributes is nsSVGLength2.
@@ -134,17 +135,17 @@ public:
    * the comments for GetUserUnitsPerInch and GetUserUnitsPerPercent).
    */
   float GetUserUnitsPerUnit(const nsSVGElement *aElement, uint8_t aAxis) const;
 
 private:
 
 #ifdef DEBUG
   bool IsValid() const {
-    return NS_finite(mValue) && IsValidUnitType(mUnit);
+    return IsFinite(mValue) && IsValidUnitType(mUnit);
   }
 #endif
 
   /**
    * The conversion factor between user units (CSS px) and CSS inches is
    * constant: 96 px per inch.
    */
   static float GetUserUnitsPerInch()
--- a/content/svg/content/src/SVGLengthListSMILType.cpp
+++ b/content/svg/content/src/SVGLengthListSMILType.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SVGLengthListSMILType.h"
 #include "nsSMILValue.h"
 #include "SVGLengthList.h"
 #include "nsMathUtils.h"
+#include "mozilla/FloatingPoint.h"
 #include <math.h>
 #include <algorithm>
 
 namespace mozilla {
 
 /*static*/ SVGLengthListSMILType SVGLengthListSMILType::sSingleton;
 
 //----------------------------------------------------------------------
@@ -211,17 +212,17 @@ SVGLengthListSMILType::ComputeDistance(c
     total += f * f;
   }
   for (; i < to.Length(); ++i) {
     double t = to[i].GetValueInUserUnits(to.Element(), to.Axis());
     total += t * t;
   }
 
   float distance = sqrt(total);
-  if (!NS_finite(distance)) {
+  if (!IsFinite(distance)) {
     return NS_ERROR_FAILURE;
   }
   aDistance = distance;
   return NS_OK;
 }
 
 nsresult
 SVGLengthListSMILType::Interpolate(const nsSMILValue& aStartVal,
--- a/content/svg/content/src/SVGMarkerElement.cpp
+++ b/content/svg/content/src/SVGMarkerElement.cpp
@@ -9,16 +9,17 @@
 #include "nsCOMPtr.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsError.h"
 #include "mozilla/dom/SVGAngle.h"
 #include "mozilla/dom/SVGMarkerElement.h"
 #include "mozilla/dom/SVGMarkerElementBinding.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/gfx/Matrix.h"
+#include "mozilla/FloatingPoint.h"
 #include "SVGContentUtils.h"
 
 using namespace mozilla::gfx;
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Marker)
 
 namespace mozilla {
 namespace dom {
@@ -168,17 +169,17 @@ void SVGMarkerElement::SetOrientToAuto()
   SetAttr(kNameSpaceID_None, nsGkAtoms::orient, nullptr,
           NS_LITERAL_STRING("auto"), true);
 }
 
 void
 SVGMarkerElement::SetOrientToAngle(SVGAngle& angle, ErrorResult& rv)
 {
   float f = angle.Value();
-  if (!NS_finite(f)) {
+  if (!IsFinite(f)) {
     rv.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
     return;
   }
   mAngleAttributes[ORIENT].SetBaseValue(f, this, true);
 }
 
 //----------------------------------------------------------------------
 // nsIContent methods
--- a/content/svg/content/src/SVGMatrix.cpp
+++ b/content/svg/content/src/SVGMatrix.cpp
@@ -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/. */
 
 #include "mozilla/dom/SVGMatrix.h"
 #include "nsError.h"
 #include <math.h>
 #include "mozilla/dom/SVGMatrixBinding.h"
+#include "mozilla/FloatingPoint.h"
 
 const double radPerDegree = 2.0 * M_PI / 360.0;
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGMatrix, mTransform)
 
@@ -189,34 +190,34 @@ SVGMatrix::FlipY()
     new SVGMatrix(gfxMatrix(mx._11, mx._12, -mx._21, -mx._22, mx._31, mx._32));
   return matrix.forget();
 }
 
 already_AddRefed<SVGMatrix>
 SVGMatrix::SkewX(float angle, ErrorResult& rv)
 {
   double ta = tan( angle*radPerDegree );
-  if (!NS_finite(ta)) {
+  if (!IsFinite(ta)) {
     rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return nullptr;
   }
 
   const gfxMatrix& mx = GetMatrix();
   gfxMatrix skewMx(mx._11, mx._12,
                    (float) (mx._21 + mx._11*ta), (float) (mx._22 + mx._12*ta),
                    mx._31, mx._32);
   nsRefPtr<SVGMatrix> matrix = new SVGMatrix(skewMx);
   return matrix.forget();
 }
 
 already_AddRefed<SVGMatrix>
 SVGMatrix::SkewY(float angle, ErrorResult& rv)
 {
   double ta = tan( angle*radPerDegree );
-  if (!NS_finite(ta)) {
+  if (!IsFinite(ta)) {
     rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return nullptr;
   }
 
   const gfxMatrix& mx = GetMatrix();
   gfxMatrix skewMx((float) (mx._11 + mx._21*ta), (float) (mx._12 + mx._22*ta),
                    mx._21, mx._22,
                    mx._31, mx._32);
--- a/content/svg/content/src/SVGNumberListSMILType.cpp
+++ b/content/svg/content/src/SVGNumberListSMILType.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SVGNumberListSMILType.h"
 #include "nsSMILValue.h"
 #include "SVGNumberList.h"
 #include "nsMathUtils.h"
+#include "mozilla/FloatingPoint.h"
 #include <math.h>
 
 /* The "identity" number list for a given number list attribute (the effective
  * number list that is used if an attribute value is not specified) varies
  * widely for different number list attributes, and can depend on the value of
  * other attributes on the same element:
  *
  * http://www.w3.org/TR/SVG11/filters.html#feColorMatrixValuesAttribute
@@ -150,17 +151,17 @@ SVGNumberListSMILType::ComputeDistance(c
 
   double total = 0.0;
 
   for (uint32_t i = 0; i < to.Length(); ++i) {
     double delta = to[i] - from[i];
     total += delta * delta;
   }
   double distance = sqrt(total);
-  if (!NS_finite(distance)) {
+  if (!IsFinite(distance)) {
     return NS_ERROR_FAILURE;
   }
   aDistance = distance;
 
   return NS_OK;
 }
 
 nsresult
--- a/content/svg/content/src/SVGPoint.h
+++ b/content/svg/content/src/SVGPoint.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_SVGPOINT_H__
 #define MOZILLA_SVGPOINT_H__
 
 #include "nsDebug.h"
 #include "gfxPoint.h"
 #include "mozilla/gfx/Point.h"
+#include "mozilla/FloatingPoint.h"
 
 namespace mozilla {
 
 /**
  * This class is currently used for point list attributes.
  *
  * The DOM wrapper class for this class is DOMSVGPoint.
  */
@@ -61,17 +62,17 @@ public:
   }
 
   operator Point() const {
     return Point(mX, mY);
   }
 
 #ifdef DEBUG
   bool IsValid() const {
-    return NS_finite(mX) && NS_finite(mY);
+    return IsFinite(mX) && IsFinite(mY);
   }
 #endif
 
   void SetX(float aX)
     { mX = aX; }
   void SetY(float aY)
     { mY = aY; }
   float GetX() const
--- a/content/svg/content/src/SVGPointListSMILType.cpp
+++ b/content/svg/content/src/SVGPointListSMILType.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SVGPointListSMILType.h"
 #include "nsSMILValue.h"
 #include "SVGPointList.h"
 #include "nsMathUtils.h"
+#include "mozilla/FloatingPoint.h"
 #include <math.h>
 
 namespace mozilla {
 
 /*static*/ SVGPointListSMILType SVGPointListSMILType::sSingleton;
 
 //----------------------------------------------------------------------
 // nsISMILType implementation
@@ -130,17 +131,17 @@ SVGPointListSMILType::ComputeDistance(co
   double total = 0.0;
 
   for (uint32_t i = 0; i < to.Length(); ++i) {
     double dx = to[i].mX - from[i].mX;
     double dy = to[i].mY - from[i].mY;
     total += dx * dx + dy * dy;
   }
   double distance = sqrt(total);
-  if (!NS_finite(distance)) {
+  if (!IsFinite(distance)) {
     return NS_ERROR_FAILURE;
   }
   aDistance = distance;
 
   return NS_OK;
 }
 
 nsresult
--- a/content/svg/content/src/SVGTransform.cpp
+++ b/content/svg/content/src/SVGTransform.cpp
@@ -8,16 +8,17 @@
 
 #include "mozilla/dom/SVGTransform.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/dom/SVGTransformBinding.h"
 #include "nsError.h"
 #include "nsSVGAnimatedTransformList.h"
 #include "nsSVGAttrTearoffTable.h"
 #include "mozilla/DebugOnly.h"
+#include "mozilla/FloatingPoint.h"
 
 namespace {
   const double kRadPerDegree = 2.0 * M_PI / 360.0;
 }
 
 namespace mozilla {
 namespace dom {
 
@@ -258,17 +259,17 @@ SVGTransform::SetSkewX(float angle, Erro
     return;
   }
 
   if (Transform().Type() == SVG_TRANSFORM_SKEWX &&
       Transform().Angle() == angle) {
     return;
   }
 
-  if (!NS_finite(tan(angle * kRadPerDegree))) {
+  if (!IsFinite(tan(angle * kRadPerDegree))) {
     rv.Throw(NS_ERROR_RANGE_ERR);
     return;
   }
 
   AutoChangeTransformNotifier notifier(this);
   DebugOnly<nsresult> result = Transform().SetSkewX(angle);
   MOZ_ASSERT(NS_SUCCEEDED(result), "SetSkewX unexpectedly failed");
 }
@@ -281,17 +282,17 @@ SVGTransform::SetSkewY(float angle, Erro
     return;
   }
 
   if (Transform().Type() == SVG_TRANSFORM_SKEWY &&
       Transform().Angle() == angle) {
     return;
   }
 
-  if (!NS_finite(tan(angle * kRadPerDegree))) {
+  if (!IsFinite(tan(angle * kRadPerDegree))) {
     rv.Throw(NS_ERROR_RANGE_ERR);
     return;
   }
 
   AutoChangeTransformNotifier notifier(this);
   DebugOnly<nsresult> result = Transform().SetSkewY(angle);
   MOZ_ASSERT(NS_SUCCEEDED(result), "SetSkewY unexpectedly failed");
 }
--- a/content/svg/content/src/nsSVGNumber2.h
+++ b/content/svg/content/src/nsSVGNumber2.h
@@ -8,16 +8,17 @@
 
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsError.h"
 #include "nsISMILAttr.h"
 #include "nsMathUtils.h"
 #include "nsSVGElement.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/FloatingPoint.h"
 #include "mozilla/dom/SVGAnimatedNumber.h"
 
 class nsSMILValue;
 
 namespace mozilla {
 namespace dom {
 class SVGAnimationElement;
 }
@@ -78,17 +79,17 @@ public:
     nsSVGNumber2* mVal; // kept alive because it belongs to content
 
     virtual float BaseVal() MOZ_OVERRIDE
     {
       return mVal->GetBaseValue();
     }
     virtual void SetBaseVal(float aValue) MOZ_OVERRIDE
     {
-      MOZ_ASSERT(NS_finite(aValue));
+      MOZ_ASSERT(mozilla::IsFinite(aValue));
       mVal->SetBaseValue(aValue, mSVGElement);
     }
 
     // Script may have modified animation parameters or timeline -- DOM getters
     // need to flush any resample requests to reflect these modifications.
     virtual float AnimVal() MOZ_OVERRIDE
     {
       mSVGElement->FlushAnimations();
--- a/content/svg/content/src/nsSVGNumberPair.h
+++ b/content/svg/content/src/nsSVGNumberPair.h
@@ -9,16 +9,18 @@
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsError.h"
 #include "nsISMILAttr.h"
 #include "nsMathUtils.h"
 #include "nsSVGElement.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/SVGAnimatedNumber.h"
+#include "mozilla/FloatingPoint.h"
+
 
 class nsSMILValue;
 
 namespace mozilla {
 namespace dom {
 class SVGAnimationElement;
 }
 }
@@ -88,17 +90,17 @@ public:
     PairIndex mIndex; // are we the first or second number
 
     virtual float BaseVal() MOZ_OVERRIDE
     {
       return mVal->GetBaseValue(mIndex);
     }
     virtual void SetBaseVal(float aValue) MOZ_OVERRIDE
     {
-      MOZ_ASSERT(NS_finite(aValue));
+      MOZ_ASSERT(mozilla::IsFinite(aValue));
       mVal->SetBaseValue(aValue, mIndex, mSVGElement);
     }
 
     // Script may have modified animation parameters or timeline -- DOM getters
     // need to flush any resample requests to reflect these modifications.
     virtual float AnimVal() MOZ_OVERRIDE
     {
       mSVGElement->FlushAnimations();
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -53,17 +53,17 @@ ComputedTimingFunction::GetValue(double 
 }
 
 // In the Web Animations model, the time fraction can be outside the range
 // [0.0, 1.0] but it shouldn't be Infinity.
 const double ComputedTiming::kNullTimeFraction = PositiveInfinity<double>();
 
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Animation, mDocument)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Animation, mDocument, mTarget)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Animation, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Animation, Release)
 
 JSObject*
 Animation::WrapObject(JSContext* aCx)
 {
   return AnimationBinding::Wrap(aCx, this);
@@ -223,16 +223,39 @@ Animation::ActiveDuration(const Animatio
            ? zeroDuration
            : StickyTimeDuration::Forever();
   }
   return StickyTimeDuration(
     aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount));
 }
 
 bool
+Animation::IsCurrent() const
+{
+  if (IsFinishedTransition()) {
+    return false;
+  }
+
+  ComputedTiming computedTiming = GetComputedTiming();
+  return computedTiming.mPhase == ComputedTiming::AnimationPhase_Before ||
+         computedTiming.mPhase == ComputedTiming::AnimationPhase_Active;
+}
+
+bool
+Animation::IsInEffect() const
+{
+  if (IsFinishedTransition()) {
+    return false;
+  }
+
+  ComputedTiming computedTiming = GetComputedTiming();
+  return computedTiming.mTimeFraction != ComputedTiming::kNullTimeFraction;
+}
+
+bool
 Animation::HasAnimationOfProperty(nsCSSProperty aProperty) const
 {
   for (size_t propIdx = 0, propEnd = mProperties.Length();
        propIdx != propEnd; ++propIdx) {
     if (aProperty == mProperties[propIdx].mProperty) {
       return true;
     }
   }
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -3,22 +3,24 @@
  * 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 mozilla_dom_Animation_h
 #define mozilla_dom_Animation_h
 
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsCSSPseudoElements.h"
 #include "nsIDocument.h"
 #include "nsWrapperCache.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/StickyTimeDuration.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TimeStamp.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/dom/Nullable.h"
 #include "nsSMILKeySpline.h"
 #include "nsStyleStruct.h" // for nsTimingFunction
 
 struct JSContext;
 
 namespace mozilla {
 
@@ -123,24 +125,29 @@ struct ElementPropertyTransition;
 namespace dom {
 
 class AnimationEffect;
 
 class Animation : public nsWrapperCache
 {
 public:
   Animation(nsIDocument* aDocument,
+            Element* aTarget,
+            nsCSSPseudoElements::Type aPseudoType,
             const AnimationTiming &aTiming,
             const nsSubstring& aName)
     : mDocument(aDocument)
+    , mTarget(aTarget)
     , mTiming(aTiming)
     , mName(aName)
     , mIsFinishedTransition(false)
     , mLastNotification(LAST_NOTIFICATION_NONE)
+    , mPseudoType(aPseudoType)
   {
+    MOZ_ASSERT(aTarget, "null animation target is not yet supported");
     SetIsDOMBinding();
   }
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Animation)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Animation)
 
   nsIDocument* GetParentObject() const { return mDocument; }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
@@ -152,16 +159,25 @@ public:
   virtual const ElementPropertyTransition* AsTransition() const {
     return nullptr;
   }
 
   // Animation interface
   // This currently returns a new object each time when used from C++ but is
   // cached when used from JS.
   already_AddRefed<AnimationEffect> GetEffect();
+  Element* GetTarget() const {
+    // Currently we only implement Element.getAnimationPlayers() which only
+    // returns animations targetting Elements so we should this should never
+    // be called for an animation that targets a pseudo-element.
+    MOZ_ASSERT(mPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement,
+               "Requesting the target of an Animation that targets a"
+               " pseudo-element is not yet supported.");
+    return mTarget;
+  }
 
   void SetParentTime(Nullable<TimeDuration> aParentTime);
 
   const AnimationTiming& Timing() const {
     return mTiming;
   }
   AnimationTiming& Timing() {
     return mTiming;
@@ -219,25 +235,18 @@ public:
   }
 
   void SetIsFinishedTransition() {
     MOZ_ASSERT(AsTransition(),
                "Calling SetIsFinishedTransition but it's not a transition");
     mIsFinishedTransition = true;
   }
 
-  bool IsCurrent() const {
-    if (IsFinishedTransition()) {
-      return false;
-    }
-
-    ComputedTiming computedTiming = GetComputedTiming();
-    return computedTiming.mPhase == ComputedTiming::AnimationPhase_Before ||
-           computedTiming.mPhase == ComputedTiming::AnimationPhase_Active;
-  }
+  bool IsCurrent() const;
+  bool IsInEffect() const;
 
   enum {
     LAST_NOTIFICATION_NONE = uint64_t(-1),
     LAST_NOTIFICATION_END = uint64_t(-2)
   };
   uint64_t LastNotification() const { return mLastNotification; }
   void SetLastNotification(uint64_t aLastNotification) {
     mLastNotification = aLastNotification;
@@ -251,27 +260,29 @@ public:
     return mProperties;
   }
 
 protected:
   virtual ~Animation() { }
 
   // We use a document for a parent object since the other likely candidate,
   // the target element, can be empty.
-  nsRefPtr<nsIDocument> mDocument;
+  nsCOMPtr<nsIDocument> mDocument;
+  nsCOMPtr<Element> mTarget;
   Nullable<TimeDuration> mParentTime;
 
   AnimationTiming mTiming;
   nsString mName;
   // A flag to mark transitions that have finished and are due to
   // be removed on the next throttle-able cycle.
   bool mIsFinishedTransition;
   // One of the LAST_NOTIFICATION_* constants, or an integer for the iteration
   // whose start we last notified on.
   uint64_t mLastNotification;
+  nsCSSPseudoElements::Type mPseudoType;
 
   InfallibleTArray<AnimationProperty> mProperties;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Animation_h
--- a/dom/animation/AnimationPlayer.cpp
+++ b/dom/animation/AnimationPlayer.cpp
@@ -59,22 +59,16 @@ AnimationPlayer::IsRunning() const
   if (IsPaused() || !GetSource() || GetSource()->IsFinishedTransition()) {
     return false;
   }
 
   ComputedTiming computedTiming = GetSource()->GetComputedTiming();
   return computedTiming.mPhase == ComputedTiming::AnimationPhase_Active;
 }
 
-bool
-AnimationPlayer::IsCurrent() const
-{
-  return GetSource() && GetSource()->IsCurrent();
-}
-
 Nullable<TimeDuration>
 AnimationPlayer::GetCurrentTimeDuration() const
 {
   Nullable<TimeDuration> result;
   if (!mHoldTime.IsNull()) {
     result = mHoldTime;
   } else {
     Nullable<TimeDuration> timelineTime = mTimeline->GetCurrentTimeDuration();
--- a/dom/animation/AnimationPlayer.h
+++ b/dom/animation/AnimationPlayer.h
@@ -59,17 +59,23 @@ public:
     return mSource ? mSource->Name() : EmptyString();
   }
 
   bool IsPaused() const {
     return mPlayState == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED;
   }
 
   bool IsRunning() const;
-  bool IsCurrent() const;
+
+  bool HasCurrentSource() const {
+    return GetSource() && GetSource()->IsCurrent();
+  }
+  bool HasInEffectSource() const {
+    return GetSource() && GetSource()->IsInEffect();
+  }
 
   // Return the duration since the start time of the player, taking into
   // account the pause state.  May be negative or null.
   Nullable<TimeDuration> GetCurrentTimeDuration() const;
 
   // The beginning of the delay period.
   Nullable<TimeDuration> mStartTime;
   Nullable<TimeDuration> mHoldTime;
--- a/dom/animation/test/chrome/test_running_on_compositor.html
+++ b/dom/animation/test/chrome/test_running_on_compositor.html
@@ -37,17 +37,16 @@ var div = document.querySelector('div.ta
 
 const OMTAPrefKey = 'layers.offmainthreadcomposition.async-animations';
 var omtaEnabled = SpecialPowers.DOMWindowUtils.layerManagerRemote &&
                   SpecialPowers.getBoolPref(OMTAPrefKey);
 
 // FIXME: When we implement Element.animate, use that here instead of CSS
 // so that we remove any dependency on the CSS mapping.
 div.style.animation = 'anim 100s';
-window.getComputedStyle(div).animationName;
 var player = div.getAnimationPlayers()[0];
 
 // Wait so that animation can be set up.
 // FIXME: When we implement the AnimationPlayer.ready promise we should wait
 // on that here.
 window.requestAnimationFrame(function() {
   is(player.isRunningOnCompositor, omtaEnabled,
      'AnimationPlayer reports that it is running on the compositor'
--- a/dom/animation/test/css-integration/test_animation-effect-name.html
+++ b/dom/animation/test/css-integration/test_animation-effect-name.html
@@ -15,51 +15,44 @@ function addDiv() {
   var div = document.createElement('div');
   document.body.appendChild(div);
   return div;
 }
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'xyz 100s';
-  window.getComputedStyle(div).animationName;
-
   assert_equals(div.getAnimationPlayers()[0].source.effect.name, 'xyz',
                 'Animation effect name matches keyframes rule name');
   div.remove();
 }, 'Effect name makes keyframe rule');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'x\\yz 100s';
-  dump(window.getComputedStyle(div).animationName + "\n");
-
   assert_equals(div.getAnimationPlayers()[0].source.effect.name, 'xyz',
                 'Escaped animation effect name matches keyframes rule name');
   div.remove();
 }, 'Escaped animation name');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'x\\79 z 100s';
-  window.getComputedStyle(div).animationName;
-
   assert_equals(div.getAnimationPlayers()[0].source.effect.name, 'xyz',
                 'Hex-escaped animation effect name matches keyframes rule'
                 + ' name');
   div.remove();
 }, 'Animation name with hex-escape');
 
 test(function() {
   var div = addDiv();
 
   // Add a transition
   div.style.left = '0px';
   window.getComputedStyle(div).transitionProperty;
   div.style.transition = 'all 100s';
   div.style.left = '100px';
-  window.getComputedStyle(div).left;
 
   assert_equals(div.getAnimationPlayers()[0].source.effect.name, '',
                 'Animation effects for transitions have an empty name');
   div.remove();
 }, 'Effect name for transitions');
 </script>
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/css-integration/test_animation-target.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<style>
+@keyframes anim { }
+</style>
+<script>
+'use strict';
+
+function addDiv() {
+  var div = document.createElement('div');
+  document.body.appendChild(div);
+  return div;
+}
+
+test(function() {
+  var div = addDiv();
+  div.style.animation = 'anim 100s';
+  var players = div.getAnimationPlayers();
+  assert_equals(players[0].source.target, div,
+    'Animation.target is the animatable div');
+  div.remove();
+}, 'Returned CSS animations have the correct Animation.target');
+
+test(function() {
+  var div = addDiv();
+
+  div.style.left = '0px';
+  window.getComputedStyle(div).transitionProperty;
+  div.style.transition = 'left 100s';
+  div.style.left = '100px';
+
+  var players = div.getAnimationPlayers();
+  assert_equals(players[0].source.target, div,
+    'Animation.target is the animatable div');
+  div.remove();
+}, 'Returned CSS transitions have the correct Animation.target');
+
+</script>
--- a/dom/animation/test/css-integration/test_animations-dynamic-changes.html
+++ b/dom/animation/test/css-integration/test_animations-dynamic-changes.html
@@ -16,27 +16,25 @@ function addDiv() {
   var div = document.createElement('div');
   document.body.appendChild(div);
   return div;
 }
 
 async_test(function(t) {
   var div = addDiv();
   div.style.animation = 'anim1 100s';
-  window.getComputedStyle(div).animationName;
 
   var originalPlayer = div.getAnimationPlayers()[0];
   var originalStartTime = originalPlayer.startTime;
   var originalCurrentTime = originalPlayer.currentTime;
 
   // Wait a moment so we can confirm the startTime doesn't change (and doesn't
   // simply reflect the current time).
   window.requestAnimationFrame(t.step_func(function() {
     div.style.animationDuration = '200s';
-    window.getComputedStyle(div).animationDuration;
     var player = div.getAnimationPlayers()[0];
     assert_equals(player, originalPlayer,
                   'The same AnimationPlayer is returned after updating'
                   + ' animation duration');
     assert_equals(player.startTime, originalStartTime,
                   'AnimationPlayers returned by getAnimationPlayers preserve'
                   + ' their startTime even when they are updated');
     // Sanity check
@@ -46,49 +44,45 @@ async_test(function(t) {
     div.remove();
     t.done();
   }));
 }, 'AnimationPlayers preserve their startTime when changed');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 100s, anim1 100s';
-  window.getComputedStyle(div).animationName;
 
   // Store original state
   var players = div.getAnimationPlayers();
   var player1 = players[0];
   var player2 = players[1];
 
   // Update first in list
   div.style.animationDuration = '200s, 100s';
-  window.getComputedStyle(div).animationDuration;
   players = div.getAnimationPlayers();
   assert_equals(players[0], player1,
                 'First player is in same position after update');
   assert_equals(players[1], player2,
                 'Second player is in same position after update');
 }, 'Updated AnimationPlayers maintain their order in the list');
 
 async_test(function(t) {
   var div = addDiv();
   div.style.animation = 'anim1 200s, anim1 100s';
-  window.getComputedStyle(div).animationName;
 
   // Store original state
   var players = div.getAnimationPlayers();
   var player1 = players[0];
   var player2 = players[1];
 
   // Wait before continuing so we can compare start times
   window.requestAnimationFrame(t.step_func(function() {
     // Swap duration of first and second in list and prepend animation at the
     // same time
     div.style.animation = 'anim1 100s, anim1 100s, anim1 200s';
-    window.getComputedStyle(div).animationName;
     players = div.getAnimationPlayers();
     assert_true(players[0] !== player1 && players[0] !== player2,
                 'New player is prepended to start of list');
     assert_equals(players[1], player1,
                   'First player is in second position after update');
     assert_equals(players[2], player2,
                   'Second player is in third position after update');
     assert_equals(players[1].startTime, players[2].startTime,
@@ -98,53 +92,47 @@ async_test(function(t) {
     div.remove();
     t.done();
   }));
 }, 'Only the startTimes of existing animations are preserved');
 
 async_test(function(t) {
   var div = addDiv();
   div.style.animation = 'anim1 100s, anim1 100s';
-  window.getComputedStyle(div).animationName;
-
   var secondPlayer = div.getAnimationPlayers()[1];
 
   // Wait before continuing so we can compare start times
   window.requestAnimationFrame(t.step_func(function() {
     // Trim list of animations
     div.style.animationName = 'anim1';
-    window.getComputedStyle(div).animationName;
     var players = div.getAnimationPlayers();
     assert_equals(players.length, 1, 'List of players was trimmed');
     assert_equals(players[0], secondPlayer,
                   'Remaining player is the second one in the list');
     assert_true(players[0].startTime < players[0].timeline.currentTime,
                 'Remaining player preserves startTime');
     div.remove();
     t.done();
   }));
 }, 'Animations are removed from the start of the list while preserving'
    + ' the state of existing players');
 
 async_test(function(t) {
   var div = addDiv();
   div.style.animation = 'anim1 100s';
-  window.getComputedStyle(div).animationName;
   var firstAddedPlayer = div.getAnimationPlayers()[0];
 
   // Wait and add second player
   window.requestAnimationFrame(t.step_func(function() {
     div.style.animation = 'anim1 100s, anim1 100s';
-    window.getComputedStyle(div).animationName;
     var secondAddedPlayer = div.getAnimationPlayers()[0];
 
     // Wait again and add another player
     window.requestAnimationFrame(t.step_func(function() {
       div.style.animation = 'anim1 100s, anim2 100s, anim1 100s';
-      window.getComputedStyle(div).animationName;
       var players = div.getAnimationPlayers();
       assert_not_equals(firstAddedPlayer, secondAddedPlayer,
                         'New players are added to start of the list');
       assert_equals(players[0], secondAddedPlayer,
                     'Second player remains in same position after'
                     + ' interleaving');
       assert_equals(players[2], firstAddedPlayer,
                     'First player remains in same position after'
--- a/dom/animation/test/css-integration/test_element-get-animation-players.html
+++ b/dom/animation/test/css-integration/test_element-get-animation-players.html
@@ -32,31 +32,29 @@ test(function() {
   div.remove();
 }, 'getAnimationPlayers for non-animated content');
 
 async_test(function(t) {
   var div = addDiv();
 
   // Add an animation
   div.style.animation = 'anim1 100s';
-  window.getComputedStyle(div).animationName;
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 1,
     'getAnimationPlayers returns a player running CSS Animations');
   var startTime = players[0].startTime;
   assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
     'CSS animation has a sensible start time');
 
   // Wait a moment then add a second animation.
   //
   // We wait for the next frame so that we can test that the start times of
   // the animations differ.
   window.requestAnimationFrame(t.step_func(function() {
     div.style.animation = 'anim1 100s, anim2 100s';
-    window.getComputedStyle(div).animationName;
     players = div.getAnimationPlayers();
     assert_equals(players.length, 2,
       'getAnimationPlayers returns one player for each value of'
       + ' animation-name');
     assert_true(players[0].startTime < players[1].startTime,
       'Additional players for CSS animations start after the original'
       + ' animation and appear later in the list');
     div.remove();
@@ -64,48 +62,46 @@ async_test(function(t) {
   }));
 }, 'getAnimationPlayers for CSS Animations');
 
 test(function() {
   var div = addDiv();
 
   // Add an animation that targets multiple properties
   div.style.animation = 'multiPropAnim 100s';
-  window.getComputedStyle(div).animationName;
   assert_equals(div.getAnimationPlayers().length, 1,
     'getAnimationPlayers returns only one player for a CSS Animation'
     + ' that targets multiple properties');
   div.remove();
 }, 'getAnimationPlayers for multi-property animations');
 
 async_test(function(t) {
   var div = addDiv();
 
   // Add a couple of transitions
   div.style.left = '0px';
   div.style.top = '0px';
   window.getComputedStyle(div).transitionProperty;
+
   div.style.transition = 'all 100s';
   div.style.left = '100px';
   div.style.top = '100px';
-  window.getComputedStyle(div).left;
 
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 2,
     'getAnimationPlayers() returns one player per transitioning property');
   var startTime = players[0].startTime;
   assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
     'CSS transitions have sensible start times');
   assert_equals(players[0].startTime, players[1].startTime,
     'CSS transitions started together have the same start time');
 
   // Wait a moment then add a third transition
   window.requestAnimationFrame(t.step_func(function() {
     div.style.backgroundColor = 'green';
-    window.getComputedStyle(div).backgroundColor;
     players = div.getAnimationPlayers();
     assert_equals(players.length, 3,
       'getAnimationPlayers returns players for all running CSS Transitions');
     assert_true(players[1].startTime < players[2].startTime,
       'Player for additional CSS transition starts after the original'
       + ' transitions and appears later in the list');
     div.remove();
     t.done();
@@ -119,17 +115,16 @@ async_test(function(t) {
   div.style.backgroundColor = 'red';
   div.style.animation = 'anim1 100s';
   window.getComputedStyle(div).backgroundColor;
 
   // Wait a moment then add a transition
   window.requestAnimationFrame(t.step_func(function() {
     div.style.transition = 'all 100s';
     div.style.backgroundColor = 'green';
-    window.getComputedStyle(div).backgroundColor;
 
     var players = div.getAnimationPlayers();
     assert_equals(players.length, 2,
       'getAnimationPlayers returns players for both animations and '
       + ' transitions that run simultaneously');
     assert_true(players[0].startTime > players[1].startTime,
       'players for transitions appear before animations even if they '
       + ' start later');
@@ -147,205 +142,200 @@ async_test(function(t) {
       'getAnimationPlayers does not return players for finished '
       + ' (and non-forwards-filling) CSS Animations');
     div.remove();
     t.done();
   }));
 
   // Add a very short animation
   div.style.animation = 'anim1 0.01s';
-  window.getComputedStyle(div).animationName;
 }, 'getAnimationPlayers for CSS Animations that have finished');
 
 async_test(function(t) {
   var div = addDiv();
 
   // Set up event listener
+  div.addEventListener('animationend', t.step_func(function() {
+    assert_equals(div.getAnimationPlayers().length, 1,
+      'getAnimationPlayers returns players for CSS Animations that have'
+      + ' finished but are filling forwards');
+    div.remove();
+    t.done();
+  }));
+
+  // Add a very short animation
+  div.style.animation = 'anim1 0.01s forwards';
+}, 'getAnimationPlayers for CSS Animations that have finished but are'
+   + ' forwards filling');
+
+async_test(function(t) {
+  var div = addDiv();
+
+  // Set up event listener
   div.addEventListener('transitionend', t.step_func(function() {
     assert_equals(div.getAnimationPlayers().length, 0,
       'getAnimationPlayers does not return finished CSS Transitions');
     div.remove();
     t.done();
   }));
 
   // Add a very short transition
   div.style.left = '0px';
   window.getComputedStyle(div).left;
+
   div.style.transition = 'all 0.01s';
   div.style.left = '100px';
   window.getComputedStyle(div).left;
 }, 'getAnimationPlayers for CSS Transitions that have finished');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'none 100s';
-  window.getComputedStyle(div).animationName;
 
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 0,
     'getAnimationPlayers returns an empty sequence for an element'
     + ' with animation-name: none');
 
   div.style.animation = 'none 100s, anim1 100s';
-  window.getComputedStyle(div).animationName;
   players = div.getAnimationPlayers();
   assert_equals(players.length, 1,
     'getAnimationPlayers returns players only for those CSS Animations whose'
     + ' animation-name is not none');
 
   div.remove();
 }, 'getAnimationPlayers for CSS Animations with animation-name: none');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'missing 100s';
-  window.getComputedStyle(div).animationName;
-
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 0,
     'getAnimationPlayers returns an empty sequence for an element'
     + ' with animation-name: missing');
 
   div.style.animation = 'anim1 100s, missing 100s';
-  window.getComputedStyle(div).animationName;
   players = div.getAnimationPlayers();
   assert_equals(players.length, 1,
     'getAnimationPlayers returns players only for those CSS Animations whose'
     + ' animation-name is found');
 
   div.remove();
 }, 'getAnimationPlayers for CSS Animations with animation-name: missing');
 
 async_test(function(t) {
   var div = addDiv();
   div.style.animation = 'anim1 100s, notyet 100s';
-  window.getComputedStyle(div).animationName;
-
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 1,
     'getAnimationPlayers initally only returns players for CSS Animations whose'
     + ' animation-name is found');
 
   window.requestAnimationFrame(t.step_func(function() {
     var keyframes = '@keyframes notyet { to { left: 100px; } }';
     document.styleSheets[0].insertRule(keyframes, 0);
-    window.getComputedStyle(div).animationName;
-
     players = div.getAnimationPlayers();
     assert_equals(players.length, 2,
       'getAnimationPlayers includes player when @keyframes rule is added'
       + ' later');
     assert_true(players[0].startTime < players[1].startTime,
       'Newly added player has a later start time');
     document.styleSheets[0].deleteRule(0);
     div.remove();
     t.done();
   }));
 }, 'getAnimationPlayers for CSS Animations where the @keyframes rule is added'
    + ' later');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 100s, anim1 100s';
-  window.getComputedStyle(div).animationName;
-
   assert_equals(div.getAnimationPlayers().length, 2,
     'getAnimationPlayers returns one player for each CSS animation-name'
     + ' even if the names are duplicated');
   div.remove();
 }, 'getAnimationPlayers for CSS Animations with duplicated animation-name');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'empty 100s';
-  window.getComputedStyle(div).animationName;
-
   assert_equals(div.getAnimationPlayers().length, 1,
     'getAnimationPlayers returns players for CSS animations with an'
     + ' empty keyframes rule');
   div.remove();
 }, 'getAnimationPlayers for CSS Animations with empty keyframes rule');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 100s 100s';
-  window.getComputedStyle(div).animationName;
-
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 1,
     'getAnimationPlayers returns animations for CSS animations whose'
     + ' delay makes them start later');
   assert_true(players[0].startTime <= document.timeline.currentTime,
     'For CSS Animations in delay phase, the start time of the player is'
     + ' not in the future');
   div.remove();
 }, 'getAnimationPlayers for CSS animations in delay phase');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 0s 100s';
-  window.getComputedStyle(div).animationName;
-
   assert_equals(div.getAnimationPlayers().length, 1,
     'getAnimationPlayers returns animations for CSS animations whose'
     + ' duration is zero');
   div.remove();
 }, 'getAnimationPlayers for zero-duration CSS Animations');
 
 test(function() {
   var div = addDiv();
 
   // Try to transition non-animatable property animation-duration
   div.style.animationDuration = '10s';
   window.getComputedStyle(div).animationDuration;
+
   div.style.transition = 'all 100s';
   div.style.animationDuration = '100s';
-  window.getComputedStyle(div).left;
 
   assert_equals(div.getAnimationPlayers().length, 0,
     'getAnimationPlayers returns an empty sequence for a transition'
     + ' of a non-animatable property');
   div.remove();
 }, 'getAnimationPlayers for transition on non-animatable property');
 
 test(function() {
   var div = addDiv();
 
   div.style.setProperty('-vendor-unsupported', '0px', '');
   window.getComputedStyle(div).transitionProperty;
   div.style.transition = 'all 100s';
   div.style.setProperty('-vendor-unsupported', '100px', '');
-  window.getComputedStyle(div).getPropertyValue('-vendor-unsupported');
 
   assert_equals(div.getAnimationPlayers().length, 0,
     'getAnimationPlayers returns an empty sequence for a transition'
     + ' of an unsupported property');
   div.remove();
 }, 'getAnimationPlayers for transition on unsupported property');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 100s';
-  window.getComputedStyle(div).animationName;
-
   var originalPlayer = div.getAnimationPlayers()[0];
 
   // Update pause state (an AnimationPlayer change)
   div.style.animationPlayState = 'paused';
-  window.getComputedStyle(div).animationPlayState;
   var pausedPlayer = div.getAnimationPlayers()[0];
   // FIXME: Check pausedPlayer.playState has changed once the API is available
   // (bug 1037321)
   assert_equals(originalPlayer, pausedPlayer,
                 'getAnimationPlayers returns the same objects even when their'
                 + ' play state changes');
 
   // Update duration (an Animation change)
   div.style.animationDuration = '200s';
-  window.getComputedStyle(div).animationDuration
   var extendedPlayer = div.getAnimationPlayers()[0];
   // FIXME: Check extendedPlayer.source.timing.duration has changed once the
   // API is available
   assert_equals(originalPlayer, extendedPlayer,
                 'getAnimationPlayers returns the same objects even when their'
                 + ' duration changes');
 
   div.remove();
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -1,6 +1,7 @@
 [animation-timeline/test_animation-timeline.html]
 skip-if = buildapp == 'mulet'
 [css-integration/test_element-get-animation-players.html]
 skip-if = buildapp == 'mulet'
 [css-integration/test_animations-dynamic-changes.html]
 [css-integration/test_animation-effect-name.html]
+[css-integration/test_animation-target.html]
--- a/dom/apps/Webapps.jsm
+++ b/dom/apps/Webapps.jsm
@@ -627,21 +627,28 @@ this.DOMApplicationRegistry = {
           // Create a new localId.
           this.webapps[id].localId = this._nextLocalId();
 
           // Core apps are not removable.
           if (this.webapps[id].removable === undefined) {
             this.webapps[id].removable = false;
           }
         } else {
+          // Fields that we must not update. Confere bug 993011 comment 10.
+          let fieldsBlacklist = ["basePath", "id", "installerAppId",
+            "installerIsBrowser", "localId", "receipts", "storeId",
+            "storeVersion"];
           // we fall into this case if the app is present in /system/b2g/webapps/webapps.json
           // and in /data/local/webapps/webapps.json: this happens when updating gaia apps
           // Confere bug 989876
-          this.webapps[id].updateTime = data[id].updateTime;
-          this.webapps[id].lastUpdateCheck = data[id].updateTime;
+          for (let field in data[id]) {
+            if (fieldsBlacklist.indexOf(field) === -1) {
+              this.webapps[id][field] = data[id][field];
+            }
+          }
         }
       }
     }.bind(this)).then(null, Cu.reportError);
   },
 
   loadAndUpdateApps: function() {
     return Task.spawn(function() {
       let runUpdate = AppsUtils.isFirstRun(Services.prefs);
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1246,21 +1246,18 @@ Navigator::MozGetUserMedia(const MediaSt
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
 
   if (!mWindow || !mWindow->GetOuterWindow() ||
       mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return;
   }
 
-  bool privileged = nsContentUtils::IsChromeDoc(mWindow->GetExtantDoc());
-
   MediaManager* manager = MediaManager::Get();
-  aRv = manager->GetUserMedia(privileged, mWindow, aConstraints,
-                              onsuccess, onerror);
+  aRv = manager->GetUserMedia(mWindow, aConstraints, onsuccess, onerror);
 }
 
 void
 Navigator::MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints,
                                   MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
                                   NavigatorUserMediaErrorCallback& aOnError,
                                   uint64_t aInnerWindowID,
                                   ErrorResult& aRv)
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2058,46 +2058,47 @@ ConstructJSImplementation(JSContext* aCx
 {
   // Make sure to divorce ourselves from the calling JS while creating and
   // initializing the object, so exceptions from that will get reported
   // properly, since those are never exceptions that a spec wants to be thrown.
   {
     AutoNoJSAPI nojsapi;
 
     // Get the XPCOM component containing the JS implementation.
-    nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId);
+    nsresult rv;
+    nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId, &rv);
     if (!implISupports) {
       NS_WARNING("Failed to get JS implementation for contract");
-      aRv.Throw(NS_ERROR_FAILURE);
+      aRv.Throw(rv);
       return;
     }
     // Initialize the object, if it implements nsIDOMGlobalPropertyInitializer.
     nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
       do_QueryInterface(implISupports);
     if (gpi) {
       JS::Rooted<JS::Value> initReturn(aCx);
-      nsresult rv = gpi->Init(aWindow, &initReturn);
+      rv = gpi->Init(aWindow, &initReturn);
       if (NS_FAILED(rv)) {
         aRv.Throw(rv);
         return;
       }
       // With JS-implemented WebIDL, the return value of init() is not used to determine
       // if init() failed, so init() should only return undefined. Any kind of permission
       // or pref checking must happen by adding an attribute to the WebIDL interface.
       if (!initReturn.isUndefined()) {
         MOZ_ASSERT(false, "The init() method for JS-implemented WebIDL should not return anything");
         MOZ_CRASH();
       }
     }
     // Extract the JS implementation from the XPCOM object.
     nsCOMPtr<nsIXPConnectWrappedJS> implWrapped =
-      do_QueryInterface(implISupports);
+      do_QueryInterface(implISupports, &rv);
     MOZ_ASSERT(implWrapped, "Failed to get wrapped JS from XPCOM component.");
     if (!implWrapped) {
-      aRv.Throw(NS_ERROR_FAILURE);
+      aRv.Throw(rv);
       return;
     }
     aObject.set(implWrapped->GetJSObject());
     if (!aObject) {
       aRv.Throw(NS_ERROR_FAILURE);
     }
   }
 }
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -95,16 +95,17 @@
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/HTMLImageElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/dom/TextMetrics.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/SVGMatrix.h"
+#include "mozilla/FloatingPoint.h"
 #include "nsGlobalWindow.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 #include "SVGContentUtils.h"
 #include "SVGImageContext.h"
 #include "nsIScreenManager.h"
 #include "nsFilterInstance.h"
 #include "nsSVGLength2.h"
@@ -4349,18 +4350,18 @@ CanvasRenderingContext2D::GetImageData(J
   if (mCanvasElement && mCanvasElement->IsWriteOnly() &&
       !nsContentUtils::IsCallerChrome())
   {
     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
     error.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
-  if (!NS_finite(aSx) || !NS_finite(aSy) ||
-      !NS_finite(aSw) || !NS_finite(aSh)) {
+  if (!IsFinite(aSx) || !IsFinite(aSy) ||
+      !IsFinite(aSw) || !IsFinite(aSh)) {
     error.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return nullptr;
   }
 
   if (!aSw || !aSh) {
     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return nullptr;
   }
--- a/dom/canvas/CanvasUtils.h
+++ b/dom/canvas/CanvasUtils.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _CANVASUTILS_H_
 #define _CANVASUTILS_H_
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "jsapi.h"
+#include "mozilla/FloatingPoint.h"
 
 class nsIPrincipal;
 
 namespace mozilla {
 
 namespace gfx {
 class Matrix;
 }
@@ -48,17 +49,17 @@ void DoDrawImageSecurityCheck(dom::HTMLC
                               bool CORSUsed);
 
 // Make a double out of |v|, treating undefined values as 0.0 (for
 // the sake of sparse arrays).  Return true iff coercion
 // succeeded.
 bool CoerceDouble(JS::Value v, double* d);
 
     /* Float validation stuff */
-#define VALIDATE(_f)  if (!NS_finite(_f)) return false
+#define VALIDATE(_f)  if (!IsFinite(_f)) return false
 
 inline bool FloatValidate (double f1) {
     VALIDATE(f1);
     return true;
 }
 
 inline bool FloatValidate (double f1, double f2) {
     VALIDATE(f1); VALIDATE(f2);
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -222,16 +222,17 @@ WebGLContextOptions::WebGLContextOptions
 {
     // Set default alpha state based on preference.
     if (Preferences::GetBool("webgl.default-no-alpha", false))
         alpha = false;
 }
 
 WebGLContext::WebGLContext()
     : gl(nullptr)
+    , mNeedsFakeNoAlpha(false)
 {
     SetIsDOMBinding();
 
     mGeneration = 0;
     mInvalidated = false;
     mShouldPresent = true;
     mResetLayer = true;
     mOptionsFrozen = false;
@@ -921,16 +922,22 @@ WebGLContext::SetDimensions(int32_t sWid
 
     MOZ_ASSERT(gl->Caps().color);
     MOZ_ASSERT(gl->Caps().alpha == mOptions.alpha);
     MOZ_ASSERT(gl->Caps().depth == mOptions.depth || !gl->Caps().depth);
     MOZ_ASSERT(gl->Caps().stencil == mOptions.stencil || !gl->Caps().stencil);
     MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias || !gl->Caps().antialias);
     MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer);
 
+    if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
+        if (!mOptions.alpha) {
+            mNeedsFakeNoAlpha = true;
+        }
+    }
+
     AssertCachedBindings();
     AssertCachedState();
 
     reporter.SetSuccessful();
     return NS_OK;
 }
 
 void
@@ -1335,17 +1342,22 @@ WebGLContext::ForceClearFramebufferWithD
             }
             // calling draw buffers can cause resolves on adreno drivers so
             // we try to avoid calling it
             if (shouldOverrideDrawBuffers)
                 gl->fDrawBuffers(mGLMaxDrawBuffers, drawBuffersCommand);
         }
 
         gl->fColorMask(1, 1, 1, 1);
-        gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+        if (mNeedsFakeNoAlpha) {
+            gl->fClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+        } else {
+            gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+        }
     }
 
     if (initializeDepthBuffer) {
         gl->fDepthMask(1);
         gl->fClearDepth(1.0f);
     }
 
     if (initializeStencilBuffer) {
@@ -1800,19 +1812,42 @@ bool WebGLContext::TexImageFromVideoElem
         tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, format, type, WebGLImageDataStatus::InitializedImageData);
         tex->Bind(TexImageTargetToTexTarget(texImageTarget));
     }
     srcImage = nullptr;
     container->UnlockCurrentImage();
     return ok;
 }
 
-//
+////////////////////////////////////////////////////////////////////////////////
+
+
+WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
+    : mWebGL(webgl)
+    , mNeedsChange(NeedsChange(webgl))
+{
+    if (mNeedsChange) {
+        mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
+                              mWebGL.mColorWriteMask[1],
+                              mWebGL.mColorWriteMask[2],
+                              false);
+    }
+}
+
+WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround()
+{
+    if (mNeedsChange) {
+        mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
+                              mWebGL.mColorWriteMask[1],
+                              mWebGL.mColorWriteMask[2],
+                              mWebGL.mColorWriteMask[3]);
+    }
+}
+////////////////////////////////////////////////////////////////////////////////
 // XPCOM goop
-//
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
   mCanvasElement,
   mExtensions,
   mBound2DTextures,
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1322,16 +1322,32 @@ protected:
     int mAlreadyGeneratedWarnings;
     int mMaxWarnings;
     bool mAlreadyWarnedAboutFakeVertexAttrib0;
 
     bool ShouldGenerateWarnings() const;
 
     uint64_t mLastUseIndex;
 
+    bool mNeedsFakeNoAlpha;
+
+    struct ScopedMaskWorkaround {
+        WebGLContext& mWebGL;
+        const bool mNeedsChange;
+
+        static bool NeedsChange(WebGLContext& webgl) {
+            return webgl.mNeedsFakeNoAlpha &&
+                   webgl.mColorWriteMask[3] != false;
+        }
+
+        ScopedMaskWorkaround(WebGLContext& webgl);
+
+        ~ScopedMaskWorkaround();
+    };
+
     void LoseOldestWebGLContextIfLimitExceeded();
     void UpdateLastUseIndex();
 
     template <typename WebGLObjectType>
     JS::Value WebGLObjectAsJSValue(JSContext *cx, const WebGLObjectType *, ErrorResult& rv) const;
     template <typename WebGLObjectType>
     JSObject* WebGLObjectAsJSObject(JSContext *cx, const WebGLObjectType *, ErrorResult& rv) const;
 
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -129,17 +129,21 @@ WebGLContext::DrawArrays(GLenum mode, GL
 
     if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
         return;
 
     if (!DrawArrays_check(first, count, 1, "drawArrays"))
         return;
 
     RunContextLossTimer();
-    gl->fDrawArrays(mode, first, count);
+
+    {
+        ScopedMaskWorkaround autoMask(*this);
+        gl->fDrawArrays(mode, first, count);
+    }
 
     Draw_cleanup();
 }
 
 void
 WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
 {
     if (IsContextLost())
@@ -147,17 +151,21 @@ WebGLContext::DrawArraysInstanced(GLenum
 
     if (!ValidateDrawModeEnum(mode, "drawArraysInstanced: mode"))
         return;
 
     if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
         return;
 
     RunContextLossTimer();
-    gl->fDrawArraysInstanced(mode, first, count, primcount);
+
+    {
+        ScopedMaskWorkaround autoMask(*this);
+        gl->fDrawArraysInstanced(mode, first, count, primcount);
+    }
 
     Draw_cleanup();
 }
 
 bool
 WebGLContext::DrawElements_check(GLsizei count, GLenum type,
                                  WebGLintptr byteOffset, GLsizei primcount,
                                  const char* info, GLuint* out_upperBound)
@@ -308,43 +316,56 @@ WebGLContext::DrawElements(GLenum mode, 
     if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
                             &upperBound))
     {
         return;
     }
 
     RunContextLossTimer();
 
-    if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
-        gl->fDrawRangeElements(mode, 0, upperBound,
-                               count, type, reinterpret_cast<GLvoid*>(byteOffset));
-    } else {
-        gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
+    {
+        ScopedMaskWorkaround autoMask(*this);
+
+        if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
+            gl->fDrawRangeElements(mode, 0, upperBound, count, type,
+                                   reinterpret_cast<GLvoid*>(byteOffset));
+        } else {
+            gl->fDrawElements(mode, count, type,
+                              reinterpret_cast<GLvoid*>(byteOffset));
+        }
     }
 
     Draw_cleanup();
 }
 
 void
 WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
                                     WebGLintptr byteOffset, GLsizei primcount)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
         return;
 
     GLuint upperBound = 0;
-    if (!DrawElements_check(count, type, byteOffset, primcount, "drawElementsInstanced",
-                            &upperBound))
+    if (!DrawElements_check(count, type, byteOffset, primcount,
+                            "drawElementsInstanced", &upperBound))
+    {
         return;
+    }
 
     RunContextLossTimer();
-    gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
+
+    {
+        ScopedMaskWorkaround autoMask(*this);
+        gl->fDrawElementsInstanced(mode, count, type,
+                                   reinterpret_cast<GLvoid*>(byteOffset),
+                                   primcount);
+    }
 
     Draw_cleanup();
 }
 
 void WebGLContext::Draw_cleanup()
 {
     UndoFakeVertexAttrib0();
     UnbindFakeBlackTextures();
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -35,18 +35,20 @@ WebGLContext::Clear(GLbitfield mask)
 
         gl->fClear(mask);
         return;
     } else {
         ClearBackbufferIfNeeded();
     }
 
     // Ok, we're clearing the default framebuffer/screen.
-
-    gl->fClear(mask);
+    {
+        ScopedMaskWorkaround autoMask(*this);
+        gl->fClear(mask);
+    }
 
     Invalidate();
     mShouldPresent = true;
 }
 
 static GLclampf
 GLClampFloat(GLclampf val)
 {
--- a/dom/events/test/test_all_synthetic_events.html
+++ b/dom/events/test/test_all_synthetic_events.html
@@ -97,16 +97,20 @@ const kEventConstructors = {
                                              },
   CompositionEvent:                          { create: function (aName, aProps) {
                                                          var e = document.createEvent("compositionevent");
                                                          e.initCompositionEvent(aName, aProps.bubbles, aProps.cancelable,
                                                                                 aProps.view, aProps.data, aProps.locale);
                                                          return e;
                                                        },
                                              },
+  CSSFontFaceLoadEvent:                      { create: function (aName, aProps) {
+                                                         return new CSSFontFaceLoadEvent(aName, aProps);
+                                                       },
+                                             },
   CustomEvent:                               { create: function (aName, aProps) {
                                                          return new CustomEvent(aName, aProps);
                                                        },
                                              },
   DataErrorEvent:                            { create: function (aName, aProps) {
                                                           return new DataErrorEvent(aName, aProps);
                                                        },
                                              },
--- a/dom/imptests/failures/html/dom/test_historical.html.json
+++ b/dom/imptests/failures/html/dom/test_historical.html.json
@@ -3,11 +3,10 @@
   "Historical DOM features must be removed: createCDATASection": true,
   "Historical DOM features must be removed: createAttribute": true,
   "Historical DOM features must be removed: createAttributeNS": true,
   "Historical DOM features must be removed: inputEncoding": true,
   "Historical DOM features must be removed: getAttributeNode": true,
   "Historical DOM features must be removed: getAttributeNodeNS": true,
   "Historical DOM features must be removed: setAttributeNode": true,
   "Historical DOM features must be removed: removeAttributeNode": true,
-  "DocumentType member must be nuked: internalSubset": true,
-  "Node member must be nuked: hasAttributes": true
+  "DocumentType member must be nuked: internalSubset": true
 }
--- a/dom/interfaces/core/nsIDOMAttr.idl
+++ b/dom/interfaces/core/nsIDOMAttr.idl
@@ -9,17 +9,17 @@
  * The nsIDOMAttr interface represents an attribute in an "Element" object. 
  * Typically the allowable values for the attribute are defined in a document 
  * type definition.
  * 
  * For more information on this interface please see 
  * http://www.w3.org/TR/DOM-Level-2-Core/
  */
 
-[builtinclass, uuid(93bf61ba-9ffa-42b7-9594-2de803c9627c)]
+[builtinclass, uuid(7d0582bd-09a7-430e-969b-054abbea19fe)]
 interface nsIDOMAttr : nsIDOMNode
 {
   readonly attribute DOMString            name;
   readonly attribute boolean              specified;
            attribute DOMString            value;
                                             // raises(DOMException) on setting
 
   // Introduced in DOM Level 2:
--- a/dom/interfaces/core/nsIDOMCDATASection.idl
+++ b/dom/interfaces/core/nsIDOMCDATASection.idl
@@ -10,12 +10,12 @@
  * that would otherwise be regarded as markup.
  * Their primary purpose is for including material such as XML fragments, 
  * without needing to escape all the delimiters.
  * 
  * For more information on this interface please see 
  * http://www.w3.org/TR/DOM-Level-2-Core/
  */
 
-[uuid(864c4e6a-3933-4f8a-8dd8-3883be60ea10)]
+[uuid(4ac42d40-69b7-4506-b730-c41ec74b74bd)]
 interface nsIDOMCDATASection : nsIDOMText
 {
 };
--- a/dom/interfaces/core/nsIDOMCharacterData.idl
+++ b/dom/interfaces/core/nsIDOMCharacterData.idl
@@ -8,17 +8,17 @@
 /**
  * The nsIDOMCharacterData interface extends nsIDOMNode with a set of 
  * attributes and methods for accessing character data in the DOM.
  * 
  * For more information on this interface please see 
  * http://www.w3.org/TR/DOM-Level-2-Core/
  */
 
-[uuid(7b1b8719-6669-4614-bf96-93ddf7966f64)]
+[uuid(844b8e7e-6d37-4fa1-8196-86e3afdfa0ca)]
 interface nsIDOMCharacterData : nsIDOMNode
 {
            attribute DOMString            data;
                                   // raises(DOMException) on setting
                                   // raises(DOMException) on retrieval
 
   readonly attribute unsigned long        length;
   DOMString                 substringData(in unsigned long offset, 
--- a/dom/interfaces/core/nsIDOMComment.idl
+++ b/dom/interfaces/core/nsIDOMComment.idl
@@ -9,12 +9,12 @@
  * The nsIDOMComment interface inherits from nsIDOMCharacterData and represents 
  * the content of a comment, i.e., all the characters between the starting 
  * '<!--' and ending '-->'.
  * 
  * For more information on this interface please see 
  * http://www.w3.org/TR/DOM-Level-2-Core/
  */
 
-[uuid(8edde4d9-dc26-492c-8477-2be0f95088ad)]
+[uuid(c1a1d2ea-e106-4ee8-806d-2633468e8098)]
 interface nsIDOMComment : nsIDOMCharacterData
 {
 };
--- a/dom/interfaces/core/nsIDOMDocument.idl
+++ b/dom/interfaces/core/nsIDOMDocument.idl
@@ -27,17 +27,17 @@ interface nsIDOMLocation;
  * cannot exist outside the context of a Document, the nsIDOMDocument 
  * interface also contains the factory methods needed to create these 
  * objects.
  *
  * For more information on this interface please see 
  * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
  */
 
-[uuid(950ca868-e09f-4a7d-9b87-e4ec9aedb3e5)]
+[uuid(08c6400b-0b6d-4ce6-b88d-e7a15a9c7c03)]
 interface nsIDOMDocument : nsIDOMNode
 {
   readonly attribute nsIDOMDocumentType         doctype;
   readonly attribute nsIDOMDOMImplementation    implementation;
   readonly attribute nsIDOMElement              documentElement;
   nsIDOMElement                 createElement([Null(Stringify)] in DOMString tagName)
                                   raises(DOMException);
   nsIDOMDocumentFragment        createDocumentFragment();
--- a/dom/interfaces/core/nsIDOMDocumentFragment.idl
+++ b/dom/interfaces/core/nsIDOMDocumentFragment.idl
@@ -9,17 +9,17 @@
  * DocumentFragment is a "lightweight" or "minimal" Document object.
  * nsIDOMDocumentFragment is used in situations where the Document
  * interface can potentially be a heavyweight interface.
  *
  * For more information on this interface please see 
  * http://www.w3.org/TR/DOM-Level-2-Core/
  */
 
-[builtinclass, uuid(5c601878-5b77-4f88-9425-3fe8d2dc8813)]
+[builtinclass, uuid(24b34c61-7326-42d4-87ec-5d3b5c0b1b26)]
 interface nsIDOMDocumentFragment : nsIDOMNode
 {
   /**
    * Return nodes that match a given CSS selector.
    *
    * @see <http://dev.w3.org/2006/webapi/selectors-api/>
    */
   nsIDOMElement querySelector([Null(Stringify)] in DOMString selectors);
--- a/dom/interfaces/core/nsIDOMDocumentType.idl
+++ b/dom/interfaces/core/nsIDOMDocumentType.idl
@@ -10,17 +10,17 @@
  * or a DocumentType object. 
  * The nsIDOMDocumentType interface in the DOM Core provides an 
  * interface to the list of entities that are defined for the document.
  *
  * For more information on this interface please see 
  * http://www.w3.org/TR/DOM-Level-2-Core/
  */
 
-[uuid(55fe2f3f-35e8-4cb0-b39d-bea1bd0061c7)]
+[uuid(23c1f549-d40b-49b8-992e-2a1136afa13f)]
 interface nsIDOMDocumentType : nsIDOMNode
 {
   readonly attribute  DOMString            name;
   readonly attribute  DOMString            publicId;
   readonly attribute  DOMString            systemId;
   readonly attribute  DOMString            internalSubset;
 
   [binaryname(MozRemove)]
--- a/dom/interfaces/core/nsIDOMElement.idl
+++ b/dom/interfaces/core/nsIDOMElement.idl
@@ -10,17 +10,17 @@ interface nsIDOMMozNamedAttrMap;
 /**
  * The nsIDOMElement interface represents an element in an HTML or 
  * XML document. 
  *
  * For more information on this interface please see 
  * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-element
  */
 
-[uuid(ea94c5e2-5d5d-4afe-b3ab-431903797f31)]
+[uuid(59eb63f9-c8c0-41d2-bf73-739de43b17f9)]
 interface nsIDOMElement : nsIDOMNode
 {
   readonly attribute DOMString        tagName;
 
            attribute DOMString        id;
            attribute DOMString        className;
   /**
    * Returns a DOMTokenList object reflecting the class attribute.
@@ -37,16 +37,17 @@ interface nsIDOMElement : nsIDOMNode
                                     in DOMString qualifiedName, 
                                     in DOMString value);
   void               removeAttribute(in DOMString name);
   void               removeAttributeNS(in DOMString namespaceURI, 
                                        in DOMString localName);
   boolean            hasAttribute(in DOMString name);
   boolean            hasAttributeNS(in DOMString namespaceURI, 
                                     in DOMString localName);
+  boolean            hasAttributes();
 
   // Obsolete methods.
   nsIDOMAttr         getAttributeNode(in DOMString name);
   nsIDOMAttr         setAttributeNode(in nsIDOMAttr newAttr);
   nsIDOMAttr         removeAttributeNode(in nsIDOMAttr oldAttr);
   nsIDOMAttr         getAttributeNodeNS(in DOMString namespaceURI, 
                                         in DOMString localName);
   nsIDOMAttr         setAttributeNodeNS(in nsIDOMAttr newAttr)
--- a/dom/interfaces/core/nsIDOMNode.idl
+++ b/dom/interfaces/core/nsIDOMNode.idl
@@ -11,17 +11,17 @@ interface nsIVariant;
  * The nsIDOMNode interface is the primary datatype for the entire 
  * Document Object Model.
  * It represents a single node in the document tree.
  *
  * For more information on this interface please see 
  * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
  */
 
-[uuid(3eef1ab9-2f87-4eda-9bb9-469c37294f72)]
+[uuid(238222a9-7aa5-4804-9f86-484853ce4b15)]
 interface nsIDOMNode : nsISupports
 {
   const unsigned short      ELEMENT_NODE       = 1;
   const unsigned short      ATTRIBUTE_NODE     = 2;
   const unsigned short      TEXT_NODE          = 3;
   const unsigned short      CDATA_SECTION_NODE = 4;
   const unsigned short      ENTITY_REFERENCE_NODE = 5;
   const unsigned short      ENTITY_NODE        = 6;
@@ -63,18 +63,16 @@ interface nsIDOMNode : nsISupports
   void                      normalize();
   // Introduced in DOM Level 2:
   readonly attribute DOMString        namespaceURI;
   // Modified in DOM Core
   readonly attribute DOMString        prefix;
 
   // Introduced in DOM Level 2:
   readonly attribute DOMString        localName;
-  // Introduced in DOM Level 2:
-  boolean            hasAttributes();
 
   // Introduced in DOM Level 3:
   // This uses a binaryname to avoid warnings due to name collision with
   // nsINode::GetBaseURI
   [binaryname(DOMBaseURI)] readonly attribute DOMString baseURI;
 
   // DocumentPosition
   const unsigned short      DOCUMENT_POSITION_DISCONNECTED = 0x01;
--- a/dom/interfaces/core/nsIDOMProcessingInstruction.idl
+++ b/dom/interfaces/core/nsIDOMProcessingInstruction.idl
@@ -10,13 +10,13 @@
  * "processing instruction", used in XML as a way to keep processor-specific 
  * information in the text of the document.
  *
  * For more information on this interface please see 
  * http://www.w3.org/TR/DOM-Level-2-Core/ and
  * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
  */
 
-[uuid(ca632936-4c6b-48b4-9920-fbe1e3710802)]
+[uuid(d0163f44-8f5b-4234-b3aa-43cab64e2039)]
 interface nsIDOMProcessingInstruction : nsIDOMCharacterData
 {
   readonly attribute DOMString        target;
 };
--- a/dom/interfaces/core/nsIDOMText.idl
+++ b/dom/interfaces/core/nsIDOMText.idl
@@ -8,17 +8,17 @@
 /**
  * The nsIDOMText interface inherits from nsIDOMCharacterData and represents 
  * the textual content (termed character data in XML) of an Element or Attr.
  *
  * For more information on this interface please see 
  * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
  */
 
-[uuid(b16d449b-60f1-444a-a7e5-dc50a5d0ffad)]
+[uuid(775bbd26-1581-4e54-b82c-5d9dc5a3363b)]
 interface nsIDOMText : nsIDOMCharacterData
 {
   nsIDOMText                      splitText(in unsigned long offset)
                                        raises(DOMException);
 
   /**
    * The concatenation of all logically adjacent text nodes with this text
    * node, where "logically adjacent" consists of all text nodes which can be
--- a/dom/interfaces/core/nsIDOMXMLDocument.idl
+++ b/dom/interfaces/core/nsIDOMXMLDocument.idl
@@ -1,16 +1,16 @@
 /* -*- 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 "nsIDOMDocument.idl"
 
-[uuid(dc767223-838f-4ca2-9f4c-ae685862d1df)]
+[uuid(1d54e44a-2012-4567-805d-bd5455fc6421)]
 interface nsIDOMXMLDocument : nsIDOMDocument
 {
   // DOM Level 3 Load & Save, DocumentLS
   // http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS
   /**
    * Whether to load synchronously or asynchronously.
    * The default is async==true.
    */
--- a/dom/interfaces/html/nsIDOMHTMLDocument.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDocument.idl
@@ -8,17 +8,17 @@
 /**
  * The nsIDOMHTMLDocument interface is the interface to a [X]HTML
  * document object.
  *
  * @see <http://www.whatwg.org/html/>
  */
 interface nsISelection;
 
-[uuid(b7fcb58a-9ad5-44b5-8c6f-b7181c249413)]
+[uuid(abf369fb-a8b2-4fba-95f5-9e4a896e40a8)]
 interface nsIDOMHTMLDocument : nsIDOMDocument
 {
            attribute DOMString            domain;
            attribute DOMString            cookie;
 
   readonly attribute nsIDOMHTMLHeadElement head;
            attribute nsIDOMHTMLElement    body;
 
--- a/dom/interfaces/html/nsIDOMHTMLElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLElement.idl
@@ -14,17 +14,17 @@ interface nsIDOMHTMLMenuElement;
  * tree.
  *
  * 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(2728c077-9ecc-4a75-ac95-16fbfcb007df)]
+[uuid(8c9472c2-785a-40b6-ad47-4d98e64562bd)]
 interface nsIDOMHTMLElement : nsIDOMElement
 {
   // metadata attributes
            attribute DOMString        title;
            attribute DOMString        lang;
            attribute DOMString        dir;
   readonly attribute nsISupports      dataset;
 
--- a/dom/interfaces/svg/nsIDOMSVGElement.idl
+++ b/dom/interfaces/svg/nsIDOMSVGElement.idl
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDOMElement.idl"
 
 interface nsIDOMCSSStyleDeclaration;
 interface nsIDOMCSSValue;
 
 
-[uuid(7a11697a-668b-4a6e-a44a-909abffee230)]
+[uuid(6618074e-0c77-4fec-8870-a6f79aa79b07)]
 interface nsIDOMSVGElement : nsIDOMElement
 {
             // raises DOMException on setting
   readonly attribute nsIDOMSVGElement    ownerSVGElement;
   readonly attribute nsIDOMSVGElement    viewportElement;
 
   [binaryname(SVGClassName)]
   readonly attribute nsISupports   className;
--- a/dom/interfaces/xul/nsIDOMXULDocument.idl
+++ b/dom/interfaces/xul/nsIDOMXULDocument.idl
@@ -5,17 +5,17 @@
 
 #include "domstubs.idl"
 #include "nsIDOMDocument.idl"
 
 interface nsIDOMXULCommandDispatcher;
 interface nsIObserver;
 interface nsIBoxObject;
 
-[uuid(546c658e-805f-4293-9738-6e6a00d75839)]
+[uuid(6f932360-ae43-4fa7-9200-66f64e05a356)]
 interface nsIDOMXULDocument : nsIDOMDocument
 {
   attribute nsIDOMNode                          popupNode;
 
   /**
    * These attributes correspond to trustedGetPopupNode().rangeOffset and
    * rangeParent. They will help you find where in the DOM the popup is
    * happening. Can be accessed from chrome only, and only during a popup
--- a/dom/interfaces/xul/nsIDOMXULElement.idl
+++ b/dom/interfaces/xul/nsIDOMXULElement.idl
@@ -7,17 +7,17 @@
 
 interface nsIRDFCompositeDataSource;
 interface nsIXULTemplateBuilder;
 interface nsIRDFResource;
 interface nsIControllers;
 interface nsIBoxObject;
 
 
-[uuid(1bd9303d-0854-4ed3-9fda-added29a570e)]
+[uuid(ef62515d-3160-4463-abd7-fc9b7385ecef)]
 interface nsIDOMXULElement : nsIDOMElement
 {
   // Layout properties
   attribute DOMString align;
   attribute DOMString dir;
   attribute DOMString flex;
   attribute DOMString flexGroup;
   attribute DOMString ordinal;
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1572,41 +1572,43 @@ MediaManager::NotifyRecordingStatusChang
 }
 
 /**
  * The entry point for this file. A call from Navigator::mozGetUserMedia
  * will end up here. MediaManager is a singleton that is responsible
  * for handling all incoming getUserMedia calls from every window.
  */
 nsresult
-MediaManager::GetUserMedia(bool aPrivileged,
+MediaManager::GetUserMedia(
   nsPIDOMWindow* aWindow, const MediaStreamConstraints& aConstraints,
   nsIDOMGetUserMediaSuccessCallback* aOnSuccess,
   nsIDOMGetUserMediaErrorCallback* aOnError)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aOnError, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
 
+  bool privileged = nsContentUtils::IsChromeDoc(aWindow->GetExtantDoc());
+
   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess(aOnSuccess);
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError);
 
   MediaStreamConstraints c(aConstraints); // copy
 
   /**
    * If we were asked to get a picture, before getting a snapshot, we check if
    * the calling page is allowed to open a popup. We do this because
    * {picture:true} will open a new "window" to let the user preview or select
    * an image, on Android. The desktop UI for {picture:true} is TBD, at which
    * may point we can decide whether to extend this test there as well.
    */
 #if !defined(MOZ_WEBRTC)
-  if (c.mPicture && !aPrivileged) {
+  if (c.mPicture && !privileged) {
     if (aWindow->GetPopupControlState() > openControlled) {
       nsCOMPtr<nsIPopupWindowManager> pm =
         do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
       if (!pm) {
         return NS_OK;
       }
       uint32_t permission;
       nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
@@ -1648,17 +1650,17 @@ MediaManager::GetUserMedia(bool aPrivile
   GetUserMediaCallbackMediaStreamListener* listener =
     new GetUserMediaCallbackMediaStreamListener(mMediaThread, windowID);
 
   // No need for locking because we always do this in the main thread.
   listeners->AppendElement(listener);
 
   // Developer preference for turning off permission check.
   if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
-    aPrivileged = true;
+    privileged = true;
   }
   if (!Preferences::GetBool("media.navigator.video.enabled", true)) {
     c.mVideo.SetAsBoolean() = false;
   }
 
 #if defined(ANDROID) || defined(MOZ_WIDGET_GONK)
   // Be backwards compatible only on mobile and only for facingMode.
   if (c.mVideo.IsMediaTrackConstraints()) {
@@ -1676,17 +1678,17 @@ MediaManager::GetUserMedia(bool aPrivile
           n.mFacingMode.Construct(tc.mOptional.Value()[i].mFacingMode.Value());
           tc.mAdvanced.Value().AppendElement(n);
         }
       }
     }
   }
 #endif
 
-  if (c.mVideo.IsMediaTrackConstraints() && !aPrivileged) {
+  if (c.mVideo.IsMediaTrackConstraints() && !privileged) {
     auto& tc = c.mVideo.GetAsMediaTrackConstraints();
     // only allow privileged content to set the window id
     if (tc.mBrowserWindow.WasPassed()) {
       tc.mBrowserWindow.Construct(-1);
     }
 
     if (tc.mAdvanced.WasPassed()) {
       uint32_t length = tc.mAdvanced.Value().Length();
@@ -1733,17 +1735,17 @@ MediaManager::GetUserMedia(bool aPrivile
 #if defined(XP_MACOSX)
             !nsCocoaFeatures::OnLionOrLater()
 #endif
 #if defined (XP_WIN)
             !IsVistaOrLater()
 #endif
            ) ||
 #endif
-          (!aPrivileged && !HostHasPermission(*docURI))) {
+          (!privileged && !HostHasPermission(*docURI))) {
         return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
       }
     }
   }
 
 #ifdef MOZ_B2G_CAMERA
   if (mCameraManager == nullptr) {
     mCameraManager = nsDOMCameraManager::CreateInstance(aWindow);
@@ -1762,21 +1764,21 @@ MediaManager::GetUserMedia(bool aPrivile
   bool isLoop = false;
   nsCOMPtr<nsIURI> loopURI;
   nsresult rv = NS_NewURI(getter_AddRefs(loopURI), "about:loopconversation");
   NS_ENSURE_SUCCESS(rv, rv);
   rv = docURI->EqualsExceptRef(loopURI, &isLoop);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (isLoop) {
-    aPrivileged = true;
+    privileged = true;
   }
 
   // XXX No full support for picture in Desktop yet (needs proper UI)
-  if (aPrivileged ||
+  if (privileged ||
       (c.mFake && !Preferences::GetBool("media.navigator.permission.fake"))) {
     MediaManager::GetMessageLoop()->PostTask(FROM_HERE, task.forget());
   } else {
     bool isHTTPS = false;
     if (docURI) {
       docURI->SchemeIs("https", &isHTTPS);
     }
 
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -1,12 +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/. */
 
+#ifndef MOZILLA_MEDIAMANAGER_H
+#define MOZILLA_MEDIAMANAGER_H
+
 #include "MediaEngine.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "nsIMediaManager.h"
 
 #include "nsHashKeys.h"
 #include "nsGlobalWindow.h"
 #include "nsClassHashtable.h"
@@ -569,19 +572,19 @@ public:
   void RemoveWindowID(uint64_t aWindowId);
   bool IsWindowStillActive(uint64_t aWindowId) {
     return !!GetWindowListeners(aWindowId);
   }
   // Note: also calls aListener->Remove(), even if inactive
   void RemoveFromWindowList(uint64_t aWindowID,
     GetUserMediaCallbackMediaStreamListener *aListener);
 
-  nsresult GetUserMedia(bool aPrivileged,
+  nsresult GetUserMedia(
     nsPIDOMWindow* aWindow,
-    const dom::MediaStreamConstraints& aRawConstraints,
+    const dom::MediaStreamConstraints& aConstraints,
     nsIDOMGetUserMediaSuccessCallback* onSuccess,
     nsIDOMGetUserMediaErrorCallback* onError);
 
   nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
     const dom::MediaStreamConstraints& aConstraints,
     nsIGetUserMediaDevicesSuccessCallback* onSuccess,
     nsIDOMGetUserMediaErrorCallback* onError,
     uint64_t aInnerWindowID = 0);
@@ -627,8 +630,10 @@ private:
   static StaticRefPtr<MediaManager> sSingleton;
 
 #ifdef MOZ_B2G_CAMERA
   nsRefPtr<nsDOMCameraManager> mCameraManager;
 #endif
 };
 
 } // namespace mozilla
+
+#endif // MOZILLA_MEDIAMANAGER_H
--- a/dom/settings/SettingsRequestManager.jsm
+++ b/dom/settings/SettingsRequestManager.jsm
@@ -678,17 +678,21 @@ let SettingsRequestManager = {
   broadcastMessage: function broadcastMessage(aMsgName, aContent) {
     if (DEBUG) debug("Broadcast");
     this.children.forEach(function(msgMgr) {
       let principal = this.mmPrincipals.get(msgMgr);
       if (!principal) {
         if (DEBUG) debug("Cannot find principal for message manager to check permissions");
       }
       else if (SettingsPermissions.hasReadPermission(principal, aContent.key)) {
-        msgMgr.sendAsyncMessage(aMsgName, aContent);
+        try {
+          msgMgr.sendAsyncMessage(aMsgName, aContent);
+        } catch (e) {
+          if (DEBUG) debug("Failed sending message: " + aMsgName);
+        }
       }
     }.bind(this));
     if (DEBUG) debug("Finished Broadcasting");
   },
 
   addObserver: function(aMsgMgr, aPrincipal) {
     if (DEBUG) debug("Add observer for " + aPrincipal.origin);
     if (this.children.indexOf(aMsgMgr) == -1) {
--- a/dom/tests/mochitest/dom-level2-core/exclusions.js
+++ b/dom/tests/mochitest/dom-level2-core/exclusions.js
@@ -22,17 +22,17 @@ dtdTests = ["attrgetownerelement01", "do
             "prefix08", "removeAttributeNS01", "removeAttributeNS02",
             "removeNamedItemNS03", "setAttributeNodeNS02", "setAttributeNS03",
             "setNamedItemNS04"];
 
 bug371552 = ["elementhasattributens02"];
 wrongDocError = ["elementsetattributenodens05", "namednodemapsetnameditemns03",
                  "setAttributeNodeNS05", "setNamedItemNS02"];
 attrExodus = ["elementsetattributenodens06", "importNode01",
-              "hc_namednodemapinvalidtype1"];
+              "hc_namednodemapinvalidtype1", "nodehasattributes02"];
 bogusPrefix = ["nodesetprefix05", "nodesetprefix09", "prefix06", "prefix07"];
 prefixReplacement = ["setAttributeNodeNS04"];
 
 function concat(lst/*...*/) {
   var f = [];
   if (arguments !== null) {
     f = arguments[0];
   }
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -250,16 +250,18 @@ var interfaceNamesInGlobalScope =
     "CSS2Properties",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSCharsetRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSConditionRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSCounterStyleRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "CSSFontFaceLoadEvent", pref: "layout.css.font-loading-api.enabled"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSFontFaceRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSFontFeatureValuesRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSGroupingRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSImportRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
@@ -394,16 +396,20 @@ var interfaceNamesInGlobalScope =
     "FileReader",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "FMRadio", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FocusEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FormData",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "FontFace", pref: "layout.css.font-loading-api.enabled"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "FontFaceSet", pref: "layout.css.font-loading-api.enabled"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "GainNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Gamepad", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "GamepadAxisMoveEvent", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "GamepadButtonEvent", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/tests/mochitest/notification/NotificationTest.js
+++ b/dom/tests/mochitest/notification/NotificationTest.js
@@ -4,16 +4,17 @@ var NotificationTest = (function () {
   function info(msg, name) {
     SimpleTest.info("::Notification Tests::" + (name || ""), msg);
   }
 
   function setup_testing_env() {
     SimpleTest.waitForExplicitFinish();
     // turn on testing pref (used by notification.cpp, and mock the alerts
     SpecialPowers.setBoolPref("notification.prompt.testing", true);
+    SpecialPowers.setAllAppsLaunchable(true);
   }
 
   function teardown_testing_env() {
     SimpleTest.finish();
   }
 
   function executeTests(tests, callback) {
     // context is `this` object in test functions
--- a/dom/webidl/Animation.webidl
+++ b/dom/webidl/Animation.webidl
@@ -9,10 +9,13 @@
  * Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [Pref="dom.animations-api.core.enabled"]
 interface Animation {
   // FIXME: |effect| should have type (AnimationEffect or EffectCallback)?
   // but we haven't implemented EffectCallback yet.
-  [Cached,Pure] readonly attribute AnimationEffect? effect;
+  [Cached,Pure]
+  readonly attribute AnimationEffect? effect;
+  // FIXME: This should be writeable (bug 1067769)
+  readonly attribute Element?         target;
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSFontFaceLoadEvent.webidl
@@ -0,0 +1,21 @@
+/* -*- 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/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/csswg/css-font-loading/#FontFaceSet-interface
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+dictionary CSSFontFaceLoadEventInit : EventInit {
+  sequence<FontFace> fontfaces = [];
+};
+
+[Constructor(DOMString type, optional CSSFontFaceLoadEventInit eventInitDict),
+ Pref="layout.css.font-loading-api.enabled"]
+interface CSSFontFaceLoadEvent : Event {
+  [Cached, Constant] readonly attribute sequence<FontFace> fontfaces;
+};
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -356,8 +356,9 @@ partial interface Document {
 };
 
 Document implements XPathEvaluator;
 Document implements GlobalEventHandlers;
 Document implements TouchEventHandlers;
 Document implements ParentNode;
 Document implements OnErrorEventHandlerForNodes;
 Document implements GeometryUtils;
+Document implements FontFaceSource;
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -46,16 +46,18 @@ interface Element : Node {
   [Throws]
   void removeAttribute(DOMString name);
   [Throws]
   void removeAttributeNS(DOMString? namespace, DOMString localName);
   [Pure]
   boolean hasAttribute(DOMString name);
   [Pure]
   boolean hasAttributeNS(DOMString? namespace, DOMString localName);
+  [Pure]
+  boolean hasAttributes();
 
   [Throws, Pure]
   Element? closest(DOMString selector);
 
   [Throws, Pure]
   boolean matches(DOMString selector);
 
   [Pure]
new file mode 100644
--- /dev/null
+++ b/dom/webidl/FontFace.webidl
@@ -0,0 +1,48 @@
+/* -*- 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/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/csswg/css-font-loading/#fontface-interface
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+typedef (ArrayBuffer or ArrayBufferView) BinaryData;
+
+dictionary FontFaceDescriptors {
+  DOMString style = "normal";
+  DOMString weight = "normal";
+  DOMString stretch = "normal";
+  DOMString unicodeRange = "U+0-10FFFF";
+  DOMString variant = "normal";
+  DOMString featureSettings = "normal";
+};
+
+enum FontFaceLoadStatus { "unloaded", "loading", "loaded", "error" };
+
+// Bug 1072107 is for exposing this in workers.
+// [Exposed=(Window,Worker)]
+[Constructor(DOMString family,
+             (DOMString or BinaryData) source,
+             optional FontFaceDescriptors descriptors),
+ Pref="layout.css.font-loading-api.enabled"]
+interface FontFace {
+  [SetterThrows] attribute DOMString family;
+  [SetterThrows] attribute DOMString style;
+  [SetterThrows] attribute DOMString weight;
+  [SetterThrows] attribute DOMString stretch;
+  [SetterThrows] attribute DOMString unicodeRange;
+  [SetterThrows] attribute DOMString variant;
+  [SetterThrows] attribute DOMString featureSettings;
+
+  readonly attribute FontFaceLoadStatus status;
+
+  [Throws]
+  Promise<FontFace> load();
+
+  [Throws]
+  readonly attribute Promise<FontFace> loaded;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/FontFaceSet.webidl
@@ -0,0 +1,63 @@
+/* -*- 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/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/csswg/css-font-loading/#FontFaceSet-interface
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+enum FontFaceSetLoadStatus { "loading", "loaded" };
+
+// Bug 1072762 is for the FontFaceSet constructor.
+// [Constructor(sequence<FontFace> initialFaces)]
+[Pref="layout.css.font-loading-api.enabled"]
+interface FontFaceSet : EventTarget {
+
+  // Emulate the Set interface, until we can extend Set correctly.
+  // Implementing these commented out operations and the iterator is
+  // bug 1072101.
+  // readonly attribute unsigned long size;
+  [Throws] void add(FontFace font);
+  boolean has(FontFace font);
+  [Throws] boolean delete(FontFace font);
+  void clear();
+  // Iterator entries();
+  // Iterator keys();
+  // Iterator values();
+  // void forEach(ForEachCallback cb, optional any thisArg);
+  // FontFace iterator;
+
+  // -- events for when loading state changes
+  attribute EventHandler onloading;
+  attribute EventHandler onloadingdone;
+  attribute EventHandler onloadingerror;
+
+  // check and start loads if appropriate
+  // and fulfill promise when all loads complete
+  // Not implemented yet: bug 1072102.
+  [Throws] Promise<sequence<FontFace>> load(DOMString font, optional DOMString text = " ");
+
+  // return whether all fonts in the fontlist are loaded
+  // (does not initiate load if not available)
+  // Not implemented yet: bug 1072102.
+  // [Throws] boolean check(DOMString font, optional DOMString text = " ");
+
+  // async notification that font loading and layout operations are done
+  [Throws] readonly attribute Promise<void> ready;
+
+  // loading state, "loading" while one or more fonts loading, "loaded" otherwise
+  readonly attribute FontFaceSetLoadStatus status;
+};
+
+// This provides access to the FontFace objects in the FontFaceSet until we
+// get iterators working (bug 1072101).  Don't enable the pref for the CSS Font
+// Loading API until the iterator is available, as we don't want to expose more
+// indexed properties on the Web.
+partial interface FontFaceSet {
+  getter FontFace (unsigned long index);
+  readonly attribute unsigned long length;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/FontFaceSource.webidl
@@ -0,0 +1,18 @@
+/* -*- 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/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/csswg/css-font-loading/#font-face-source
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[NoInterfaceObject]
+interface FontFaceSource {
+
+  [Throws, Pref="layout.css.font-loading-api.enabled"]
+  readonly attribute FontFaceSet fonts;
+};
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -96,18 +96,16 @@ interface Node : EventTarget {
   // a non-nullable type.
   [Constant]
   readonly attribute DOMString? namespaceURI;
   [Constant]
   readonly attribute DOMString? prefix;
   [Constant]
   readonly attribute DOMString? localName;
 
-  [Pure]
-  boolean hasAttributes();
   [Throws, Func="IsChromeOrXBL"]
   any setUserData(DOMString key, any data);
   [Throws, Func="IsChromeOrXBL"]
   any getUserData(DOMString key);
   [ChromeOnly]
   readonly attribute Principal nodePrincipal;
   [ChromeOnly]
   readonly attribute URI? baseURIObject;
--- a/dom/webidl/WorkerGlobalScope.webidl
+++ b/dom/webidl/WorkerGlobalScope.webidl
@@ -34,16 +34,19 @@ partial interface WorkerGlobalScope {
   void importScripts(DOMString... urls);
 
   readonly attribute WorkerNavigator navigator;
 };
 
 WorkerGlobalScope implements WindowTimers;
 WorkerGlobalScope implements WindowBase64;
 
+// Not implemented yet: bug 1072107.
+// WorkerGlobalScope implements FontFaceSource;
+
 // Mozilla extensions
 partial interface WorkerGlobalScope {
   attribute EventHandler onclose;
 
   void dump(optional DOMString str);
 
   // XXXbz no spec for this yet, because the webperf WG is a bit dysfunctional
   readonly attribute Performance performance;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -125,16 +125,19 @@ WEBIDL_FILES = [
     'EventSource.webidl',
     'EventTarget.webidl',
     'File.webidl',
     'FileList.webidl',
     'FileMode.webidl',
     'FileReader.webidl',
     'FileReaderSync.webidl',
     'FocusEvent.webidl',
+    'FontFace.webidl',
+    'FontFaceSet.webidl',
+    'FontFaceSource.webidl',
     'FormData.webidl',
     'Function.webidl',
     'GainNode.webidl',
     'Geolocation.webidl',
     'GeometryUtils.webidl',
     'GetUserMediaRequest.webidl',
     'Headers.webidl',
     'History.webidl',
@@ -643,16 +646,17 @@ if CONFIG['MOZ_B2G_FM']:
 
 GENERATED_EVENTS_WEBIDL_FILES = [
     'AutocompleteErrorEvent.webidl',
     'BlobEvent.webidl',
     'CallEvent.webidl',
     'CallGroupErrorEvent.webidl',
     'CFStateChangeEvent.webidl',
     'CloseEvent.webidl',
+    'CSSFontFaceLoadEvent.webidl',
     'DataErrorEvent.webidl',
     'DataStoreChangeEvent.webidl',
     'DeviceLightEvent.webidl',
     'DeviceOrientationEvent.webidl',
     'DeviceProximityEvent.webidl',
     'DeviceStorageChangeEvent.webidl',
     'DOMTransactionEvent.webidl',
     'DownloadEvent.webidl',
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -246,26 +246,17 @@ GetRetainedImageFromSourceSurface(Source
                            data->Stride(), data->GetFormat());
     }
   }
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetCG::OptimizeSourceSurface(SourceSurface *aSurface) const
 {
-  if (aSurface->GetType() == SurfaceType::COREGRAPHICS_IMAGE ||
-      aSurface->GetType() == SurfaceType::COREGRAPHICS_CGCONTEXT) {
-    return aSurface;
-  }
-  RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
-
-  return CreateSourceSurfaceFromData(data->GetData(),
-                                     data->GetSize(),
-                                     data->Stride(),
-                                     data->GetFormat());
+  return aSurface;
 }
 
 class UnboundnessFixer
 {
     CGRect mClipBounds;
     CGLayerRef mLayer;
     CGContextRef mCg;
   public:
--- a/gfx/gl/SharedSurfaceANGLE.cpp
+++ b/gfx/gl/SharedSurfaceANGLE.cpp
@@ -283,27 +283,37 @@ ChooseConfig(GLContext* gl, GLLibraryEGL
         NS_WARNING("No configs found for the requested formats.");
         return EGL_NO_CONFIG;
     }
 
     // The requests passed to ChooseConfig are treated as minimums. If you ask
     // for 0 bits of alpha, we might still get 8 bits.
     EGLConfig config = EGL_NO_CONFIG;
     for (int i = 0; i < foundConfigs; i++) {
-        EGLConfig cur = configs[0];
-        if (DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE,
-                                       caps.alpha) &&
-            DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE,
-                                       caps.depth) &&
-            DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE,
-                                       caps.stencil))
+        EGLConfig cur = configs[i];
+        if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE,
+                                        caps.depth) ||
+            !DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE,
+                                        caps.stencil))
         {
-            config = cur;
-            break;
+            continue;
         }
+
+        // We can't enforce alpha on ANGLE yet because of:
+        // https://code.google.com/p/angleproject/issues/detail?id=764
+        if (!gl->IsANGLE()) {
+            if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE,
+                                            caps.alpha))
+            {
+                continue;
+            }
+        }
+
+        config = cur;
+        break;
     }
 
     if (config == EGL_NO_CONFIG) {
         NS_WARNING("No acceptable EGLConfig found.");
         return EGL_NO_CONFIG;
     }
 
     if (gl->DebugMode()) {
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1284,16 +1284,20 @@ nsEventStatus AsyncPanZoomController::On
   case NOTHING:
     // May happen if the user double-taps and drags without lifting after the
     // second tap. Ignore if this happens.
     return nsEventStatus_eIgnore;
 
   case TOUCHING:
   case CROSS_SLIDING_X:
   case CROSS_SLIDING_Y:
+    // We may have some velocity stored on the axis from move events
+    // that were not big enough to trigger scrolling. Clear that out.
+    mX.SetVelocity(0);
+    mY.SetVelocity(0);
     SetState(NOTHING);
     return nsEventStatus_eIgnore;
 
   case PANNING:
   case PANNING_LOCKED_X:
   case PANNING_LOCKED_Y:
   {
     CurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
@@ -2444,17 +2448,21 @@ bool AsyncPanZoomController::UpdateAnima
       RequestContentRepaint();
     }
     UpdateSharedCompositorFrameMetrics();
     return true;
   }
   return false;
 }
 
-void AsyncPanZoomController::GetOverscrollTransform(Matrix4x4* aTransform) const {
+Matrix4x4 AsyncPanZoomController::GetOverscrollTransform() const {
+  if (!IsOverscrolled()) {
+    return Matrix4x4();
+  }
+
   // The overscroll effect is a uniform stretch along the overscrolled axis,
   // with the edge of the content where we have reached the end of the
   // scrollable area pinned into place.
 
   // The kStretchFactor parameter determines how much overscroll can stretch the
   // content.
   const float kStretchFactor = gfxPrefs::APZOverscrollStretchFactor();
 
@@ -2479,18 +2487,18 @@ void AsyncPanZoomController::GetOverscro
   if (mY.IsOverscrolled() && mY.GetOverscroll() > 0) {
     // Overscrolled at the bottomn.
     ScreenCoord overscrolledCompositionHeight = scaleY * compositionSize.height;
     ScreenCoord extraCompositionHeight = overscrolledCompositionHeight - compositionSize.height;
     translation.y = -extraCompositionHeight;
   }
 
   // Combine the transformations into a matrix.
-  *aTransform = Matrix4x4().Scale(scaleX, scaleY, 1)
-                           .PostTranslate(translation.x, translation.y, 0);
+  return Matrix4x4().Scale(scaleX, scaleY, 1)
+                    .PostTranslate(translation.x, translation.y, 0);
 }
 
 bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
 {
   AssertOnCompositorThread();
 
   // Don't send any state-change notifications until the end of the function,
   // because we may go through some intermediate states while we finish
@@ -2556,29 +2564,22 @@ bool AsyncPanZoomController::AdvanceAnim
                                             mAsyncScrollTimeoutTask,
                                             gfxPrefs::APZAsyncScrollTimeout());
   }
 
   return requestAnimationFrame;
 }
 
 void AsyncPanZoomController::SampleContentTransformForFrame(ViewTransform* aOutTransform,
-                                                            ScreenPoint& aScrollOffset,
-                                                            Matrix4x4* aOutOverscrollTransform)
+                                                            ScreenPoint& aScrollOffset)
 {
   ReentrantMonitorAutoEnter lock(mMonitor);
 
   aScrollOffset = mFrameMetrics.GetScrollOffset() * mFrameMetrics.GetZoom();
   *aOutTransform = GetCurrentAsyncTransform();
-
-  // If we are overscrolled, we would like the compositor to apply an
-  // additional transform that produces an overscroll effect.
-  if (aOutOverscrollTransform && IsOverscrolled()) {
-    GetOverscrollTransform(aOutOverscrollTransform);
-  }
 }
 
 ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() const {
   ReentrantMonitorAutoEnter lock(mMonitor);
 
   CSSPoint lastPaintScrollOffset;
   if (mLastContentPaintMetrics.IsScrollable()) {
     lastPaintScrollOffset = mLastContentPaintMetrics.GetScrollOffset();
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -161,28 +161,27 @@ public:
   bool AdvanceAnimations(const TimeStamp& aSampleTime);
 
   bool UpdateAnimation(const TimeStamp& aSampleTime,
                        Vector<Task*>* aOutDeferredTasks);
 
   /**
    * Query the transforms that should be applied to the layer corresponding
    * to this APZC due to asynchronous panning and zooming.
-   * This function returns two transforms via out parameters:
-   *   |aOutTransform| is the transform due to regular panning and zooming
-   *   |aOverscrollTransform| is the transform due to overscrolling
-   * The two are separated because some clients want to ignore the overscroll
-   * transform for some purposes (and for convenience to these clients, the
-   * overscroll transform parameter may be nullptr). Clients who do not want
-   * to ignore the overscroll transform should multiply the two transforms
-   * together.
+   * This function returns the async transform via the |aOutTransform|
+   * out parameter.
    */
   void SampleContentTransformForFrame(ViewTransform* aOutTransform,
-                                      ScreenPoint& aScrollOffset,
-                                      Matrix4x4* aOutOverscrollTransform);
+                                      ScreenPoint& aScrollOffset);
+
+  /**
+   * Return a visual effect that reflects this apzc's
+   * overscrolled state, if any.
+   */
+  Matrix4x4 GetOverscrollTransform() const;
 
   /**
    * A shadow layer update has arrived. |aLayerMetrics| is the new FrameMetrics
    * for the container layer corresponding to this APZC.
    * |aIsFirstPaint| is a flag passed from the shadow
    * layers code indicating that the frame metrics being sent with this call are
    * the initial metrics and the initial paint of the frame has just happened.
    */
@@ -590,22 +589,16 @@ private:
   /**
    * Convert ScreenPoint relative to this APZC to CSSPoint relative
    * to the parent document. This excludes the transient compositor transform.
    * NOTE: This must be converted to CSSPoint relative to the child
    * document before sending over IPC.
    */
   bool ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* aOut);
 
-  /**
-   * Return in |aTransform| a visual effect that reflects this apzc's
-   * overscrolled state, if any.
-   */
-  void GetOverscrollTransform(Matrix4x4* aTransform) const;
-
   enum AxisLockMode {
     FREE,     /* No locking at all */
     STANDARD, /* Default axis locking mode that remains locked until pan ends*/
     STICKY,   /* Allow lock to be broken, with hysteresis */
   };
 
   static AxisLockMode GetAxisLockMode();
 
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -507,17 +507,17 @@ TileClient::~TileClient()
 TileClient::TileClient(const TileClient& o)
 {
   mBackBuffer.Set(this, o.mBackBuffer);
   mBackBufferOnWhite = o.mBackBufferOnWhite;
   mFrontBuffer = o.mFrontBuffer;
   mFrontBufferOnWhite = o.mFrontBufferOnWhite;
   mBackLock = o.mBackLock;
   mFrontLock = o.mFrontLock;
-  mCompositableClient = o.mCompositableClient;
+  mCompositableClient = nullptr;
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   mLastUpdate = o.mLastUpdate;
 #endif
   mManager = o.mManager;
   mInvalidFront = o.mInvalidFront;
   mInvalidBack = o.mInvalidBack;
 }
 
@@ -526,17 +526,17 @@ TileClient::operator=(const TileClient& 
 {
   if (this == &o) return *this;
   mBackBuffer.Set(this, o.mBackBuffer);
   mBackBufferOnWhite = o.mBackBufferOnWhite;
   mFrontBuffer = o.mFrontBuffer;
   mFrontBufferOnWhite = o.mFrontBufferOnWhite;
   mBackLock = o.mBackLock;
   mFrontLock = o.mFrontLock;
-  mCompositableClient = o.mCompositableClient;
+  mCompositableClient = nullptr;
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   mLastUpdate = o.mLastUpdate;
 #endif
   mManager = o.mManager;
   mInvalidFront = o.mInvalidFront;
   mInvalidBack = o.mInvalidBack;
   return *this;
 }
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -581,21 +581,20 @@ AsyncCompositionManager::ApplyAsyncConte
     AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(i);
     if (!controller) {
       continue;
     }
 
     hasAsyncTransform = true;
 
     ViewTransform asyncTransformWithoutOverscroll;
-    Matrix4x4 overscrollTransform;
     ScreenPoint scrollOffset;
     controller->SampleContentTransformForFrame(&asyncTransformWithoutOverscroll,
-                                               scrollOffset,
-                                               &overscrollTransform);
+                                               scrollOffset);
+    Matrix4x4 overscrollTransform = controller->GetOverscrollTransform();
 
     if (!aLayer->IsScrollInfoLayer()) {
       controller->MarkAsyncTransformAppliedToContent();
     }
 
     const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
     CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
     CSSRect displayPort(metrics.mCriticalDisplayPort.IsEmpty() ?
@@ -728,25 +727,33 @@ ApplyAsyncTransformToScrollbarForContent
   Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
 
   if (aScrollbarIsDescendant) {
     // If the scrollbar layer is a child of the content it is a scrollbar for, then we
     // need to do an extra untransform to cancel out the transient async transform on
     // the content. This is needed because otherwise that transient async transform is
     // part of the effective transform of this scrollbar, and the scrollbar will jitter
     // as the content scrolls.
-    Matrix4x4 transientUntransform = transientTransform.Inverse();
-    transform = transform * transientUntransform;
+    // Since the async transform is applied on top of the content's regular
+    // transform, we need to make sure to unapply the async transform in the
+    // same coordinate space. This requires applying the content transform and
+    // then unapplying it after unapplying the async transform.
+    Matrix4x4 asyncUntransform = (asyncTransform * apzc->GetOverscrollTransform()).Inverse();
+    Matrix4x4 contentTransform = aContent.GetTransform();
+    Matrix4x4 contentUntransform = contentTransform.Inverse();
+
+    Matrix4x4 compensation = contentTransform * asyncUntransform * contentUntransform;
+    transform = transform * compensation;
 
     // We also need to make a corresponding change on the clip rect of all the
     // layers on the ancestor chain from the scrollbar layer up to but not
     // including the layer with the async transform. Otherwise the scrollbar
     // shifts but gets clipped and so appears to flicker.
     for (Layer* ancestor = aScrollbar; ancestor != aContent.GetLayer(); ancestor = ancestor->GetParent()) {
-      TransformClipRect(ancestor, transientUntransform);
+      TransformClipRect(ancestor, compensation);
     }
   }
 
   // GetTransform already takes the pre- and post-scale into account.  Since we
   // will apply the pre- and post-scale again when computing the effective
   // transform, we must apply the inverses here.
   if (ContainerLayer* container = aScrollbar->AsContainerLayer()) {
     transform.Scale(1.0f/container->GetPreXScale(),
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -157,20 +157,19 @@ public:
     while (AdvanceAnimations(aSampleTime)) {
       aSampleTime += aIncrement;
     }
   }
 
   bool SampleContentTransformForFrame(const TimeStamp& aSampleTime,
                                       ViewTransform* aOutTransform,
                                       ScreenPoint& aScrollOffset) {
-    Matrix4x4 aOverscrollTransform;  // ignored
     bool ret = AdvanceAnimations(aSampleTime);
     AsyncPanZoomController::SampleContentTransformForFrame(
-      aOutTransform, aScrollOffset, &aOverscrollTransform);
+      aOutTransform, aScrollOffset);
     return ret;
   }
 };
 
 class TestAPZCTreeManager : public APZCTreeManager {
 };
 
 static FrameMetrics
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -121,16 +121,18 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUs
              gfxSparseBitSet* aUnicodeRanges)
     : gfxFontEntry(NS_LITERAL_STRING("userfont")),
       mUserFontLoadState(STATUS_NOT_LOADED),
       mFontDataLoadingState(NOT_LOADING),
       mUnsupportedFormat(false),
       mLoader(nullptr),
       mFontSet(aFontSet)
 {
+    MOZ_ASSERT(aWeight != 0,
+               "aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
     mIsUserFontContainer = true;
     mSrcList = aFontFaceSrcList;
     mSrcIndex = 0;
     mWeight = aWeight;
     mStretch = aStretch;
     // XXX Currently, we don't distinguish 'italic' and 'oblique' styles;
     // we need to fix this. (Bug 543715)
     mItalic = (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
@@ -244,31 +246,55 @@ gfxUserFontEntry::StoreUserFontData(gfxF
                                     uint32_t aMetaOrigLen)
 {
     if (!aFontEntry->mUserFontData) {
         aFontEntry->mUserFontData = new gfxUserFontData;
     }
     gfxUserFontData* userFontData = aFontEntry->mUserFontData;
     userFontData->mSrcIndex = mSrcIndex;
     const gfxFontFaceSrc& src = mSrcList[mSrcIndex];
-    if (src.mIsLocal) {
-        userFontData->mLocalName = src.mLocalName;
-    } else {
-        userFontData->mURI = src.mURI;
-        userFontData->mPrincipal = mPrincipal;
+    switch (src.mSourceType) {
+        case gfxFontFaceSrc::eSourceType_Local:
+            userFontData->mLocalName = src.mLocalName;
+            break;
+        case gfxFontFaceSrc::eSourceType_URL:
+            userFontData->mURI = src.mURI;
+            userFontData->mPrincipal = mPrincipal;
+            break;
+        case gfxFontFaceSrc::eSourceType_Buffer:
+            userFontData->mIsBuffer = true;
+            break;
     }
     userFontData->mPrivate = aPrivate;
     userFontData->mFormat = src.mFormatFlags;
     userFontData->mRealName = aOriginalName;
     if (aMetadata) {
         userFontData->mMetadata.SwapElements(*aMetadata);
         userFontData->mMetaOrigLen = aMetaOrigLen;
     }
 }
 
+void
+gfxUserFontEntry::GetFamilyNameAndURIForLogging(nsACString& aFamilyName,
+                                                nsACString& aURI)
+{
+  aFamilyName.Assign(NS_ConvertUTF16toUTF8(mFamilyName));
+
+  aURI.Truncate();
+  if (mSrcIndex == mSrcList.Length()) {
+    aURI.AppendLiteral("(end of source list)");
+  } else {
+    if (mSrcList[mSrcIndex].mURI) {
+      mSrcList[mSrcIndex].mURI->GetSpec(aURI);
+    } else {
+      aURI.AppendLiteral("(invalid URI)");
+    }
+  }
+}
+
 struct WOFFHeader {
     AutoSwap_PRUint32 signature;
     AutoSwap_PRUint32 flavor;
     AutoSwap_PRUint32 length;
     AutoSwap_PRUint16 numTables;
     AutoSwap_PRUint16 reserved;
     AutoSwap_PRUint32 totalSfntSize;
     AutoSwap_PRUint16 majorVersion;
@@ -332,21 +358,21 @@ gfxUserFontEntry::LoadNextSrc()
         // but don't reset state - if we've already timed out,
         // that counts against the new download
         mSrcIndex++;
     }
 
     // load each src entry in turn, until a local face is found
     // or a download begins successfully
     while (mSrcIndex < numSrc) {
-        const gfxFontFaceSrc& currSrc = mSrcList[mSrcIndex];
+        gfxFontFaceSrc& currSrc = mSrcList[mSrcIndex];
 
         // src local ==> lookup and load immediately
 
-        if (currSrc.mIsLocal) {
+        if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_Local) {
             gfxFontEntry* fe =
                 gfxPlatform::GetPlatform()->LookupLocalFont(currSrc.mLocalName,
                                                             mWeight,
                                                             mStretch,
                                                             mItalic);
             mFontSet->SetLocalRulesUsed();
             if (fe) {
                 LOG(("fontset (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
@@ -368,17 +394,17 @@ gfxUserFontEntry::LoadNextSrc()
                 LOG(("fontset (%p) [src %d] failed local: (%s) for (%s)\n",
                      mFontSet, mSrcIndex,
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
                      NS_ConvertUTF16toUTF8(mFamilyName).get()));
             }
         }
 
         // src url ==> start the load process
-        else {
+        else if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL) {
             if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
                     currSrc.mFormatFlags)) {
 
                 nsIPrincipal* principal = nullptr;
                 bool bypassCache;
                 nsresult rv = mFontSet->CheckFontLoad(&currSrc, &principal,
                                                       &bypassCache);
 
@@ -455,16 +481,38 @@ gfxUserFontEntry::LoadNextSrc()
                 }
             } else {
                 // We don't log a warning to the web console yet,
                 // as another source may load successfully
                 mUnsupportedFormat = true;
             }
         }
 
+        // FontFace buffer ==> load immediately
+
+        else {
+            MOZ_ASSERT(currSrc.mSourceType == gfxFontFaceSrc::eSourceType_Buffer);
+
+            uint8_t* buffer = nullptr;
+            uint32_t bufferLength = 0;
+
+            // sync load font immediately
+            currSrc.mBuffer->TakeBuffer(buffer, bufferLength);
+            if (buffer && LoadPlatformFont(buffer, bufferLength)) {
+                // LoadPlatformFont takes ownership of the buffer, so no need
+                // to free it here.
+                SetLoadState(STATUS_LOADED);
+                return;
+            } else {
+                mFontSet->LogMessage(this,
+                                     "font load failed",
+                                     nsIScriptError::errorFlag);
+            }
+        }
+
         mSrcIndex++;
     }
 
     if (mUnsupportedFormat) {
         mFontSet->LogMessage(this, "no supported format found",
                              nsIScriptError::warningFlag);
     }
 
@@ -572,32 +620,32 @@ gfxUserFontEntry::LoadPlatformFont(const
                  this, mSrcIndex, fontURI.get(),
                  NS_ConvertUTF16toUTF8(mFamilyName).get()));
         }
 #endif
     }
 
     // The downloaded data can now be discarded; the font entry is using the
     // sanitized copy
-    NS_Free((void*)aFontData);
+    moz_free((void*)aFontData);
 
     return fe != nullptr;
 }
 
 void
 gfxUserFontEntry::Load()
 {
     if (mUserFontLoadState == STATUS_NOT_LOADED) {
         LoadNextSrc();
     }
 }
 
 // This is called when a font download finishes.
 // Ownership of aFontData passes in here, and the font set must
-// ensure that it is eventually deleted via NS_Free().
+// ensure that it is eventually deleted via moz_free().
 bool
 gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
                                            uint32_t aLength,
                                            nsresult aDownloadStatus)
 {
     // forget about the loader, as we no longer potentially need to cancel it
     // if the entry is obsoleted
     mLoader = nullptr;
@@ -648,17 +696,17 @@ gfxUserFontSet::~gfxUserFontSet()
 {
     gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList();
     if (fp) {
         fp->RemoveUserFontSet(this);
     }
 }
 
 already_AddRefed<gfxUserFontEntry>
-gfxUserFontSet::FindOrCreateFontFace(
+gfxUserFontSet::FindOrCreateUserFontEntry(
                                const nsAString& aFamilyName,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                uint32_t aWeight,
                                int32_t aStretch,
                                uint32_t aItalicStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                uint32_t aLanguageOverride,
                                gfxSparseBitSet* aUnicodeRanges)
@@ -675,19 +723,19 @@ gfxUserFontSet::FindOrCreateFontFace(
     if (family) {
         entry = FindExistingUserFontEntry(family, aFontFaceSrcList, aWeight,
                                           aStretch, aItalicStyle,
                                           aFeatureSettings, aLanguageOverride,
                                           aUnicodeRanges);
     }
 
     if (!entry) {
-      entry = CreateFontFace(aFontFaceSrcList, aWeight, aStretch,
-                             aItalicStyle, aFeatureSettings, aLanguageOverride,
-                             aUnicodeRanges);
+      entry = CreateUserFontEntry(aFontFaceSrcList, aWeight, aStretch,
+                                  aItalicStyle, aFeatureSettings,
+                                  aLanguageOverride, aUnicodeRanges);
       entry->mFamilyName = aFamilyName;
 
 #ifdef PR_LOGGING
       if (LOG_ENABLED()) {
           LOG(("userfonts (%p) created \"%s\" (%p) with style: %s weight: %d "
                "stretch: %d",
                this, NS_ConvertUTF16toUTF8(aFamilyName).get(), entry.get(),
                (aItalicStyle & NS_FONT_STYLE_ITALIC ? "italic" :
@@ -696,26 +744,25 @@ gfxUserFontSet::FindOrCreateFontFace(
       }
 #endif
     }
 
     return entry.forget();
 }
 
 already_AddRefed<gfxUserFontEntry>
-gfxUserFontSet::CreateFontFace(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+gfxUserFontSet::CreateUserFontEntry(
+                               const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                uint32_t aWeight,
                                int32_t aStretch,
                                uint32_t aItalicStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                uint32_t aLanguageOverride,
                                gfxSparseBitSet* aUnicodeRanges)
 {
-    MOZ_ASSERT(aWeight != 0,
-               "aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
 
     nsRefPtr<gfxUserFontEntry> userFontEntry =
         new gfxUserFontEntry(this, aFontFaceSrcList, aWeight,
                               aStretch, aItalicStyle, aFeatureSettings,
                               aLanguageOverride, aUnicodeRanges);
     return userFontEntry.forget();
 }
 
@@ -751,18 +798,18 @@ gfxUserFontSet::FindExistingUserFontEntr
 
         return existingUserFontEntry;
     }
 
     return nullptr;
 }
 
 void
-gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
-                            gfxUserFontEntry* aUserFontEntry)
+gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName,
+                                 gfxUserFontEntry* aUserFontEntry)
 {
     gfxUserFontFamily* family = GetFamily(aFamilyName);
     family->AddFontEntry(aUserFontEntry);
 
 #ifdef PR_LOGGING
     if (LOG_ENABLED()) {
         LOG(("userfonts (%p) added \"%s\" (%p)",
              this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry));
@@ -984,31 +1031,40 @@ gfxUserFontSet::UserFontCache::Entry::Ke
 }
 
 void
 gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry* aFontEntry,
                                          EntryPersistence aPersistence)
 {
     NS_ASSERTION(aFontEntry->mFamilyName.Length() != 0,
                  "caching a font associated with no family yet");
+
+    gfxUserFontData* data = aFontEntry->mUserFontData;
+    if (data->mIsBuffer) {
+#ifdef DEBUG_USERFONT_CACHE
+        printf("userfontcache skipped fontentry with buffer source: %p\n",
+               aFontEntry);
+#endif
+        return;
+    }
+
     if (!sUserFonts) {
         sUserFonts = new nsTHashtable<Entry>;
 
         nsCOMPtr<nsIObserverService> obs =
             mozilla::services::GetObserverService();
         if (obs) {
             Flusher* flusher = new Flusher;
             obs->AddObserver(flusher, "cacheservice:empty-cache",
                              false);
             obs->AddObserver(flusher, "last-pb-context-exited", false);
             obs->AddObserver(flusher, "xpcom-shutdown", false);
         }
     }
 
-    gfxUserFontData* data = aFontEntry->mUserFontData;
     if (data->mLength) {
         MOZ_ASSERT(aPersistence == kPersistent);
         MOZ_ASSERT(!data->mPrivate);
         sUserFonts->PutEntry(Key(data->mCRC32, data->mLength, aFontEntry,
                                  data->mPrivate, aPersistence));
     } else {
         MOZ_ASSERT(aPersistence == kDiscardable);
         // For data: URIs, the principal is ignored; anyone who has the same
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -14,74 +14,105 @@
 #include "nsIPrincipal.h"
 #include "nsIScriptError.h"
 #include "nsURIHashKey.h"
 
 class nsFontFaceLoader;
 
 //#define DEBUG_USERFONT_CACHE
 
+class gfxFontFaceBufferSource
+{
+  NS_INLINE_DECL_REFCOUNTING(gfxFontFaceBufferSource)
+public:
+  virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) = 0;
+
+protected:
+  virtual ~gfxFontFaceBufferSource() {}
+};
+
 // parsed CSS @font-face rule information
 // lifetime: from when @font-face rule processed until font is loaded
 struct gfxFontFaceSrc {
-    bool                   mIsLocal;       // url or local
+
+    enum SourceType {
+        eSourceType_Local,
+        eSourceType_URL,
+        eSourceType_Buffer
+    };
+
+    SourceType             mSourceType;
 
     // if url, whether to use the origin principal or not
     bool                   mUseOriginPrincipal;
 
     // format hint flags, union of all possible formats
     // (e.g. TrueType, EOT, SVG, etc.)
     // see FLAG_FORMAT_* enum values below
     uint32_t               mFormatFlags;
 
     nsString               mLocalName;     // full font name if local
     nsCOMPtr<nsIURI>       mURI;           // uri if url
     nsCOMPtr<nsIURI>       mReferrer;      // referrer url if url
     nsCOMPtr<nsIPrincipal> mOriginPrincipal; // principal if url
+
+    nsRefPtr<gfxFontFaceBufferSource> mBuffer;
 };
 
 inline bool
 operator==(const gfxFontFaceSrc& a, const gfxFontFaceSrc& b)
 {
-    bool equals;
-    return (a.mIsLocal && b.mIsLocal &&
-            a.mLocalName == b.mLocalName) ||
-           (!a.mIsLocal && !b.mIsLocal &&
-            a.mUseOriginPrincipal == b.mUseOriginPrincipal &&
-            a.mFormatFlags == b.mFormatFlags &&
-            NS_SUCCEEDED(a.mURI->Equals(b.mURI, &equals)) && equals &&
-            NS_SUCCEEDED(a.mReferrer->Equals(b.mReferrer, &equals)) && equals &&
-            a.mOriginPrincipal->Equals(b.mOriginPrincipal));
+    if (a.mSourceType != b.mSourceType) {
+        return false;
+    }
+    switch (a.mSourceType) {
+        case gfxFontFaceSrc::eSourceType_Local:
+            return a.mLocalName == b.mLocalName;
+        case gfxFontFaceSrc::eSourceType_URL: {
+            bool equals;
+            return a.mUseOriginPrincipal == b.mUseOriginPrincipal &&
+                   a.mFormatFlags == b.mFormatFlags &&
+                   NS_SUCCEEDED(a.mURI->Equals(b.mURI, &equals)) && equals &&
+                   NS_SUCCEEDED(a.mReferrer->Equals(b.mReferrer, &equals)) &&
+                     equals &&
+                   a.mOriginPrincipal->Equals(b.mOriginPrincipal);
+        }
+        case gfxFontFaceSrc::eSourceType_Buffer:
+            return a.mBuffer == b.mBuffer;
+    }
+    NS_WARNING("unexpected mSourceType");
+    return false;
 }
 
 // Subclassed to store platform-specific code cleaned out when font entry is
 // deleted.
 // Lifetime: from when platform font is created until it is deactivated.
 // If the platform does not need to add any platform-specific code/data here,
 // then the gfxUserFontSet will allocate a base gfxUserFontData and attach
 // to the entry to track the basic user font info fields here.
 class gfxUserFontData {
 public:
     gfxUserFontData()
         : mSrcIndex(0), mFormat(0), mMetaOrigLen(0),
-          mCRC32(0), mLength(0), mPrivate(false)
+          mCRC32(0), mLength(0), mPrivate(false), mIsBuffer(false)
     { }
     virtual ~gfxUserFontData() { }
 
     nsTArray<uint8_t> mMetadata;  // woff metadata block (compressed), if any
     nsCOMPtr<nsIURI>  mURI;       // URI of the source, if it was url()
     nsCOMPtr<nsIPrincipal> mPrincipal; // principal for the download, if url()
     nsString          mLocalName; // font name used for the source, if local()
     nsString          mRealName;  // original fullname from the font resource
     uint32_t          mSrcIndex;  // index in the rule's source list
     uint32_t          mFormat;    // format hint for the source used, if any
     uint32_t          mMetaOrigLen; // length needed to decompress metadata
     uint32_t          mCRC32;     // Checksum
     uint32_t          mLength;    // Font length
     bool              mPrivate;   // whether font belongs to a private window
+    bool              mIsBuffer;  // whether the font source was a buffer
 };
 
 // initially contains a set of userfont font entry objects, replaced with
 // platform/user fonts as downloaded
 
 class gfxUserFontFamily : public gfxFontFamily {
 public:
     friend class gfxUserFontSet;
@@ -149,40 +180,40 @@ public:
 
 
     // creates a font face without adding it to a particular family
     // weight - [100, 900] (multiples of 100)
     // stretch = [NS_FONT_STRETCH_ULTRA_CONDENSED, NS_FONT_STRETCH_ULTRA_EXPANDED]
     // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
     // language override = result of calling gfxFontStyle::ParseFontLanguageOverride
     // TODO: support for unicode ranges not yet implemented
-    already_AddRefed<gfxUserFontEntry> CreateFontFace(
+    virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
                               const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                               uint32_t aWeight,
                               int32_t aStretch,
                               uint32_t aItalicStyle,
                               const nsTArray<gfxFontFeature>& aFeatureSettings,
                               uint32_t aLanguageOverride,
-                              gfxSparseBitSet* aUnicodeRanges);
+                              gfxSparseBitSet* aUnicodeRanges) = 0;
 
     // creates a font face for the specified family, or returns an existing
     // matching entry on the family if there is one
-    already_AddRefed<gfxUserFontEntry> FindOrCreateFontFace(
+    already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntry(
                                const nsAString& aFamilyName,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                uint32_t aWeight,
                                int32_t aStretch,
                                uint32_t aItalicStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                uint32_t aLanguageOverride,
                                gfxSparseBitSet* aUnicodeRanges);
 
     // add in a font face for which we have the gfxUserFontEntry already
-    void AddFontFace(const nsAString& aFamilyName,
-                     gfxUserFontEntry* aUserFontEntry);
+    void AddUserFontEntry(const nsAString& aFamilyName,
+                          gfxUserFontEntry* aUserFontEntry);
 
     // Whether there is a face with this family name
     bool HasFamily(const nsAString& aFamilyName) const
     {
         return LookupFamily(aFamilyName) != nullptr;
     }
 
     // Look up and return the gfxUserFontFamily in mFontFamilies with
@@ -438,17 +469,17 @@ protected:
     virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
                                 const char* aMessage,
                                 uint32_t aFlags = nsIScriptError::errorFlag,
                                 nsresult aStatus = NS_OK) = 0;
 
     // helper method for performing the actual userfont set rebuild
     virtual void DoRebuildUserFontSet() = 0;
 
-    // helper method for FindOrCreateFontFace
+    // helper method for FindOrCreateUserFontEntry
     gfxUserFontEntry* FindExistingUserFontEntry(
                                    gfxUserFontFamily* aFamily,
                                    const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                    uint32_t aWeight,
                                    int32_t aStretch,
                                    uint32_t aItalicStyle,
                                    const nsTArray<gfxFontFeature>& aFeatureSettings,
                                    uint32_t aLanguageOverride,
@@ -519,27 +550,36 @@ public:
         return mUserFontLoadState == STATUS_LOADING &&
                mFontDataLoadingState < LOADING_SLOWLY;
     }
 
     // load the font - starts the loading of sources which continues until
     // a valid font resource is found or all sources fail
     void Load();
 
+    // methods to expose some information to FontFaceSet::UserFontSet
+    // since we can't make that class a friend
+    void SetLoader(nsFontFaceLoader* aLoader) { mLoader = aLoader; }
+    nsFontFaceLoader* GetLoader() { return mLoader; }
+    nsIPrincipal* GetPrincipal() { return mPrincipal; }
+    uint32_t GetSrcIndex() { return mSrcIndex; }
+    void GetFamilyNameAndURIForLogging(nsACString& aFamilyName,
+                                       nsACString& aURI);
+
 protected:
     const uint8_t* SanitizeOpenTypeData(const uint8_t* aData,
                                         uint32_t aLength,
                                         uint32_t& aSaneLength,
                                         bool aIsCompressed);
 
     // attempt to load the next resource in the src list.
     void LoadNextSrc();
 
     // change the load state
-    void SetLoadState(UserFontLoadState aLoadState);
+    virtual void SetLoadState(UserFontLoadState aLoadState);
 
     // when download has been completed, pass back data here
     // aDownloadStatus == NS_OK ==> download succeeded, error otherwise
     // returns true if platform font creation sucessful (or local()
     // reference was next in line)
     // Ownership of aFontData is passed in here; the font set must
     // ensure that it is eventually deleted with NS_Free().
     bool FontDataDownloadComplete(const uint8_t* aFontData, uint32_t aLength,
--- a/image/decoders/icon/mac/nsIconChannelCocoa.mm
+++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm
@@ -17,26 +17,36 @@
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 #include "nsIMIMEService.h"
 #include "nsCExternalHandlerService.h"
 #include "nsILocalFileMac.h"
 #include "nsIFileURL.h"
 #include "nsTArray.h"
 #include "nsObjCExceptions.h"
+#include "nsProxyRelease.h"
 
 #include <Cocoa/Cocoa.h>
 
 // nsIconChannel methods
 nsIconChannel::nsIconChannel()
 {
 }
 
 nsIconChannel::~nsIconChannel() 
-{}
+{
+  if (mLoadInfo) {
+    nsCOMPtr<nsIThread> mainThread;
+    NS_GetMainThread(getter_AddRefs(mainThread));
+
+    nsILoadInfo *forgetableLoadInfo;
+    mLoadInfo.forget(&forgetableLoadInfo);
+    NS_ProxyRelease(mainThread, forgetableLoadInfo, false);
+  }
+}
 
 NS_IMPL_ISUPPORTS(nsIconChannel, 
                   nsIChannel, 
                   nsIRequest,
 			       nsIRequestObserver,
 			       nsIStreamListener)
 
 nsresult nsIconChannel::Init(nsIURI* uri)
--- a/image/decoders/icon/win/nsIconChannel.cpp
+++ b/image/decoders/icon/win/nsIconChannel.cpp
@@ -18,16 +18,17 @@
 #include "nsIStringStream.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 #include "nsIFile.h"
 #include "nsIFileURL.h"
 #include "nsIMIMEService.h"
 #include "nsCExternalHandlerService.h"
 #include "nsDirectoryServiceDefs.h"
+#include "nsProxyRelease.h"
 
 #ifdef _WIN32_WINNT
 #undef _WIN32_WINNT
 #endif
 #define _WIN32_WINNT 0x0600
 
 // we need windows.h to read out registry information...
 #include <windows.h>
@@ -62,17 +63,26 @@ static SHSTOCKICONID GetStockIconIDForNa
 }
 
 // nsIconChannel methods
 nsIconChannel::nsIconChannel()
 {
 }
 
 nsIconChannel::~nsIconChannel() 
-{}
+{
+  if (mLoadInfo) {
+    nsCOMPtr<nsIThread> mainThread;
+    NS_GetMainThread(getter_AddRefs(mainThread));
+
+    nsILoadInfo *forgetableLoadInfo;
+    mLoadInfo.forget(&forgetableLoadInfo);
+    NS_ProxyRelease(mainThread, forgetableLoadInfo, false);
+  }
+}
 
 NS_IMPL_ISUPPORTS(nsIconChannel, 
                   nsIChannel, 
                   nsIRequest,
                   nsIRequestObserver,
                   nsIStreamListener)
 
 nsresult nsIconChannel::Init(nsIURI* uri)
--- a/ipc/glue/ProcessUtils_linux.cpp
+++ b/ipc/glue/ProcessUtils_linux.cpp
@@ -112,70 +112,64 @@ static void ProcLoaderClientDeinit();
  * starting from kBeginReserveFileDescriptor so that operations like
  * __android_log_print() won't take these magic FDs.
  */
 static const int kReservedFileDescriptors = 5;
 static const int kBeginReserveFileDescriptor = STDERR_FILENO + 1;
 
 class ProcLoaderParent : public PProcLoaderParent
 {
-private:
-  nsAutoPtr<FileDescriptor> mChannelFd; // To keep a reference.
-
 public:
-  ProcLoaderParent(FileDescriptor *aFd) : mChannelFd(aFd) {}
+  ProcLoaderParent() {}
+  virtual ~ProcLoaderParent() {}
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   virtual bool RecvLoadComplete(const int32_t &aPid,
                                 const int32_t &aCookie) MOZ_OVERRIDE;
-
-  virtual void OnChannelError() MOZ_OVERRIDE;
 };
 
 void
 ProcLoaderParent::ActorDestroy(ActorDestroyReason aWhy)
 {
+  if (aWhy == AbnormalShutdown) {
+    NS_WARNING("ProcLoaderParent is destroyed abnormally.");
+  }
+
+  if (sProcLoaderClientOnDeinit) {
+    // Get error for closing while the channel is already error.
+    return;
+  }
+
+  // Destroy self asynchronously.
+  ProcLoaderClientDeinit();
 }
 
 static void
 _ProcLoaderParentDestroy(PProcLoaderParent *aLoader)
 {
-  aLoader->Close();
   delete aLoader;
   sProcLoaderClientOnDeinit = false;
 }
 
 bool
 ProcLoaderParent::RecvLoadComplete(const int32_t &aPid,
                                    const int32_t &aCookie)
 {
-  ProcLoaderClientDeinit();
   return true;
 }
 
 static void
 CloseFileDescriptors(FdArray& aFds)
 {
   for (size_t i = 0; i < aFds.length(); i++) {
     unused << HANDLE_EINTR(close(aFds[i]));
   }
 }
 
-void
-ProcLoaderParent::OnChannelError()
-{
-  if (sProcLoaderClientOnDeinit) {
-    // Get error for closing while the channel is already error.
-    return;
-  }
-  NS_WARNING("ProcLoaderParent is in channel error");
-  ProcLoaderClientDeinit();
-}
-
 /**
  * Initialize the client of B2G loader for loader itself.
  *
  * The initialization of B2G loader are divided into two stages. First
  * stage is to collect child info passed from the main program of the
  * loader.  Second stage is to initialize Gecko according to info from the
  * first stage and make the client of loader service ready.
  *
@@ -199,21 +193,21 @@ void
 ProcLoaderClientGeckoInit()
 {
   MOZ_ASSERT(sProcLoaderClientInitialized, "call ProcLoaderClientInit() at first");
   MOZ_ASSERT(!sProcLoaderClientGeckoInitialized,
              "call ProcLoaderClientGeckoInit() more than once");
 
   sProcLoaderClientGeckoInitialized = true;
 
-  FileDescriptor *fd = new FileDescriptor(sProcLoaderChannelFd);
-  close(sProcLoaderChannelFd);
+  TransportDescriptor fd;
+  fd.mFd = base::FileDescriptor(sProcLoaderChannelFd, /*auto_close=*/ false);
   sProcLoaderChannelFd = -1;
-  Transport *transport = OpenDescriptor(*fd, Transport::MODE_CLIENT);
-  sProcLoaderParent = new ProcLoaderParent(fd);
+  Transport *transport = OpenDescriptor(fd, Transport::MODE_CLIENT);
+  sProcLoaderParent = new ProcLoaderParent();
   sProcLoaderParent->Open(transport,
                           sProcLoaderPid,
                           XRE_GetIOMessageLoop(),
                           ParentSide);
   sProcLoaderLoop = MessageLoop::current();
 }
 
 /**
@@ -543,18 +537,18 @@ ProcLoaderServiceRun(pid_t aPeerPid, int
   gArgc = aArgc;
 
   {
     nsresult rv = XRE_InitCommandLine(aArgc, _argv);
     if (NS_FAILED(rv)) {
       MOZ_CRASH();
     }
 
-    FileDescriptor fd(aFd);
-    close(aFd);
+    TransportDescriptor fd;
+    fd.mFd = base::FileDescriptor(aFd, /*auto_close =*/false);
 
     MOZ_ASSERT(!sProcLoaderServing);
     MessageLoop loop;
 
     nsAutoPtr<ContentProcess> process;
     process = new ContentProcess(aPeerPid);
     ChildThread *iothread = process->child_thread();
 
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -269,17 +269,20 @@ class Node {
     }
     template<typename T>
     Node &operator=(const Rooted<T *> &root) {
         construct(root.get());
         return *this;
     }
 
     // Constructors accepting SpiderMonkey's other generic-pointer-ish types.
-    explicit Node(JS::HandleValue value);
+    // Note that we *do* want an implicit constructor here: JS::Value and
+    // JS::ubi::Node are both essentially tagged references to other sorts of
+    // objects, so letting conversions happen automatically is appropriate.
+    MOZ_IMPLICIT Node(JS::HandleValue value);
     Node(JSGCTraceKind kind, void *ptr);
 
     // copy construction and copy assignment just use memcpy, since we know
     // instances contain nothing but a vtable pointer and a data pointer.
     //
     // To be completely correct, concrete classes could provide a virtual
     // 'construct' member function, which we could invoke on rhs to construct an
     // instance in our storage. But this is good enough; there's no need to jump
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2064,17 +2064,17 @@ IsSimdAvailable(JSContext *cx, unsigned 
     return true;
 }
 
 static bool
 ByteSize(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     mozilla::MallocSizeOf mallocSizeOf = cx->runtime()->debuggerMallocSizeOf;
-    JS::ubi::Node node(args.get(0));
+    JS::ubi::Node node = args.get(0);
     if (node)
         args.rval().set(NumberValue(node.size(mallocSizeOf)));
     else
         args.rval().setUndefined();
     return true;
 }
 
 static const JSFunctionSpecWithHelp TestingFunctions[] = {
--- a/js/src/doc/Debugger/Debugger.Object.md
+++ b/js/src/doc/Debugger/Debugger.Object.md
@@ -151,16 +151,19 @@ from its prototype:
 :   If the referent is a function that is debuggee code, a
     [`Debugger.Environment`][environment] instance representing the lexical
     environment enclosing the function when it was created. If the referent
     is a function proxy or not debuggee code, this is `undefined`.
 
 `isBoundFunction`
 :   `true` if the referent is a bound function; `false` otherwise.
 
+`isArrowFunction`
+:   `true` if the referent is an arrow function; `false` otherwise.
+
 `boundTargetFunction`
 :   If the referent is a bound function, this is its target function—the
     function that was bound to a particular `this` object. If the referent
     is not a bound function, this is `undefined`.
 
 `boundThis`
 :   If the referent is a bound function, this is the `this` value it was
     bound to. If the referent is not a bound function, this is `undefined`.
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -139,18 +139,18 @@ static const size_t MAX_BACKGROUND_FINAL
 
 class TenuredCell;
 
 // A GC cell is the base class for all GC things.
 struct Cell
 {
   public:
     MOZ_ALWAYS_INLINE bool isTenured() const { return !IsInsideNursery(this); }
-    MOZ_ALWAYS_INLINE const TenuredCell *asTenured() const;
-    MOZ_ALWAYS_INLINE TenuredCell *asTenured();
+    MOZ_ALWAYS_INLINE const TenuredCell &asTenured() const;
+    MOZ_ALWAYS_INLINE TenuredCell &asTenured();
 
     inline JSRuntime *runtimeFromMainThread() const;
     inline JS::shadow::Runtime *shadowRuntimeFromMainThread() const;
 
     // Note: Unrestricted access to the runtime of a GC thing from an arbitrary
     // thread can easily lead to races. Use this method very carefully.
     inline JSRuntime *runtimeFromAnyThread() const;
     inline JS::shadow::Runtime *shadowRuntimeFromAnyThread() const;
@@ -1141,28 +1141,28 @@ static void
 AssertValidColor(const TenuredCell *thing, uint32_t color)
 {
 #ifdef DEBUG
     ArenaHeader *aheader = thing->arenaHeader();
     MOZ_ASSERT(color < aheader->getThingSize() / CellSize);
 #endif
 }
 
-MOZ_ALWAYS_INLINE const TenuredCell *
+MOZ_ALWAYS_INLINE const TenuredCell &
 Cell::asTenured() const
 {
     MOZ_ASSERT(isTenured());
-    return static_cast<const TenuredCell *>(this);
+    return *static_cast<const TenuredCell *>(this);
 }
 
-MOZ_ALWAYS_INLINE TenuredCell *
+MOZ_ALWAYS_INLINE TenuredCell &
 Cell::asTenured()
 {
     MOZ_ASSERT(isTenured());
-    return static_cast<TenuredCell *>(this);
+    return *static_cast<TenuredCell *>(this);
 }
 
 inline JSRuntime *
 Cell::runtimeFromMainThread() const
 {
     JSRuntime *rt = chunk()->info.trailer.runtime;
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
     return rt;
@@ -1378,17 +1378,17 @@ TenuredCell::writeBarrierPostRemove(Tenu
 }
 
 #ifdef DEBUG
 bool
 Cell::isAligned() const
 {
     if (!isTenured())
         return true;
-    return asTenured()->isAligned();
+    return asTenured().isAligned();
 }
 
 bool
 TenuredCell::isAligned() const
 {
     return Arena::isAligned(address(), arenaHeader()->getThingSize());
 }
 #endif
--- a/js/src/gc/Iteration.cpp
+++ b/js/src/gc/Iteration.cpp
@@ -114,17 +114,17 @@ void
 js::IterateGrayObjects(Zone *zone, GCThingCallback cellCallback, void *data)
 {
     zone->runtimeFromMainThread()->gc.evictNursery();
     AutoPrepareForTracing prep(zone->runtimeFromMainThread(), SkipAtoms);
 
     for (size_t finalizeKind = 0; finalizeKind <= FINALIZE_OBJECT_LAST; finalizeKind++) {
         for (ZoneCellIterUnderGC i(zone, AllocKind(finalizeKind)); !i.done(); i.next()) {
             JSObject *obj = i.get<JSObject>();
-            if (obj->asTenured()->isMarked(GRAY))
+            if (obj->asTenured().isMarked(GRAY))
                 cellCallback(data, obj);
         }
     }
 }
 
 JS_PUBLIC_API(void)
 JS_IterateCompartments(JSRuntime *rt, void *data,
                        JSIterateCompartmentCallback compartmentCallback)
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -225,17 +225,17 @@ CheckMarkedThing(JSTracer *trc, T **thin
 
     /*
      * Try to assert that the thing is allocated.  This is complicated by the
      * fact that allocated things may still contain the poison pattern if that
      * part has not been overwritten, and that the free span list head in the
      * ArenaHeader may not be synced with the real one in ArenaLists.
      */
     MOZ_ASSERT_IF(IsThingPoisoned(thing) && rt->isHeapBusy(),
-                  !InFreeList(thing->asTenured()->arenaHeader(), thing));
+                  !InFreeList(thing->asTenured().arenaHeader(), thing));
 #endif
 }
 
 /*
  * We only set the maybeAlive flag for objects and scripts. It's assumed that,
  * if a compartment is alive, then it will have at least some live object or
  * script it in. Even if we get this wrong, the worst that will happen is that
  * scheduledForDestruction will be set on the compartment, which will cause some
@@ -445,24 +445,24 @@ IsMarked(T **thingp)
 #endif
     {
         if (IsInsideNursery(*thingp)) {
             Nursery &nursery = rt->gc.nursery;
             return nursery.getForwardedPointer(thingp);
         }
     }
 #endif  // JSGC_GENERATIONAL
-    Zone *zone = (*thingp)->asTenured()->zone();
+    Zone *zone = (*thingp)->asTenured().zone();
     if (!zone->isCollecting() || zone->isGCFinished())
         return true;
 #ifdef JSGC_COMPACTING
     if (zone->isGCCompacting() && IsForwarded(*thingp))
         *thingp = Forwarded(*thingp);
 #endif
-    return (*thingp)->asTenured()->isMarked();
+    return (*thingp)->asTenured().isMarked();
 }
 
 template <typename T>
 static bool
 IsAboutToBeFinalized(T **thingp)
 {
     MOZ_ASSERT(thingp);
     MOZ_ASSERT(*thingp);
@@ -490,29 +490,29 @@ IsAboutToBeFinalized(T **thingp)
         if (rt->isHeapMinorCollecting()) {
             if (IsInsideNursery(thing))
                 return !nursery.getForwardedPointer(thingp);
             return false;
         }
     }
 #endif  // JSGC_GENERATIONAL
 
-    Zone *zone = thing->asTenured()->zone();
+    Zone *zone = thing->asTenured().zone();
     if (zone->isGCSweeping()) {
         /*
          * We should return false for things that have been allocated during
          * incremental sweeping, but this possibility doesn't occur at the moment
          * because this function is only called at the very start of the sweeping a
          * compartment group and during minor gc. Rather than do the extra check,
          * we just assert that it's not necessary.
          */
         MOZ_ASSERT_IF(!rt->isHeapMinorCollecting(),
-                      !thing->asTenured()->arenaHeader()->allocatedDuringIncremental);
+                      !thing->asTenured().arenaHeader()->allocatedDuringIncremental);
 
-        return !thing->asTenured()->isMarked();
+        return !thing->asTenured().isMarked();
     }
 #ifdef JSGC_COMPACTING
     else if (zone->isGCCompacting() && IsForwarded(thing)) {
         *thingp = Forwarded(thing);
         return false;
     }
 #endif
 
@@ -661,17 +661,17 @@ DeclMarkerImpl(TypeObject, js::types::Ty
 
 void
 gc::MarkKind(JSTracer *trc, void **thingp, JSGCTraceKind kind)
 {
     MOZ_ASSERT(thingp);
     MOZ_ASSERT(*thingp);
     DebugOnly<Cell *> cell = static_cast<Cell *>(*thingp);
     MOZ_ASSERT_IF(cell->isTenured(),
-                  kind == MapAllocToTraceKind(cell->asTenured()->getAllocKind()));
+                  kind == MapAllocToTraceKind(cell->asTenured().getAllocKind()));
     switch (kind) {
       case JSTRACE_OBJECT:
         MarkInternal(trc, reinterpret_cast<JSObject **>(thingp));
         break;
       case JSTRACE_STRING:
         MarkInternal(trc, reinterpret_cast<JSString **>(thingp));
         break;
       case JSTRACE_SYMBOL:
@@ -943,40 +943,40 @@ ShouldMarkCrossCompartment(JSTracer *trc
 
     uint32_t color = AsGCMarker(trc)->getMarkColor();
     MOZ_ASSERT(color == BLACK || color == GRAY);
 
     if (IsInsideNursery(cell)) {
         MOZ_ASSERT(color == BLACK);
         return false;
     }
-    TenuredCell *tenured = cell->asTenured();
+    TenuredCell &tenured = cell->asTenured();
 
-    JS::Zone *zone = tenured->zone();
+    JS::Zone *zone = tenured.zone();
     if (color == BLACK) {
         /*
          * Having black->gray edges violates our promise to the cycle
          * collector. This can happen if we're collecting a compartment and it
          * has an edge to an uncollected compartment: it's possible that the
          * source and destination of the cross-compartment edge should be gray,
          * but the source was marked black by the conservative scanner.
          */
-        if (tenured->isMarked(GRAY)) {
+        if (tenured.isMarked(GRAY)) {
             MOZ_ASSERT(!zone->isCollecting());
             trc->runtime()->gc.setFoundBlackGrayEdges();
         }
         return zone->isGCMarking();
     } else {
         if (zone->isGCMarkingBlack()) {
             /*
              * The destination compartment is being not being marked gray now,
              * but it will be later, so record the cell so it can be marked gray
              * at the appropriate time.
              */
-            if (!tenured->isMarked())
+            if (!tenured.isMarked())
                 DelayCrossCompartmentGrayMarking(src);
             return false;
         }
         return zone->isGCMarkingGray();
     }
 }
 
 void
@@ -1036,17 +1036,17 @@ gc::IsCellAboutToBeFinalized(Cell **thin
     JS_COMPARTMENT_ASSERT_STR(rt, sym)
 
 static void
 PushMarkStack(GCMarker *gcmarker, ObjectImpl *thing)
 {
     JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
     MOZ_ASSERT(!IsInsideNursery(thing));
 
-    if (thing->asTenured()->markIfUnmarked(gcmarker->getMarkColor()))
+    if (thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushObject(thing);
 }
 
 /*
  * PushMarkStack for BaseShape unpacks its children directly onto the mark
  * stack. For a pre-barrier between incremental slices, this may result in
  * objects in the nursery getting pushed onto the mark stack. It is safe to
  * ignore these objects because they will be marked by the matching
@@ -1054,27 +1054,27 @@ PushMarkStack(GCMarker *gcmarker, Object
  */
 static void
 MaybePushMarkStackBetweenSlices(GCMarker *gcmarker, JSObject *thing)
 {
     DebugOnly<JSRuntime *> rt = gcmarker->runtime();
     JS_COMPARTMENT_ASSERT(rt, thing);
     MOZ_ASSERT_IF(rt->isHeapBusy(), !IsInsideNursery(thing));
 
-    if (!IsInsideNursery(thing) && thing->asTenured()->markIfUnmarked(gcmarker->getMarkColor()))
+    if (!IsInsideNursery(thing) && thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushObject(thing);
 }
 
 static void
 PushMarkStack(GCMarker *gcmarker, JSFunction *thing)
 {
     JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
     MOZ_ASSERT(!IsInsideNursery(thing));
 
-    if (thing->asTenured()->markIfUnmarked(gcmarker->getMarkColor()))
+    if (thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushObject(thing);
 }
 
 static void
 PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing)
 {
     JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
     MOZ_ASSERT(!IsInsideNursery(thing));
@@ -1704,17 +1704,17 @@ GCMarker::processMarkStackTop(SliceBudge
                 MOZ_ASSERT(runtime()->isAtomsZone(str->zone()) || str->zone() == obj->zone());
                 if (str->markIfUnmarked())
                     ScanString(this, str);
             }
         } else if (v.isObject()) {
             JSObject *obj2 = &v.toObject();
             JS_COMPARTMENT_ASSERT(runtime(), obj2);
             MOZ_ASSERT(obj->compartment() == obj2->compartment());
-            if (obj2->asTenured()->markIfUnmarked(getMarkColor())) {
+            if (obj2->asTenured().markIfUnmarked(getMarkColor())) {
                 pushValueArray(obj, vp, end);
                 obj = obj2;
                 goto scan_obj;
             }
         } else if (v.isSymbol()) {
             JS::Symbol *sym = v.toSymbol();
             if (!sym->isWellKnownSymbol()) {
                 JS_COMPARTMENT_ASSERT_SYM(runtime(), sym);
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -582,17 +582,17 @@ GCMarker::markDelayedChildren(SliceBudge
 }
 
 #ifdef DEBUG
 void
 GCMarker::checkZone(void *p)
 {
     MOZ_ASSERT(started);
     DebugOnly<Cell *> cell = static_cast<Cell *>(p);
-    MOZ_ASSERT_IF(cell->isTenured(), cell->asTenured()->zone()->isCollecting());
+    MOZ_ASSERT_IF(cell->isTenured(), cell->asTenured().zone()->isCollecting());
 }
 #endif
 
 bool
 GCMarker::hasBufferedGrayRoots() const
 {
     return grayBufferState == GRAY_BUFFER_OK;
 }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-isArrowFunction.js
@@ -0,0 +1,22 @@
+// Debugger.Object.prototype.isArrowFunction recognizes arrow functions.
+
+var g = newGlobal();
+var dbg = new Debugger;
+var gDO = dbg.addDebuggee(g);
+var hits = 0;
+
+function checkIsArrow(shouldBe, expr) {
+  print(expr);
+  assertEq(gDO.evalInGlobal(expr).return.isArrowFunction, shouldBe);
+}
+
+checkIsArrow(true, '() => { }');
+checkIsArrow(true, '(a) => { bleh; }');
+checkIsArrow(false, 'Object.getPrototypeOf(() => { })');
+checkIsArrow(false, '(function () { })');
+checkIsArrow(false, 'function f() { } f');
+checkIsArrow(false, '({})');
+checkIsArrow(false, 'Math.atan2');
+checkIsArrow(false, 'Function.prototype');
+checkIsArrow(false, 'Function("")');
+checkIsArrow(false, 'new Function("")');
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4006,17 +4006,17 @@ static const VMFunction NewGCThingParInf
 
 bool
 CodeGenerator::emitAllocateGCThingPar(LInstruction *lir, Register objReg, Register cxReg,
                                       Register tempReg1, Register tempReg2, JSObject *templateObj)
 {
     MOZ_ASSERT(lir->mirRaw());
     MOZ_ASSERT(lir->mirRaw()->isInstruction());
 
-    gc::AllocKind allocKind = templateObj->asTenured()->getAllocKind();
+    gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
 #ifdef JSGC_FJGENERATIONAL
     OutOfLineCode *ool = oolCallVM(NewGCThingParInfo, lir,
                                    (ArgList(), Imm32(allocKind)), StoreRegisterTo(objReg));
     if (!ool)
         return false;
 #else
     OutOfLineNewGCThingPar *ool = new(alloc()) OutOfLineNewGCThingPar(lir, allocKind, objReg, cxReg);
     if (!ool || !addOutOfLineCode(ool, lir->mirRaw()->toInstruction()))
@@ -4188,17 +4188,17 @@ typedef JSObject *(*NewGCObjectFn)(JSCon
                                    gc::InitialHeap initialHeap);
 static const VMFunction NewGCObjectInfo =
     FunctionInfo<NewGCObjectFn>(js::jit::NewGCObject);
 
 bool
 CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
 {
     JSObject *templateObject = lir->mir()->templateObject();
-    gc::AllocKind allocKind = templateObject->asTenured()->getAllocKind();
+    gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
 
     OutOfLineCode *ool = oolCallVM(NewGCObjectInfo, lir,
                                    (ArgList(), Imm32(allocKind), Imm32(initialHeap)),
                                    StoreRegisterTo(objReg));
     if (!ool)
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6772,17 +6772,17 @@ IonBuilder::ensureDefiniteTypeSet(MDefin
 
 static size_t
 NumFixedSlots(JSObject *object)
 {
     // Note: we can't use object->numFixedSlots() here, as this will read the
     // shape and can race with the main thread if we are building off thread.
     // The allocation kind and object class (which goes through the type) can
     // be read freely, however.
-    gc::AllocKind kind = object->asTenured()->getAllocKind();
+    gc::AllocKind kind = object->asTenured().getAllocKind();
     return gc::GetGCKindSlots(kind, object->getClass());
 }
 
 bool
 IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psucceeded,
                           MDefinition *lexicalCheck)
 {
     jsid id = NameToId(name);
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -590,28 +590,28 @@ void
 MacroAssembler::newGCThing(Register result, Register temp, JSObject *templateObj,
                             gc::InitialHeap initialHeap, Label *fail)
 {
     // This method does not initialize the object: if external slots get
     // allocated into |temp|, there is no easy way for us to ensure the caller
     // frees them. Instead just assert this case does not happen.
     MOZ_ASSERT(!templateObj->numDynamicSlots());
 
-    gc::AllocKind allocKind = templateObj->asTenured()->getAllocKind();
+    gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
     MOZ_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
 
     allocateObject(result, temp, allocKind, templateObj->numDynamicSlots(), initialHeap, fail);
 }
 
 void
 MacroAssembler::createGCObject(Register obj, Register temp, JSObject *templateObj,
                                gc::InitialHeap initialHeap, Label *fail, bool initFixedSlots)
 {
     uint32_t nDynamicSlots = templateObj->numDynamicSlots();
-    gc::AllocKind allocKind = templateObj->asTenured()->getAllocKind();
+    gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
     MOZ_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
 
     // Arrays with copy on write elements do not need fixed space for an
     // elements header. The template object, which owns the original elements,
     // might have another allocation kind.
     if (templateObj->denseElementsAreCopyOnWrite())
         allocKind = gc::FINALIZE_OBJECT0_BACKGROUND;
 
@@ -731,17 +731,17 @@ MacroAssembler::newGCTenuredThingPar(Reg
     // tempReg1->head.first = tempReg2;
     storePtr(tempReg2, Address(tempReg1, gc::FreeList::offsetOfFirst()));
 }
 
 void
 MacroAssembler::newGCThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
                               JSObject *templateObject, Label *fail)
 {
-    gc::AllocKind allocKind = templateObject->asTenured()->getAllocKind();
+    gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
     MOZ_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
     MOZ_ASSERT(!templateObject->numDynamicSlots());
 
     newGCThingPar(result, cx, tempReg1, tempReg2, allocKind, fail);
 }
 
 void
 MacroAssembler::newGCStringPar(Register result, Register cx, Register tempReg1, Register tempReg2,
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -3239,17 +3239,17 @@ MObjectState::Copy(TempAllocator &alloc,
 }
 
 bool
 MNewArray::shouldUseVM() const
 {
     MOZ_ASSERT(count() < JSObject::NELEMENTS_LIMIT);
 
     size_t arraySlots =
-        gc::GetGCKindSlots(templateObject()->asTenured()->getAllocKind()) - ObjectElements::VALUES_PER_HEADER;
+        gc::GetGCKindSlots(templateObject()->asTenured().getAllocKind()) - ObjectElements::VALUES_PER_HEADER;
 
     // Allocate space using the VMCall when mir hints it needs to get allocated
     // immediately, but only when data doesn't fit the available array slots.
     bool allocating = allocatingBehaviour() != NewArray_Unallocating && count() > arraySlots;
 
     return templateObject()->hasSingletonType() || allocating;
 }
 
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -1115,17 +1115,17 @@ RCreateThisWithTemplate::recover(JSConte
 {
     RootedObject templateObject(cx, &iter.read().toObject());
 
     // Use AutoEnterAnalysis to avoid invoking the object metadata callback
     // while bailing out, which could try to walk the stack.
     types::AutoEnterAnalysis enter(cx);
 
     // See CodeGenerator::visitCreateThisWithTemplate
-    gc::AllocKind allocKind = templateObject->asTenured()->getAllocKind();
+    gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
     gc::InitialHeap initialHeap = tenuredHeap_ ? gc::TenuredHeap : gc::DefaultHeap;
     JSObject *resultObject = JSObject::copy(cx, allocKind, initialHeap, templateObject);
     if (!resultObject)
         return false;
 
     RootedValue result(cx);
     result.setObject(*resultObject);
     iter.storeInstructionResult(result);
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1127,19 +1127,19 @@ AssertValidObjectPtr(JSContext *cx, JSOb
     MOZ_ASSERT(obj->compartment() == cx->compartment());
     MOZ_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
 
     MOZ_ASSERT_IF(!obj->hasLazyType(),
                   obj->type()->clasp() == obj->lastProperty()->getObjectClass());
 
     if (obj->isTenured()) {
         MOZ_ASSERT(obj->isAligned());
-        gc::AllocKind kind = obj->asTenured()->getAllocKind();
+        gc::AllocKind kind = obj->asTenured().getAllocKind();
         MOZ_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
-        MOZ_ASSERT(obj->asTenured()->zone() == cx->zone());
+        MOZ_ASSERT(obj->asTenured().zone() == cx->zone());
     }
 }
 
 void
 AssertValidStringPtr(JSContext *cx, JSString *str)
 {
     // We can't closely inspect strings from another runtime.
     if (str->runtimeFromAnyThread() != cx->runtime()) {
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -647,17 +647,17 @@ js::GCThingTraceKind(void *thing)
 }
 
 JS_FRIEND_API(void)
 js::VisitGrayWrapperTargets(Zone *zone, GCThingCallback callback, void *closure)
 {
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
         for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
             gc::Cell *thing = e.front().key().wrapped;
-            if (thing->isTenured() && thing->asTenured()->isMarked(gc::GRAY))
+            if (thing->isTenured() && thing->asTenured().isMarked(gc::GRAY))
                 callback(closure, thing);
         }
     }
 }
 
 JS_FRIEND_API(JSObject *)
 js::GetWeakmapKeyDelegate(JSObject *key)
 {
@@ -1184,17 +1184,17 @@ JS::IncrementalReferenceBarrier(void *pt
     if (kind == JSTRACE_STRING && StringIsPermanentAtom(static_cast<JSString *>(ptr)))
         return;
 
     gc::Cell *cell = static_cast<gc::Cell *>(ptr);
 
 #ifdef DEBUG
     Zone *zone = kind == JSTRACE_OBJECT
                  ? static_cast<JSObject *>(cell)->zone()
-                 : cell->asTenured()->zone();
+                 : cell->asTenured().zone();
     MOZ_ASSERT(!zone->runtimeFromMainThread()->isHeapMajorCollecting());
 #endif
 
     if (kind == JSTRACE_OBJECT)
         JSObject::writeBarrierPre(static_cast<JSObject*>(cell));
     else if (kind == JSTRACE_STRING)
         JSString::writeBarrierPre(static_cast<JSString*>(cell));
     else if (kind == JSTRACE_SYMBOL)
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -456,17 +456,17 @@ class JSFunction : public JSObject
 
   private:
     inline js::FunctionExtended *toExtended();
     inline const js::FunctionExtended *toExtended() const;
 
   public:
     inline bool isExtended() const {
         JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind);
-        MOZ_ASSERT_IF(isTenured(), !!(flags() & EXTENDED) == (asTenured()->getAllocKind() == ExtendedFinalizeKind));
+        MOZ_ASSERT_IF(isTenured(), !!(flags() & EXTENDED) == (asTenured().getAllocKind() == ExtendedFinalizeKind));
         return !!(flags() & EXTENDED);
     }
 
     /*
      * Accessors for data stored in extended functions. Use setExtendedSlot if
      * the function has already been initialized. Otherwise use
      * initExtendedSlot.
      */
@@ -479,17 +479,17 @@ class JSFunction : public JSObject
     static bool setTypeForScriptedFunction(js::ExclusiveContext *cx, js::HandleFunction fun,
                                            bool singleton = false);
 
     /* GC support. */
     js::gc::AllocKind getAllocKind() const {
         js::gc::AllocKind kind = FinalizeKind;
         if (isExtended())
             kind = ExtendedFinalizeKind;
-        MOZ_ASSERT_IF(isTenured(), kind == asTenured()->getAllocKind());
+        MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind());
         return kind;
     }
 };
 
 extern JSString *
 fun_toStringHelper(JSContext *cx, js::HandleObject obj, unsigned indent);
 
 inline JSFunction::Flags
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -498,17 +498,17 @@ Arena::finalize(FreeOp *fop, AllocKind t
     uintptr_t lastThing = thingsEnd() - thingSize;
 
     FreeSpan newListHead;
     FreeSpan *newListTail = &newListHead;
     size_t nmarked = 0;
 
     for (ArenaCellIterUnderFinalize i(&aheader); !i.done(); i.next()) {
         T *t = i.get<T>();
-        if (t->asTenured()->isMarked()) {
+        if (t->asTenured().isMarked()) {
             uintptr_t thing = reinterpret_cast<uintptr_t>(t);
             if (thing != firstThingOrSuccessorOfLastMarkedThing) {
                 // We just finished passing over one or more free things,
                 // so record a new FreeSpan.
                 newListTail->initBoundsUnchecked(firstThingOrSuccessorOfLastMarkedThing,
                                                  thing - thingSize);
                 newListTail = newListTail->nextSpanUnchecked();
             }
@@ -4194,39 +4194,39 @@ DropStringWrappers(JSRuntime *rt)
  */
 
 void
 JSCompartment::findOutgoingEdges(ComponentFinder<JS::Zone> &finder)
 {
     for (js::WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
         CrossCompartmentKey::Kind kind = e.front().key().kind;
         MOZ_ASSERT(kind != CrossCompartmentKey::StringWrapper);
-        TenuredCell *other = e.front().key().wrapped->asTenured();
+        TenuredCell &other = e.front().key().wrapped->asTenured();
         if (kind == CrossCompartmentKey::ObjectWrapper) {
             /*
              * Add edge to wrapped object compartment if wrapped object is not
              * marked black to indicate that wrapper compartment not be swept
              * after wrapped compartment.
              */
-            if (!other->isMarked(BLACK) || other->isMarked(GRAY)) {
-                JS::Zone *w = other->zone();
+            if (!other.isMarked(BLACK) || other.isMarked(GRAY)) {
+                JS::Zone *w = other.zone();
                 if (w->isGCMarking())
                     finder.addEdgeTo(w);
             }
         } else {
             MOZ_ASSERT(kind == CrossCompartmentKey::DebuggerScript ||
                        kind == CrossCompartmentKey::DebuggerSource ||
                        kind == CrossCompartmentKey::DebuggerObject ||
                        kind == CrossCompartmentKey::DebuggerEnvironment);
             /*
              * Add edge for debugger object wrappers, to ensure (in conjuction
              * with call to Debugger::findCompartmentEdges below) that debugger
              * and debuggee objects are always swept in the same group.
              */
-            JS::Zone *w = other->zone();
+            JS::Zone *w = other.zone();
             if (w->isGCMarking())
                 finder.addEdgeTo(w);
         }
     }
 
     Debugger::findCompartmentEdges(zone(), finder);
 }
 
@@ -4457,21 +4457,21 @@ MarkIncomingCrossCompartmentPointers(JSR
         for (JSObject *src = c->gcIncomingGrayPointers;
              src;
              src = NextIncomingCrossCompartmentPointer(src, unlinkList))
         {
             JSObject *dst = CrossCompartmentPointerReferent(src);
             MOZ_ASSERT(dst->compartment() == c);
 
             if (color == GRAY) {
-                if (IsObjectMarked(&src) && src->asTenured()->isMarked(GRAY))
+                if (IsObjectMarked(&src) && src->asTenured().isMarked(GRAY))
                     MarkGCThingUnbarriered(&rt->gc.marker, (void**)&dst,
                                            "cross-compartment gray pointer");
             } else {
-                if (IsObjectMarked(&src) && !src->asTenured()->isMarked(GRAY))
+                if (IsObjectMarked(&src) && !src->asTenured().isMarked(GRAY))
                     MarkGCThingUnbarriered(&rt->gc.marker, (void**)&dst,
                                            "cross-compartment black pointer");
             }
         }
 
         if (unlinkList)
             c->gcIncomingGrayPointers = nullptr;
     }
@@ -6336,27 +6336,27 @@ AutoDisableProxyCheck::~AutoDisableProxy
 {
     gc.enableStrictProxyChecking();
 }
 
 JS_FRIEND_API(void)
 JS::AssertGCThingMustBeTenured(JSObject *obj)
 {
     MOZ_ASSERT(obj->isTenured() &&
-               (!IsNurseryAllocable(obj->asTenured()->getAllocKind()) || obj->getClass()->finalize));
+               (!IsNurseryAllocable(obj->asTenured().getAllocKind()) || obj->getClass()->finalize));
 }
 
 JS_FRIEND_API(void)
 js::gc::AssertGCThingHasType(js::gc::Cell *cell, JSGCTraceKind kind)
 {
     MOZ_ASSERT(cell);
     if (IsInsideNursery(cell))
         MOZ_ASSERT(kind == JSTRACE_OBJECT);
     else
-        MOZ_ASSERT(MapAllocToTraceKind(cell->asTenured()->getAllocKind()) == kind);
+        MOZ_ASSERT(MapAllocToTraceKind(cell->asTenured().getAllocKind()) == kind);
 }
 
 JS_FRIEND_API(size_t)
 JS::GetGCNumber()
 {
     JSRuntime *rt = js::TlsPerThreadData.get()->runtimeFromMainThread();
     if (!rt)
         return 0;
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -36,17 +36,17 @@ ThreadSafeContext::isThreadLocal(T thing
     if (cx->nursery().isInsideNewspace(thing))
         return true;
 #endif
 
     // Global invariant
     MOZ_ASSERT(!IsInsideNursery(thing));
 
     // The thing is not in the nursery, but is it in the private tenured area?
-    if (allocator_->arenas.containsArena(runtime_, thing->asTenured()->arenaHeader()))
+    if (allocator_->arenas.containsArena(runtime_, thing->asTenured().arenaHeader()))
     {
         // GC should be suppressed in preparation for mutating thread local
         // objects, as we don't want to trip any barriers.
         MOZ_ASSERT(!thing->zoneFromAnyThread()->needsIncrementalBarrier());
         MOZ_ASSERT(!thing->runtimeFromAnyThread()->needsIncrementalBarrier());
 
         return true;
     }
@@ -87,17 +87,17 @@ inline JSGCTraceKind
 GetGCThingTraceKind(const void *thing)
 {
     MOZ_ASSERT(thing);
     const Cell *cell = static_cast<const Cell *>(thing);
 #ifdef JSGC_GENERATIONAL
     if (IsInsideNursery(cell))
         return JSTRACE_OBJECT;
 #endif
-    return MapAllocToTraceKind(cell->asTenured()->getAllocKind());
+    return MapAllocToTraceKind(cell->asTenured().getAllocKind());
 }
 
 inline void
 GCRuntime::poke()
 {
     poked = true;
 
 #ifdef JS_GC_ZEAL
@@ -541,17 +541,17 @@ static inline void
 CheckIncrementalZoneState(ThreadSafeContext *cx, T *t)
 {
 #ifdef DEBUG
     if (!cx->isJSContext())
         return;
 
     Zone *zone = cx->asJSContext()->zone();
     MOZ_ASSERT_IF(t && zone->wasGCStarted() && (zone->isGCMarking() || zone->isGCSweeping()),
-                  t->asTenured()->arenaHeader()->allocatedDuringIncremental);
+                  t->asTenured().arenaHeader()->allocatedDuringIncremental);
 #endif
 }
 
 /*
  * Allocate a new GC thing. After a successful allocation the caller must
  * fully initialize the thing before calling any function that can potentially
  * trigger GC. This will ensure that GC tracing never sees junk values stored
  * in the partially initialized thing.
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2050,17 +2050,17 @@ js::DeepCloneObjectLiteral(JSContext *cx
     RootedValue v(cx);
     RootedObject deepObj(cx);
 
     if (obj->is<ArrayObject>()) {
         clone = NewDenseUnallocatedArray(cx, obj->as<ArrayObject>().length(), nullptr, newKind);
     } else {
         // Object literals are tenured by default as holded by the JSScript.
         MOZ_ASSERT(obj->isTenured());
-        AllocKind kind = obj->asTenured()->getAllocKind();
+        AllocKind kind = obj->asTenured().getAllocKind();
         Rooted<TypeObject*> typeObj(cx, obj->getType(cx));
         if (!typeObj)
             return nullptr;
         RootedObject parent(cx, obj->getParent());
         clone = NewObjectWithGivenProto(cx, &JSObject::class_, TaggedProto(typeObj->proto().toObject()),
                                         parent, kind, newKind);
     }
 
@@ -2158,17 +2158,17 @@ js::XDRObjectLiteral(XDRState<mode> *xdr
 
     } else {
         // Code the alloc kind of the object.
         AllocKind kind;
         {
             if (mode == XDR_ENCODE) {
                 MOZ_ASSERT(obj->getClass() == &JSObject::class_);
                 MOZ_ASSERT(obj->isTenured());
-                kind = obj->asTenured()->getAllocKind();
+                kind = obj->asTenured().getAllocKind();
             }
 
             if (!xdr->codeEnum32(&kind))
                 return false;
 
             if (mode == XDR_DECODE)
                 obj.set(NewBuiltinClassInstance(cx, &JSObject::class_, kind, js::MaybeSingletonObject));
         }
@@ -2356,17 +2356,17 @@ js::XDRObjectLiteral(XDRState<XDR_ENCODE
 template bool
 js::XDRObjectLiteral(XDRState<XDR_DECODE> *xdr, MutableHandleObject obj);
 
 JSObject *
 js::CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj)
 {
     if (srcObj->getClass() == &JSObject::class_) {
         AllocKind kind = GetBackgroundAllocKind(GuessObjectGCKind(srcObj->numFixedSlots()));
-        MOZ_ASSERT_IF(srcObj->isTenured(), kind == srcObj->asTenured()->getAllocKind());
+        MOZ_ASSERT_IF(srcObj->isTenured(), kind == srcObj->asTenured().getAllocKind());
 
         JSObject *proto = cx->global()->getOrCreateObjectPrototype(cx);
         if (!proto)
             return nullptr;
         Rooted<TypeObject*> typeObj(cx, cx->getNewType(&JSObject::class_, TaggedProto(proto)));
         if (!typeObj)
             return nullptr;
 
@@ -2386,17 +2386,17 @@ js::CloneObjectLiteral(JSContext *cx, Ha
     RootedId id(cx);
     RootedValue value(cx);
     for (size_t i = 0; i < length; i++) {
         // The only markable values in copy on write arrays are atoms, which
         // can be freely copied between compartments.
         value = srcObj->getDenseElement(i);
         MOZ_ASSERT_IF(value.isMarkable(),
                       value.toGCThing()->isTenured() &&
-                      cx->runtime()->isAtomsZone(value.toGCThing()->asTenured()->zone()));
+                      cx->runtime()->isAtomsZone(value.toGCThing()->asTenured().zone()));
 
         id = INT_TO_JSID(i);
         if (!JSObject::defineGeneric(cx, res, id, value, nullptr, nullptr, JSPROP_ENUMERATE))
             return nullptr;
     }
 
     if (!ObjectElements::MakeElementsCopyOnWrite(cx, res))
         return nullptr;
@@ -2471,26 +2471,26 @@ JSObject::ReserveForTradeGuts(JSContext 
      * inline slots. The fixed slots will be updated in place during TradeGuts.
      * Non-native objects need to be reshaped according to the new count.
      */
     if (a->isNative()) {
         if (!a->generateOwnShape(cx))
             MOZ_CRASH();
     } else {
         reserved.newbshape = EmptyShape::getInitialShape(cx, aClass, aProto, a->getParent(), a->getMetadata(),
-                                                         b->asTenured()->getAllocKind());
+                                                         b->asTenured().getAllocKind());
         if (!reserved.newbshape)
             MOZ_CRASH();
     }
     if (b->isNative()) {
         if (!b->generateOwnShape(cx))
             MOZ_CRASH();
     } else {
         reserved.newashape = EmptyShape::getInitialShape(cx, bClass, bProto, b->getParent(), b->getMetadata(),
-                                                         a->asTenured()->getAllocKind());
+                                                         a->asTenured().getAllocKind());
         if (!reserved.newashape)
             MOZ_CRASH();
     }
 
     /* The avals/bvals vectors hold all original values from the objects. */
 
     if (!reserved.avals.reserve(a->slotSpan()))
         MOZ_CRASH();
@@ -2680,18 +2680,18 @@ JSObject::TradeGuts(JSContext *cx, JSObj
 #endif
 }
 
 /* Use this method with extreme caution. It trades the guts of two objects. */
 bool
 JSObject::swap(JSContext *cx, HandleObject a, HandleObject b)
 {
     // Ensure swap doesn't cause a finalizer to not be run.
-    MOZ_ASSERT(IsBackgroundFinalized(a->asTenured()->getAllocKind()) ==
-               IsBackgroundFinalized(b->asTenured()->getAllocKind()));
+    MOZ_ASSERT(IsBackgroundFinalized(a->asTenured().getAllocKind()) ==
+               IsBackgroundFinalized(b->asTenured().getAllocKind()));
     MOZ_ASSERT(a->compartment() == b->compartment());
 
     unsigned r = NotifyGCPreSwap(a, b);
 
     TradeGutsReserved reserved(cx);
     if (!ReserveForTradeGuts(cx, a, b, reserved)) {
         NotifyGCPostSwap(b, a, r);
         return false;
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -79,17 +79,17 @@ JSObject::unwatch(JSContext *cx, JS::Han
 
 inline void
 JSObject::finalize(js::FreeOp *fop)
 {
     js::probes::FinalizeObject(this);
 
 #ifdef DEBUG
     MOZ_ASSERT(isTenured());
-    if (!IsBackgroundFinalized(asTenured()->getAllocKind())) {
+    if (!IsBackgroundFinalized(asTenured().getAllocKind())) {
         /* Assert we're on the main thread. */
         MOZ_ASSERT(CurrentThreadCanAccessRuntime(fop->runtime()));
     }
 #endif
     const js::Class *clasp = getClass();
     if (clasp->finalize)
         clasp->finalize(fop, this);
 
@@ -1094,17 +1094,17 @@ NewObjectScriptedCall(JSContext *cx, Mut
 static inline JSObject *
 CopyInitializerObject(JSContext *cx, HandleObject baseobj, NewObjectKind newKind = GenericObject)
 {
     MOZ_ASSERT(baseobj->getClass() == &JSObject::class_);
     MOZ_ASSERT(!baseobj->inDictionaryMode());
 
     gc::AllocKind allocKind = gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots());
     allocKind = gc::GetBackgroundAllocKind(allocKind);
-    MOZ_ASSERT_IF(baseobj->isTenured(), allocKind == baseobj->asTenured()->getAllocKind());
+    MOZ_ASSERT_IF(baseobj->isTenured(), allocKind == baseobj->asTenured().getAllocKind());
     RootedObject obj(cx);
     obj = NewBuiltinClassInstance(cx, &JSObject::class_, allocKind, newKind);
     if (!obj)
         return nullptr;
 
     RootedObject metadata(cx, obj->getMetadata());
     RootedShape lastProp(cx, baseobj->lastProperty());
     if (!JSObject::setLastProperty(cx, obj, lastProp))
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2911,17 +2911,17 @@ Rebase(JSScript *dst, JSScript *src, T *
 
 JSScript *
 js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, HandleScript src,
                 NewObjectKind newKind /* = GenericObject */)
 {
     /* NB: Keep this in sync with XDRScript. */
 
     /* Some embeddings are not careful to use ExposeObjectToActiveJS as needed. */
-    MOZ_ASSERT(!src->sourceObject()->asTenured()->isMarked(gc::GRAY));
+    MOZ_ASSERT(!src->sourceObject()->asTenured().isMarked(gc::GRAY));
 
     uint32_t nconsts   = src->hasConsts()   ? src->consts()->length   : 0;
     uint32_t nobjects  = src->hasObjects()  ? src->objects()->length  : 0;
     uint32_t nregexps  = src->hasRegexps()  ? src->regexps()->length  : 0;
     uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
     uint32_t nblockscopes = src->hasBlockScopes() ? src->blockScopes()->length : 0;
 
     /* Script data */
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -175,17 +175,17 @@ ObjectValueMap::findZoneEdges()
      * For unmarked weakmap keys with delegates in a different zone, add a zone
      * edge to ensure that the delegate zone does finish marking after the key
      * zone.
      */
     JS::AutoSuppressGCAnalysis nogc;
     Zone *mapZone = compartment->zone();
     for (Range r = all(); !r.empty(); r.popFront()) {
         JSObject *key = r.front().key();
-        if (key->asTenured()->isMarked(BLACK) && !key->asTenured()->isMarked(GRAY))
+        if (key->asTenured().isMarked(BLACK) && !key->asTenured().isMarked(GRAY))
             continue;
         JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp;
         if (!op)
             continue;
         JSObject *delegate = op(key);
         if (!delegate)
             continue;
         Zone *delegateZone = delegate->zone();
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -160,10 +160,10 @@ bool Wrapper::finalizeInBackground(Value
      * Make the 'background-finalized-ness' of the wrapper the same as the
      * wrapped object, to allow transplanting between them.
      *
      * If the wrapped object is in the nursery then we know it doesn't have a
      * finalizer, and so background finalization is ok.
      */
     if (IsInsideNursery(&priv.toObject()))
         return true;
-    return IsBackgroundFinalized(priv.toObject().asTenured()->getAllocKind());
+    return IsBackgroundFinalized(priv.toObject().asTenured().getAllocKind());
 }
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -5283,16 +5283,26 @@ DebuggerObject_getEnvironment(JSContext 
         if (!env)
             return false;
     }
 
     return dbg->wrapEnvironment(cx, env, args.rval());
 }
 
 static bool
+DebuggerObject_getIsArrowFunction(JSContext *cx, unsigned argc, Value *vp)
+{
+    THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get isArrowFunction", args, refobj);
+
+    args.rval().setBoolean(refobj->is<JSFunction>()
+                           && refobj->as<JSFunction>().isArrow());
+    return true;
+}
+
+static bool
 DebuggerObject_getIsBoundFunction(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get isBoundFunction", args, refobj);
 
     args.rval().setBoolean(refobj->isBoundFunction());
     return true;
 }
 
@@ -5862,16 +5872,17 @@ static const JSPropertySpec DebuggerObje
     JS_PSG("proto", DebuggerObject_getProto, 0),
     JS_PSG("class", DebuggerObject_getClass, 0),
     JS_PSG("callable", DebuggerObject_getCallable, 0),
     JS_PSG("name", DebuggerObject_getName, 0),
     JS_PSG("displayName", DebuggerObject_getDisplayName, 0),
     JS_PSG("parameterNames", DebuggerObject_getParameterNames, 0),
     JS_PSG("script", DebuggerObject_getScript, 0),
     JS_PSG("environment", DebuggerObject_getEnvironment, 0),
+    JS_PSG("isArrowFunction", DebuggerObject_getIsArrowFunction, 0),
     JS_PSG("isBoundFunction", DebuggerObject_getIsBoundFunction, 0),
     JS_PSG("boundTargetFunction", DebuggerObject_getBoundTargetFunction, 0),
     JS_PSG("boundThis", DebuggerObject_getBoundThis, 0),
     JS_PSG("boundArguments", DebuggerObject_getBoundArguments, 0),
     JS_PSG("global", DebuggerObject_getGlobal, 0),
     JS_PSG("allocationSite", DebuggerObject_getAllocationSite, 0),
     JS_PS_END
 };
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -819,17 +819,17 @@ class ObjectImpl : public gc::Cell
      * capacity is not stored explicitly, and the allocated size of the slot
      * array is kept in sync with this count.
      */
     static uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class *clasp);
 
     /* Memory usage functions. */
     size_t tenuredSizeOfThis() const {
         MOZ_ASSERT(isTenured());
-        return js::gc::Arena::thingSize(asTenured()->getAllocKind());
+        return js::gc::Arena::thingSize(asTenured().getAllocKind());
     }
 
     /* Elements accessors. */
 
     ObjectElements * getElementsHeader() const {
         return ObjectElements::fromElements(elements);
     }
 
@@ -979,24 +979,24 @@ class ObjectImpl : public gc::Cell
     static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
     static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); }
 };
 
 /* static */ MOZ_ALWAYS_INLINE void
 ObjectImpl::readBarrier(ObjectImpl *obj)
 {
     if (!isNullLike(obj) && obj->isTenured())
-        obj->asTenured()->readBarrier(obj->asTenured());
+        obj->asTenured().readBarrier(&obj->asTenured());
 }
 
 /* static */ MOZ_ALWAYS_INLINE void
 ObjectImpl::writeBarrierPre(ObjectImpl *obj)
 {
     if (!isNullLike(obj) && obj->isTenured())
-        obj->asTenured()->writeBarrierPre(obj->asTenured());
+        obj->asTenured().writeBarrierPre(&obj->asTenured());
 }
 
 /* static */ MOZ_ALWAYS_INLINE void
 ObjectImpl::writeBarrierPost(ObjectImpl *obj, void *cellp)
 {
     MOZ_ASSERT(cellp);
 #ifdef JSGC_GENERATIONAL
     if (IsNullTaggedPointer(obj))
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -247,17 +247,17 @@ RegExpObject::trace(JSTracer *trc, JSObj
     // be collected. To detect this we need to test all the following
     // conditions, since:
     //   1. During TraceRuntime, isHeapBusy() is true, but the tracer might not
     //      be a marking tracer.
     //   2. When a write barrier executes, IS_GC_MARKING_TRACER is true, but
     //      isHeapBusy() will be false.
     if (trc->runtime()->isHeapBusy() &&
         IS_GC_MARKING_TRACER(trc) &&
-        !obj->asTenured()->zone()->isPreservingCode())
+        !obj->asTenured().zone()->isPreservingCode())
     {
         obj->setPrivate(nullptr);
     } else {
         shared->trace(trc);
     }
 }
 
 const Class RegExpObject::class_ = {
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1284,17 +1284,17 @@ CloneObject(JSContext *cx, HandleObject 
         if (!str)
             return nullptr;
         clone = StringObject::create(cx, str);
     } else if (selfHostedObject->is<ArrayObject>()) {
         clone = NewDenseEmptyArray(cx, nullptr, TenuredObject);
     } else {
         MOZ_ASSERT(selfHostedObject->isNative());
         clone = NewObjectWithGivenProto(cx, selfHostedObject->getClass(), TaggedProto(nullptr), cx->global(),
-                                        selfHostedObject->asTenured()->getAllocKind(),
+                                        selfHostedObject->asTenured().getAllocKind(),
                                         SingletonObject);
     }
     if (!clone)
         return nullptr;
     if (!CloneProperties(cx, selfHostedObject, clone))
         return nullptr;
     return clone;
 }
--- a/js/xpconnect/tests/chrome/chrome.ini
+++ b/js/xpconnect/tests/chrome/chrome.ini
@@ -62,16 +62,17 @@ skip-if = buildapp == 'mulet'
 [test_bug865948.xul]
 [test_bug866823.xul]
 [test_bug895340.xul]
 [test_bug932906.xul]
 [test_bug996069.xul]
 [test_bug1041626.xul]
 [test_bug1042436.xul]
 [test_bug1050049.html]
+[test_bug1074863.html]
 [test_xrayToJS.xul]
 skip-if = buildapp == 'mulet'
 [test_chrometoSource.xul]
 skip-if = buildapp == 'mulet'
 [test_cloneInto.xul]
 [test_cows.xul]
 skip-if = buildapp == 'mulet'
 [test_discardSystemSource.xul]
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/test_bug1074863.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1074863
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1074863</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1074863 **/
+  const Cu = Components.utils;
+  var sb = new Cu.Sandbox('http://www.example.com');
+  sb.namedCtor = Image;
+  ok(true, "Didn't assert");
+
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1074863">Mozilla Bug 1074863</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -109,16 +109,21 @@ WrapperFactory::WaiveXray(JSContext *cx,
 
 // In general, we're trying to deprecate COWs incrementally as we introduce
 // Xrays to the corresponding object types. But switching off COWs for certain
 // things would be too tumultuous at present, so we punt on them for later.
 static bool
 ForceCOWBehavior(JSObject *obj)
 {
     JSProtoKey key = IdentifyStandardInstanceOrPrototype(obj);
+    if (key == JSProto_Function && GetXrayType(obj) == XrayForDOMObject) {
+        // This means that we've got a DOM constructor, which we never want to
+        // expose COW-style.
+        return false;
+    }
     if (key == JSProto_Object || key == JSProto_Array || key == JSProto_Function) {
         MOZ_ASSERT(GetXrayType(obj) == XrayForJSObject,
                    "We should use XrayWrappers for standard ES Object, Array, and Function "
                    "instances modulo this hack");
         return true;
     }
 
     return false;
--- a/layout/base/ActiveLayerTracker.cpp
+++ b/layout/base/ActiveLayerTracker.cpp
@@ -277,17 +277,17 @@ ActiveLayerTracker::IsStyleAnimated(nsIF
       return true;
     }
   }
   if (aProperty == eCSSProperty_transform && aFrame->Preserves3D()) {
     return IsStyleAnimated(aFrame->GetParent(), aProperty);
   }
   nsIContent* content = aFrame->GetContent();
   if (content) {
-    return nsLayoutUtils::HasAnimations(content, aProperty);
+    return nsLayoutUtils::HasCurrentAnimationsForProperty(content, aProperty);
   }
 
   return false;
 }
 
 /* static */ bool
 ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(nsIFrame* aFrame)
 {
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -235,16 +235,19 @@ public:
   // CreateNeededFrames.
   // Note: It's the caller's responsibility to make sure to wrap a
   // ProcessPendingRestyles call in a view update batch and a script blocker.
   // This function does not call ProcessAttachedQueue() on the binding manager.
   // If the caller wants that to happen synchronously, it needs to handle that
   // itself.
   void ProcessPendingRestyles();
 
+  // Returns whether there are any pending restyles.
+  bool HasPendingRestyles() { return mPendingRestyles.Count() != 0; }
+
   // ProcessPendingRestyles calls into one of our RestyleTracker
   // objects.  It then calls back to these functions at the beginning
   // and end of its work.
   void BeginProcessingRestyles();
   void EndProcessingRestyles();
 
   // Update styles for animations that are running on the compositor and
   // whose updating is suppressed on the main thread (to save
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -90,16 +90,17 @@ class nsAccessibilityService;
 namespace mozilla {
 namespace a11y {
 class DocAccessible;
 } // namespace a11y
 } // namespace mozilla
 #endif
 class nsIWidget;
 struct nsArenaMemoryStats;
+class nsITimer;
 
 typedef short SelectionType;
 
 namespace mozilla {
 class EventStates;
 
 namespace dom {
 class Element;
@@ -1606,16 +1607,19 @@ public:
   bool IsNeverPainting() {
     return mIsNeverPainting;
   }
 
   void SetNeverPainting(bool aNeverPainting) {
     mIsNeverPainting = aNeverPainting;
   }
 
+  bool HasPendingReflow() const
+    { return mReflowScheduled || mReflowContinueTimer; }
+
 protected:
   friend class nsRefreshDriver;
 
   // IMPORTANT: The ownership implicit in the following member variables
   // has been explicitly checked.  If you add any members to this class,
   // please make the ownership explicit (pinkerton, scc).
 
   // These are the same Document and PresContext owned by the DocViewer.
@@ -1631,16 +1635,22 @@ protected:
   // GetRootFrame() can be inlined:
   nsFrameManagerBase*       mFrameManager;
   mozilla::WeakPtr<nsDocShell>                 mForwardingContainer;
   nsRefreshDriver*          mHiddenInvalidationObserverRefreshDriver;
 #ifdef ACCESSIBILITY
   mozilla::a11y::DocAccessible* mDocAccessible;
 #endif
 
+  // At least on Win32 and Mac after interupting a reflow we need to post
+  // the resume reflow event off a timer to avoid event starvation because
+  // posted messages are processed before other messages when the modal
+  // moving/sizing loop is running, see bug 491700 for details.
+  nsCOMPtr<nsITimer>        mReflowContinueTimer;
+
 #ifdef DEBUG
   nsIFrame*                 mDrawEventTargetFrame;
   // Ensure that every allocation from the PresArena is eventually freed.
   uint32_t                  mPresArenaAllocCount;
 #endif
 
   // Count of the number of times this presshell has been painted to a window.
   uint64_t                  mPaintCount;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -389,28 +389,47 @@ nsLayoutUtils::HasAnimations(nsIContent*
   return GetAnimationsOrTransitions(aContent, nsGkAtoms::animationsProperty,
                                     aProperty) ||
          GetAnimationsOrTransitions(aContent, nsGkAtoms::transitionsProperty,
                                     aProperty);
 }
 
 bool
 nsLayoutUtils::HasCurrentAnimations(nsIContent* aContent,
-                                    nsIAtom* aAnimationProperty,
-                                    nsPresContext* aPresContext)
+                                    nsIAtom* aAnimationProperty)
 {
   if (!aContent->MayHaveAnimations())
     return false;
 
   AnimationPlayerCollection* collection =
     static_cast<AnimationPlayerCollection*>(
       aContent->GetProperty(aAnimationProperty));
   return (collection && collection->HasCurrentAnimations());
 }
 
+bool
+nsLayoutUtils::HasCurrentAnimationsForProperty(nsIContent* aContent,
+                                               nsCSSProperty aProperty)
+{
+  if (!aContent->MayHaveAnimations())
+    return false;
+
+  static nsIAtom* const sAnimProps[] = { nsGkAtoms::transitionsProperty,
+                                         nsGkAtoms::animationsProperty,
+                                         nullptr };
+  for (nsIAtom* const* animProp = sAnimProps; *animProp; animProp++) {
+    AnimationPlayerCollection* collection =
+      static_cast<AnimationPlayerCollection*>(aContent->GetProperty(*animProp));
+    if (collection && collection->HasCurrentAnimationsForProperty(aProperty))
+      return true;
+  }
+
+  return false;
+}
+
 static gfxSize
 GetScaleForValue(const StyleAnimationValue& aValue, nsIFrame* aFrame)
 {
   if (!aFrame) {
     NS_WARNING("No frame.");
     return gfxSize();
   }
   if (aValue.GetUnit() != StyleAnimationValue::eUnit_Transform) {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1874,23 +1874,30 @@ public:
 
   /**
    * Returns true if the content node has animations or transitions for the
    * property.
    */
   static bool HasAnimations(nsIContent* aContent, nsCSSProperty aProperty);
 
   /**
-   * Returns true if the content node has any current animations or transitions.
+   * Returns true if the content node has any current animations or transitions
+   * (depending on the value of |aAnimationProperty|).
    * A current animation is any animation that has not yet finished playing
    * including paused animations.
    */
   static bool HasCurrentAnimations(nsIContent* aContent,
-                                   nsIAtom* aAnimationProperty,
-                                   nsPresContext* aPresContext);
+                                   nsIAtom* aAnimationProperty);
+
+  /**
+   * Returns true if the content node has any current animations or transitions
+   * for the specified property.
+   */
+  static bool HasCurrentAnimationsForProperty(nsIContent* aContent,
+                                              nsCSSProperty aProperty);
 
   /**
    * Checks if off-main-thread animations are enabled.
    */
   static bool AreAsyncAnimationsEnabled();
 
   /**
    * Checks if we should warn about animations that can't be async
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -55,17 +55,17 @@
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/TabParent.h"
 #include "nsRefreshDriver.h"
 #include "Layers.h"
 #include "nsIDOMEvent.h"
 #include "gfxPrefs.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsFrameLoader.h"
-
+#include "mozilla/dom/FontFaceSet.h"
 #include "nsContentUtils.h"
 #include "nsPIWindowRoot.h"
 #include "mozilla/Preferences.h"
 
 // Needed for Start/Stop of Image Animation
 #include "imgIContainer.h"
 #include "nsIImageLoadingContent.h"
 
@@ -232,18 +232,17 @@ nsPresContext::nsPresContext(nsIDocument
   if (!IsDynamic()) {
     mImageAnimationMode = imgIContainer::kDontAnimMode;
     mNeverAnimate = true;
   } else {
     mImageAnimationMode = imgIContainer::kNormalAnimMode;
     mNeverAnimate = false;
   }
   NS_ASSERTION(mDocument, "Null document");
-  mUserFontSet = nullptr;
-  mUserFontSetDirty = true;
+  mFontFaceSetDirty = true;
 
   mCounterStylesDirty = true;
 
   // if text perf logging enabled, init stats struct
   PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textperf);
   if (log && log->level >= PR_LOG_WARNING) {
     mTextPerf = new gfxTextPerfMetrics();
   }
@@ -1089,20 +1088,20 @@ nsPresContext::Init(nsDeviceContext* aDe
   return NS_OK;
 }
 
 // Note: We don't hold a reference on the shell; it has a reference to
 // us
 void
 nsPresContext::SetShell(nsIPresShell* aShell)
 {
-  if (mUserFontSet) {
+  if (mFontFaceSet) {
     // Clear out user font set if we have one
-    mUserFontSet->Destroy();
-    NS_RELEASE(mUserFontSet);
+    mFontFaceSet->DestroyUserFontSet();
+    mFontFaceSet = nullptr;
   }
 
   if (mShell) {
     // Remove ourselves as the charset observer from the shell's doc, because
     // this shell may be going away for good.
     nsIDocument *doc = mShell->GetDocument();
     if (doc) {
       doc->RemoveCharSetObserver(this);
@@ -2063,29 +2062,33 @@ nsPresContext::GetUserFontSetInternal()
   // for somebody to call GetUserFontSet in order to rebuild it (see
   // comments below in RebuildUserFontSet for why).
 #ifdef DEBUG
   bool userFontSetGottenBefore = mGetUserFontSetCalled;
 #endif
   // Set mGetUserFontSetCalled up front, so that FlushUserFontSet will actually
   // flush.
   mGetUserFontSetCalled = true;
-  if (mUserFontSetDirty) {
+  if (mFontFaceSetDirty) {
     // If this assertion fails, and there have actually been changes to
     // @font-face rules, then we will call StyleChangeReflow in
     // FlushUserFontSet.  If we're in the middle of reflow,
     // that's a bad thing to do, and the caller was responsible for
     // flushing first.  If we're not (e.g., in frame construction), it's
     // ok.
     NS_ASSERTION(!userFontSetGottenBefore || !mShell->IsReflowLocked(),
                  "FlushUserFontSet should have been called first");
     FlushUserFontSet();
   }
 
-  return mUserFontSet;
+  if (!mFontFaceSet) {
+    return nullptr;
+  }
+
+  return mFontFaceSet->GetUserFontSet();
 }
 
 gfxUserFontSet*
 nsPresContext::GetUserFontSetExternal()
 {
   return GetUserFontSetInternal();
 }
 
@@ -2093,71 +2096,57 @@ void
 nsPresContext::FlushUserFontSet()
 {
   if (!mShell) {
     return; // we've been torn down
   }
 
   if (!mGetUserFontSetCalled) {
     return; // No one cares about this font set yet, but we want to be careful
-            // to not unset our mUserFontSetDirty bit, so when someone really
+            // to not unset our mFontFaceSetDirty bit, so when someone really
             // does we'll create it.
   }
 
-  if (mUserFontSetDirty) {
+  if (mFontFaceSetDirty) {
     if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
       nsTArray<nsFontFaceRuleContainer> rules;
       if (!mShell->StyleSet()->AppendFontFaceRules(this, rules)) {
-        if (mUserFontSet) {
-          mUserFontSet->Destroy();
-          NS_RELEASE(mUserFontSet);
-        }
         return;
       }
 
-      bool changed = false;
-
-      if (rules.Length() == 0) {
-        if (mUserFontSet) {
-          mUserFontSet->Destroy();
-          NS_RELEASE(mUserFontSet);
-          changed = true;
-        }
-      } else {
-        if (!mUserFontSet) {
-          mUserFontSet = new nsUserFontSet(this);
-          NS_ADDREF(mUserFontSet);
-        }
-        changed = mUserFontSet->UpdateRules(rules);
+      if (!mFontFaceSet) {
+        mFontFaceSet = new FontFaceSet(mDocument->GetInnerWindow(), this);
       }
+      mFontFaceSet->EnsureUserFontSet(this);
+      bool changed = mFontFaceSet->UpdateRules(rules);
 
       // We need to enqueue a style change reflow (for later) to
       // reflect that we're modifying @font-face rules.  (However,
       // without a reflow, nothing will happen to start any downloads
       // that are needed.)
       if (changed) {
         UserFontSetUpdated();
       }
     }
 
-    mUserFontSetDirty = false;
+    mFontFaceSetDirty = false;
   }
 }
 
 void
 nsPresContext::RebuildUserFontSet()
 {
   if (!mGetUserFontSetCalled) {
     // We want to lazily build the user font set the first time it's
     // requested (so we don't force creation of rule cascades too
     // early), so don't do anything now.
     return;
   }
 
-  mUserFontSetDirty = true;
+  mFontFaceSetDirty = true;
   mDocument->SetNeedStyleFlush();
 
   // Somebody has already asked for the user font set, so we need to
   // post an event to rebuild it.  Setting the user font set to be dirty
   // and lazily rebuilding it isn't sufficient, since it is only the act
   // of rebuilding it that will trigger the style change reflow that
   // calls GetUserFontSet.  (This reflow causes rebuilding of text runs,
   // which starts font loads, whose completion causes another style
@@ -2187,16 +2176,26 @@ nsPresContext::UserFontSetUpdated()
   //   2. Changing the value of the 'ex' and 'ch' units in style data,
   //      which also depend on font metrics.  Updating this information
   //      requires rebuilding the rule tree from the top, avoiding the
   //      reuse of cached data even when no style rules have changed.
 
   PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW);
 }
 
+FontFaceSet*
+nsPresContext::Fonts()
+{
+  if (!mFontFaceSet) {
+    mFontFaceSet = new FontFaceSet(mDocument->GetInnerWindow(), this);
+    GetUserFontSet();  // this will cause the user font set to be created/updated
+  }
+  return mFontFaceSet;
+}
+
 void
 nsPresContext::FlushCounterStyles()
 {
   if (!mShell) {
     return; // we've been torn down
   }
   if (mCounterStyleManager->IsInitial()) {
     // Still in its initial state, no need to clean.
@@ -2643,16 +2642,31 @@ nsPresContext::HavePendingInputEvent()
         }
       }
       return false;
     }
   }
 }
 
 void
+nsPresContext::NotifyFontFaceSetOnRefresh()
+{
+  if (mFontFaceSet) {
+    mFontFaceSet->DidRefresh();
+  }
+}
+
+bool
+nsPresContext::HasPendingRestyleOrReflow()
+{
+  return (mRestyleManager && mRestyleManager->HasPendingRestyles()) ||
+         PresShell()->HasPendingReflow();
+}
+
+void
 nsPresContext::ReflowStarted(bool aInterruptible)
 {
 #ifdef NOISY_INTERRUPTIBLE_REFLOW
   if (!aInterruptible) {
     printf("STARTING NONINTERRUPTIBLE REFLOW\n");
   }
 #endif
   // We don't support interrupting in paginated contexts, since page
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -53,30 +53,30 @@ class nsFrameManager;
 class nsILinkHandler;
 class nsIAtom;
 class nsICSSPseudoComparator;
 struct nsStyleBackground;
 struct nsStyleBorder;
 class nsIRunnable;
 class gfxUserFontSet;
 class gfxTextPerfMetrics;
-class nsUserFontSet;
 struct nsFontFaceRuleContainer;
 class nsPluginFrame;
 class nsTransitionManager;
 class nsAnimationManager;
 class nsRefreshDriver;
 class nsIWidget;
 class nsDeviceContext;
 
 namespace mozilla {
 class EventStateManager;
 class RestyleManager;
 class CounterStyleManager;
 namespace dom {
+class FontFaceSet;
 class MediaQueryList;
 }
 namespace layers {
 class ContainerLayer;
 }
 }
 
 // supported values for cached bool types
@@ -866,16 +866,18 @@ public:
   void FlushUserFontSet();
   void RebuildUserFontSet(); // asynchronously
 
   // Should be called whenever the set of fonts available in the user
   // font set changes (e.g., because a new font loads, or because the
   // user font set is changed and fonts become unavailable).
   void UserFontSetUpdated();
 
+  mozilla::dom::FontFaceSet* Fonts();
+
   void FlushCounterStyles();
   void RebuildCounterStyles(); // asynchronously
 
   // Ensure that it is safe to hand out CSS rules outside the layout
   // engine by ensuring that all CSS style sheets have unique inners
   // and, if necessary, synchronously rebuilding all style data.
   void EnsureSafeToHandOutCSSRules();
 
@@ -916,16 +918,27 @@ public:
 
   void SetProcessingAnimationStyleChange(bool aProcessing) {
     NS_ASSERTION(aProcessing != bool(mProcessingAnimationStyleChange),
                  "should never nest");
     mProcessingAnimationStyleChange = aProcessing;
   }
 
   /**
+   * Returns whether there are any pending restyles or reflows.
+   */
+  bool HasPendingRestyleOrReflow();
+
+  /**
+   * Informs the document's FontFaceSet that the refresh driver ticked,
+   * flushing style and layout.
+   */
+  void NotifyFontFaceSetOnRefresh();
+
+  /**
    * Notify the prescontext that the presshell is about to reflow a reflow root.
    * The single argument indicates whether this reflow should be interruptible.
    * If aInterruptible is false then CheckForInterrupt and HasPendingInterrupt
    * will always return false. If aInterruptible is true then CheckForInterrupt
    * will return true when a pending event is detected.  This is for use by the
    * presshell only.  Reflow code wanting to prevent interrupts should use
    * InterruptPreventer.
    */
@@ -1242,17 +1255,17 @@ protected:
   nsCOMPtr<nsITimer>    mPrefChangedTimer;
 
   FramePropertyTable    mPropertyTable;
 
   nsInvalidateRequestList mInvalidateRequestsSinceLastPaint;
   nsInvalidateRequestList mUndeliveredInvalidateRequestsBeforeLastPaint;
 
   // container for per-context fonts (downloadable, SVG, etc.)
-  nsUserFontSet*        mUserFontSet;
+  nsRefPtr<mozilla::dom::FontFaceSet> mFontFaceSet;
 
   // text performance metrics
   nsAutoPtr<gfxTextPerfMetrics>   mTextPerf;
 
   nsRect                mVisibleArea;
   nsSize                mPageSize;
   float                 mPageScale;
   float                 mPPScale;
@@ -1323,18 +1336,18 @@ protected:
   // Does the associated document use root-em (rem) units?
   unsigned              mUsesRootEMUnits : 1;
   // Does the associated document use viewport units (vw/vh/vmin/vmax)?
   unsigned              mUsesViewportUnits : 1;
 
   // Has there been a change to the viewport's dimensions?
   unsigned              mPendingViewportChange : 1;
 
-  // Is the current mUserFontSet valid?
-  unsigned              mUserFontSetDirty : 1;
+  // Is the current mFontFaceSet valid?
+  unsigned              mFontFaceSetDirty : 1;
   // Has GetUserFontSet() been called?
   unsigned              mGetUserFontSetCalled : 1;
   // Do we currently have an event posted to call FlushUserFontSet?
   unsigned              mPostedFlushUserFontSet : 1;
 
   // Is the current mCounterStyleManager valid?
   unsigned              mCounterStylesDirty : 1;
   // Do we currently have an event posted to call FlushCounterStyles?
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -773,22 +773,16 @@ protected:
   nsRefPtr<mozilla::TouchCaret> mTouchCaret;
   nsRefPtr<mozilla::SelectionCarets> mSelectionCarets;
 
   // This timer controls painting suppression.  Until it fires
   // or all frames are constructed, we won't paint anything but
   // our <body> background and scrollbars.
   nsCOMPtr<nsITimer>        mPaintSuppressionTimer;
 
-  // At least on Win32 and Mac after interupting a reflow we need to post
-  // the resume reflow event off a timer to avoid event starvation because
-  // posted messages are processed before other messages when the modal
-  // moving/sizing loop is running, see bug 491700 for details.
-  nsCOMPtr<nsITimer>        mReflowContinueTimer;
-
   nsCOMPtr<nsITimer>        mDelayedPaintTimer;
 
   // The `performance.now()` value when we last started to process reflows.
   DOMHighResTimeStamp       mLastReflowStart;
 
   mozilla::TimeStamp        mLoadBegin;  // used to time loads
 
   // Information needed to properly handle scrolling content into view if the
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1236,16 +1236,23 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
             profiler_tracing("Paint", "Styles", mStyleCause, TRACING_INTERVAL_START);
             mStyleCause = nullptr;
           }
 
           NS_ADDREF(shell);
           mStyleFlushObservers.RemoveElement(shell);
           shell->GetPresContext()->RestyleManager()->mObservingRefreshDriver = false;
           shell->FlushPendingNotifications(ChangesToFlush(Flush_Style, false));
+          // Inform the FontFaceSet that we ticked, so that it can resolve its
+          // ready promise if it needs to (though it might still be waiting on
+          // a layout flush).
+          nsPresContext* presContext = shell->GetPresContext();
+          if (presContext) {
+            presContext->NotifyFontFaceSetOnRefresh();
+          }
           NS_RELEASE(shell);
 
           if (docShell) {
             docShell->AddProfileTimelineMarker("Styles", TRACING_INTERVAL_END);
           }
         }
 
         if (tracingStyleFlush) {
@@ -1277,16 +1284,22 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
           }
 
           NS_ADDREF(shell);
           mLayoutFlushObservers.RemoveElement(shell);
           shell->mReflowScheduled = false;
           shell->mSuppressInterruptibleReflows = false;
           shell->FlushPendingNotifications(ChangesToFlush(Flush_InterruptibleLayout,
                                                           false));
+          // Inform the FontFaceSet that we ticked, so that it can resolve its
+          // ready promise if it needs to.
+          nsPresContext* presContext = shell->GetPresContext();
+          if (presContext) {
+            presContext->NotifyFontFaceSetOnRefresh();
+          }
           NS_RELEASE(shell);
         }
 
         if (tracingLayoutFlush) {
           profiler_tracing("Paint", "Reflow", TRACING_INTERVAL_END);
         }
       }
     }
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -26,16 +26,17 @@
 #include "nsListControlFrame.h"
 #include "nsAutoPtr.h"
 #include "nsStyleSet.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsLayoutUtils.h"
 #include "nsDisplayList.h"
 #include "nsITheme.h"
+#include "nsThemeConstants.h"
 #include "nsRenderingContext.h"
 #include "mozilla/Likely.h"
 #include <algorithm>
 #include "nsTextNode.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
@@ -729,18 +730,21 @@ nsComboboxControlFrame::GetIntrinsicISiz
     dropdownContentWidth = NSCoordSaturatingSubtract(dropdownContentWidth,
                                                      scrollbarWidth,
                                                      nscoord_MAX);
 
     displayWidth = std::max(dropdownContentWidth, displayWidth);
   }
 
   // add room for the dropmarker button if there is one
-  if (!IsThemed() || presContext->GetTheme()->ThemeNeedsComboboxDropmarker())
+  if ((!IsThemed() ||
+       presContext->GetTheme()->ThemeNeedsComboboxDropmarker()) &&
+      StyleDisplay()->mAppearance != NS_THEME_NONE) {
     displayWidth += scrollbarWidth;
+  }
 
   return displayWidth;
 
 }
 
 nscoord
 nsComboboxControlFrame::GetMinISize(nsRenderingContext *aRenderingContext)
 {
@@ -808,17 +812,18 @@ nsComboboxControlFrame::Reflow(nsPresCon
     // it's released in its ReflowFinished / ReflowCallbackCanceled.
     unused << resize.forget();
   }
 
   // Get the width of the vertical scrollbar.  That will be the width of the
   // dropdown button.
   nscoord buttonWidth;
   const nsStyleDisplay *disp = StyleDisplay();
-  if (IsThemed(disp) && !aPresContext->GetTheme()->ThemeNeedsComboboxDropmarker()) {
+  if ((IsThemed(disp) && !aPresContext->GetTheme()->ThemeNeedsComboboxDropmarker()) ||
+      StyleDisplay()->mAppearance == NS_THEME_NONE) {
     buttonWidth = 0;
   }
   else {
     nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame);
     NS_ASSERTION(scrollable, "List must be a scrollable frame");
     buttonWidth = scrollable->GetNondisappearingScrollbarWidth(
       PresContext(), aReflowState.rendContext);
     if (buttonWidth > aReflowState.ComputedWidth()) {
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/BasicEvents.h"
 #include "mozilla/EventStates.h"
 #include "nsContentUtils.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentList.h"
 #include "nsStyleSet.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsThreadUtils.h"
+#include "mozilla/FloatingPoint.h"
 
 #ifdef ACCESSIBILITY
 #include "mozilla/a11y/AccTypes.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -767,17 +768,17 @@ nsNumberControlFrame::GetValueOfAnonText
   // number format does not allow the ',' grouping separator. We can detect all
   // the cases where we need to convert by seeing if the locale-specific
   // parsing function understands the user input to mean the same thing as the
   // HTML-5-conforming parsing function. If so, then we should return the value
   // as-is to avoid normalization. Otherwise, we return the de-localized
   // serialization.
   ICUUtils::LanguageTagIterForContent langTagIter(mContent);
   double value = ICUUtils::ParseNumber(aValue, langTagIter);
-  if (NS_finite(value) &&
+  if (IsFinite(value) &&
       value != HTMLInputElement::StringToDecimal(aValue).toDouble()) {
     aValue.Truncate();
     aValue.AppendFloat(value);
   }
 #endif
   // else, we return whatever FromContent put into aValue (the number as typed
   // in by the user)
 }
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -16,16 +16,17 @@
 #include "nsPlaceholderFrame.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include "nsStyleContext.h"
 #include "nsStyleUtil.h"
 #include "prlog.h"
 #include <algorithm>
 #include "mozilla/LinkedList.h"
+#include "mozilla/FloatingPoint.h"
 
 using namespace mozilla;
 using namespace mozilla::layout;
 
 // Convenience typedefs for helper classes that we forward-declare in .h file
 // (so that nsFlexContainerFrame methods can use them as parameters):
 typedef nsFlexContainerFrame::FlexItem FlexItem;
 typedef nsFlexContainerFrame::FlexLine FlexLine;
@@ -2123,17 +2124,17 @@ FlexLine::ResolveFlexibleLengths(nscoord
           float curWeight = item->GetWeight(isUsingFlexGrow);
           float curFlexFactor = item->GetFlexFactor(isUsingFlexGrow);
           MOZ_ASSERT(curWeight >= 0.0f, "weights are non-negative");
           MOZ_ASSERT(curFlexFactor >= 0.0f, "flex factors are non-negative");
 
           weightSum += curWeight;
           flexFactorSum += curFlexFactor;
 
-          if (NS_finite(weightSum)) {
+          if (IsFinite(weightSum)) {
             if (curWeight == 0.0f) {
               item->SetShareOfWeightSoFar(0.0f);
             } else {
               item->SetShareOfWeightSoFar(curWeight / weightSum);
             }
           } // else, the sum of weights overflows to infinity, in which
             // case we don't bother with "SetShareOfWeightSoFar" since
             // we know we won't use it. (instead, we'll just give every
@@ -2194,17 +2195,17 @@ FlexLine::ResolveFlexibleLengths(nscoord
           MOZ_ASSERT(item,
                      "numUnfrozenItemsToBeSeen says items remain to be seen");
           if (!item->IsFrozen()) {
             numUnfrozenItemsToBeSeen--;
 
             // To avoid rounding issues, we compute the change in size for this
             // item, and then subtract it from the remaining available space.
             nscoord sizeDelta = 0;
-            if (NS_finite(weightSum)) {
+            if (IsFinite(weightSum)) {
               float myShareOfRemainingSpace =
                 item->GetShareOfWeightSoFar();
 
               MOZ_ASSERT(myShareOfRemainingSpace >= 0.0f &&
                          myShareOfRemainingSpace <= 1.0f,
                          "my share should be nonnegative fractional amount");
 
               if (myShareOfRemainingSpace == 1.0f) {
--- a/layout/inspector/nsFontFace.cpp
+++ b/layout/inspector/nsFontFace.cpp
@@ -5,16 +5,20 @@
 #include "nsFontFace.h"
 #include "nsIDOMCSSFontFaceRule.h"
 #include "nsCSSRules.h"
 #include "gfxTextRun.h"
 #include "gfxUserFontSet.h"
 #include "nsFontFaceLoader.h"
 #include "mozilla/gfx/2D.h"
 #include "zlib.h"
+#include "mozilla/dom/FontFaceSet.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
 
 nsFontFace::nsFontFace(gfxFontEntry*      aFontEntry,
                        gfxFontGroup*      aFontGroup,
                        uint8_t            aMatchType)
   : mFontEntry(aFontEntry),
     mFontGroup(aFontGroup),
     mMatchType(aMatchType)
 {
@@ -83,20 +87,23 @@ nsFontFace::GetCSSFamilyName(nsAString &
 /* readonly attribute nsIDOMCSSFontFaceRule rule; */
 NS_IMETHODIMP
 nsFontFace::GetRule(nsIDOMCSSFontFaceRule **aRule)
 {
   // check whether this font entry is associated with an @font-face rule
   // in the relevant font group's user font set
   nsCSSFontFaceRule* rule = nullptr;
   if (mFontEntry->IsUserFont()) {
-    nsUserFontSet* fontSet =
-      static_cast<nsUserFontSet*>(mFontGroup->GetUserFontSet());
+    FontFaceSet::UserFontSet* fontSet =
+      static_cast<FontFaceSet::UserFontSet*>(mFontGroup->GetUserFontSet());
     if (fontSet) {
-      rule = fontSet->FindRuleForEntry(mFontEntry);
+      FontFaceSet* fontFaceSet = fontSet->GetFontFaceSet();
+      if (fontFaceSet) {
+        rule = fontFaceSet->FindRuleForEntry(mFontEntry);
+      }
     }
   }
 
   NS_IF_ADDREF(*aRule = rule);
   return NS_OK;
 }
 
 /* readonly attribute long srcIndex; */
--- a/layout/reftests/css-enabled/select/reftest.list
+++ b/layout/reftests/css-enabled/select/reftest.list
@@ -1,9 +1,9 @@
 == select-fieldset-1.html select-fieldset-ref.html
-fails-if(Android||B2G) == select-fieldset-2.html select-fieldset-ref-disabled.html
-fails-if(Android||B2G) == select-fieldset-3.html select-fieldset-ref-disabled.html
+fails-if(B2G) == select-fieldset-2.html select-fieldset-ref-disabled.html
+fails-if(B2G) == select-fieldset-3.html select-fieldset-ref-disabled.html
 == select-fieldset-4.html select-fieldset-ref.html
 == select-fieldset-legend-1.html select-fieldset-legend-ref-1.html
-fails-if(Android||B2G) == select-fieldset-legend-2.html select-fieldset-legend-ref-2.html
-fails-if(Android||B2G) == select-fieldset-legend-3.html select-fieldset-legend-ref-3.html
+fails-if(B2G) == select-fieldset-legend-2.html select-fieldset-legend-ref-2.html
+fails-if(B2G) == select-fieldset-legend-3.html select-fieldset-legend-ref-3.html
 == select-fieldset-legend-4.html select-fieldset-legend-ref-4.html
 == select-fieldset-legend-5.html select-fieldset-legend-ref-5.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/dynamic-insert-1-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+@font-face {
+  font-family: One;
+  src: url(../fonts/markA.ttf);
+}
+body { font-family: One; }
+</style>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/dynamic-insert-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<style>
+body { font-family: One; }
+</style>
+<script>
+window.addEventListener("MozReftestInvalidate", function() {
+  var face = new FontFace("One", "url(../fonts/markA.ttf)");
+  face.load().then(function() {
+    document.fonts.add(face);
+    document.documentElement.className = "";
+  });
+});
+</script>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/dynamic-remove-1-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+@font-face {
+  font-family: One;
+  src: url(../fonts/markA.ttf);
+}
+body { font-family: One; }
+</style>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/dynamic-remove-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<style>
+body { font-family: One; }
+</style>
+<script>
+var f1 = new FontFace("One", "url(../fonts/markA.ttf)");
+var f2 = new FontFace("One", "url(../fonts/mark2A.ttf)");
+
+f1.load();
+f2.load();
+
+Promise.all([f1.load(), f2.load()])
+  .then(function() {
+    document.fonts.add(f1);
+    document.fonts.add(f2);
+  })
+  .then(document.fonts.ready)
+  .then(function() {
+    document.fonts.delete(f2);
+    document.documentElement.className = "";
+  });
+</script>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/ex-unit-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<!-- modeled on ../font-face/ex-unit-1.html -->
+<html class="reftest-wait">
+<title>ex unit with Ahem font</title>
+<style>
+html { background: white; }
+body { font-family: Ahhhem; font-size: 50px; height: 2ex; width: 2ex; background: blue;  }
+</style>
+<script>
+document.fonts.add(new FontFace("Ahhhem", "url(../fonts/Ahem.ttf)"));
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/name-collision.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<!-- modeled after ../font-face/name-collision.html -->
+<html class="reftest-wait">
+<!--
+  Font family names in @font-face rules take precedence over locally-available font families,
+  so none of the names of commonly used platform fonts should match against locally available
+  fonts.
+-->
+<style>
+body { margin: 50px; font-family: fallback; }
+table { font-family: Sample; margin-left: 3em; }
+.sample { font-family: Sample, fallback; }
+table td { font-size: 24pt; }
+
+/* Windows */
+
+.arial { font-family: Arial, fallback; }
+.timesnewroman { font-family: Times New Roman, fallback; }
+.couriernew { font-family: Courier New, fallback; }
+
+/* Mac OS X */
+
+.futura { font-family: Futura, fallback; }
+.helvetica { font-family: Helvetica, fallback; }
+.times { font-family: Times, fallback; }
+.courier { font-family: Courier, fallback; }
+
+/* Linux */
+
+.bitstreamverasans { font-family: Bitstream Vera Sans, fallback; }
+.dejavusans { font-family: DejaVu Sans, fallback; }
+.freesans { font-family: FreeSans, fallback; }
+</style>
+<script>
+function addTestFont(aFamily) {
+  document.fonts.add(new FontFace(aFamily, "url(../fonts/mplus/mplus-1p-black.ttf)", { weight: 900 }));
+}
+
+document.fonts.add(new FontFace("fallback", "url(../fonts/mplus/mplus-1p-regular.ttf)"));
+
+addTestFont("Sample");
+
+/* Windows */
+
+addTestFont("Arial");
+addTestFont("Times New Roman");
+addTestFont("Courier New");
+
+/* Mac OS X */
+
+addTestFont("Futura");
+addTestFont("Helvetica");
+addTestFont("Times");
+addTestFont("Courier");
+
+/* Linux */
+
+addTestFont("Bitstream Vera Sans");
+addTestFont("DejaVu Sans");
+addTestFont("FreeSans");
+
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
+
+<p>All text below should appear in the same extra bold font face:</p>
+
+<table>
+<tr class="sample"><td>Sample</td></tr>
+<tr class="arial"><td>Arial</td></tr>
+<tr class="timesnewroman"><td>Times New Roman</td></tr>
+<tr class="couriernew"><td>Courier New</td></tr>
+<tr class="futura"><td>Futura</td></tr>
+<tr class="helvetica"><td>Helvetica</td></tr>
+<tr class="times"><td>Times</td></tr>
+<tr class="courier"><td>Courier</td></tr>
+<tr class="bitstreamverasans"><td>Bitstream Vera Sans</td></tr>
+<tr class="dejavusans"><td>DejaVu Sans</td></tr>
+<tr class="freesans"><td>FreeSans</td></tr>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/order-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<!-- modeled on ../font-face/order-1.html -->
+<html class="reftest-wait">
+<style>
+body { font-family: "One"; }
+</style>
+<script>
+document.fonts.add(new FontFace("One", "url(../fonts/mark2A.ttf)"));
+document.fonts.add(new FontFace("One", "url(../fonts/markA.ttf)"));
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/reftest.list
@@ -0,0 +1,10 @@
+default-preferences pref(layout.css.font-loading-api.enabled,true)
+
+HTTP(..) == dynamic-insert-1.html dynamic-insert-1-ref.html
+HTTP(..) == dynamic-remove-1.html dynamic-remove-1-ref.html
+HTTP(..) == ex-unit-1.html ../font-face/ex-unit-1-ref.html
+HTTP(..) == name-collision.html ../font-face/name-collision-ref.html
+HTTP(..) == order-1.html ../font-face/order-1-ref.html
+HTTP(..) == src-list-1.html ../font-face/src-list-1-ref.html
+HTTP(..) == src-list-2.html ../font-face/src-list-2-ref.html
+HTTP(..) == src-list-data-1.html ../font-face/src-list-data-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/src-list-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<!-- modeled on ../font-face/src-list-1.html -->
+<html class="reftest-wait">
+<style>
+body { font-family: One; }
+</style>
+<script>
+document.fonts.add(new FontFace("One", "url(../fonts/markA.ttf), url(../fonts/mark2A.ttf)"));
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/src-list-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<!-- modeled on ../font-face/src-list-2.html -->
+<html class="reftest-wait">
+<style>
+body { font-family: "One"; }
+</style>
+<script>
+document.fonts.add(new FontFace("One", "url(../fonts/markA.ttf), url(../fonts/markB.ttf)"));
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/src-list-data-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<!-- modeled on ../font-face/src-list-data-1.html -->
+<html class="reftest-wait">
+<style>
+body { margin: 20px; font-size: 100px; font-family: test; }
+p { margin: 0; padding: 0; }
+</style>
+<script>
+document.fonts.add(new FontFace("test", "url(data:font/opentype;base64,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AC4AIABDAG8AcAB5AHIAaQBnAGgAdAAgAGkAbgBmAG8AIABwAGUAbgBkAGkAbgBnAC4AbABvAGEAZAB0AGUAcwB0AFIAZQBnAHUAbABhAHIAdwBlAGIAZgBvAG4AdABsAG8AYQBkAHQAZQBzAHQAIABSAGUAZwB1AGwAYQByAFYAZQByAHMAaQBvAG4AIAAwADAAMQAuADAAMAAxAEIAYQBzAGUAZAAgAG8AbgAgAEwAZQBhAGcAdQBlACAARwBvAHQAaABpAGMAIABiAHkAIABMAGUAYQBnAHUAZQAgAG8AZgAgAE0AbwB2AGUAYQBiAGwAZQAgAFQAeQBwAGUALAAgAG0AbwBkAGkAZgBpAGUAZAAgAGIAeQAgAEoAbwBoAG4AIABEAGEAZwBnAGUAdAB0AGgAdAB0AHAAOgAvAC8AdwB3AHcALgB0AGgAZQBsAGUAYQBnAHUAZQBvAGYAbQBvAHYAZQBhAGIAbABlAHQAeQBwAGUALgBjAG8AbQAvAGwAZQBhAGcAdQBlAC0AZwBvAHQAaABpAGMAQQBsAGwAIABmAG8AbgB0AHMAIABmAHIAbwBtACAAVABoAGUAIABMAGUAYQBnAHUAZQAgAG8AZgAgAE0AbwB2AGUAYQBiAGwAZQAgAFQAeQBwAGUAIABhAHIAZQAgAHMAdQBiAGoAZQBjAHQAIAB0AG8AIAB0AGgAZQAgAE8AcABlAG4AIABGAG8AbgB0ACAATABpAGMAZQBuAHMAZQBoAHQAdABwADoALwAvAHMAYwByAGkAcAB0AHMALgBzAGkAbAAuAG8AcgBnAC8ATwBGAEwAAgAAAAAAAP9nAGYAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AD8AQABBAEIAQwBEAEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgBfAGAAYQECAKMAhACFAJYAjgCLAQMAigDaAI0AwwDeAKIArQDJAMcArgBiAGMAkABkAMsAZQDIAMoAzwDMAM0AzgDpAGYA0wDQANEArwBnAJEA1gDUANUAaADrAO0AiQBqAGkAawBtAGwAbgCgAG8AcQBwAHIAcwB1AHQAdgB3AOoAeAB6AHkAewB9AHwAoQB/AH4AgACBAOwA7gC6ANcA4gDjALAAsQDkAOUAuwDmAOcA2ADhANsA3ADdAOAA2QDfAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQCyALMAtgC3AMQAtAC1AMUAhwCrARIBEwEUAIwA7wEVARYBFwd1bmkwMEEwB3VuaTAwQUQHdW5pMjAwMAd1bmkyMDAxB3VuaTIwMDIHdW5pMjAwMwd1bmkyMDA0B3VuaTIwMDUHdW5pMjAwNgd1bmkyMDA3B3VuaTIwMDgHdW5pMjAwOQd1bmkyMDBBB3VuaTIwMTAHdW5pMjAxMQpmaWd1cmVkYXNoB3VuaTIwMkYHdW5pMjA1RgRFdXJvB3VuaUUwMDAHdW5pRkIwMQd1bmlGQjAyAAAAAQAB//8ADwAAAAEAAAAAyYlvMQAAAADGp3m3AAAAAMrhKHcAAQAAAAwAAAAWAAAAAgABAAEA3wABAAQAAAABAAAAAAABAAAACgAuADwAAkRGTFQADmxhdG4AGAAEAAAAAP//AAAABAAAAAD//wABAAAAAVRTVDEACAAAAAEAAAABAAQAAQAAAAEACAACAA4ABABEADMANgBWAAEABAAkACkALAAvAAA=)"));
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
+<p>FAIL</p>
--- a/layout/reftests/native-theme/combobox-nonnative-when-styled-ref.html
+++ b/layout/reftests/native-theme/combobox-nonnative-when-styled-ref.html
@@ -1,17 +1,21 @@
 <!DOCTYPE HTML>
+<div style="position:relative">
+<!-- mask the dropdown button -->
+<div style="position:absolute; width:50px; left:7px; top:0; bottom:0; background:black;"></div>
 <!-- these should make the select non-native -->
-<select size="1" style="-moz-appearance: none; border-width: 0"></select>
-<select size="1" style="-moz-appearance: none; border-width: 1px"></select>
-<select size="1" style="-moz-appearance: none; border-width: 2px"></select>
-<select size="1" style="-moz-appearance: none; border-width: 3px"></select>
-<select size="1" style="-moz-appearance: none; border-width: 4px"></select>
-<select size="1" style="-moz-appearance: none; border-width: 5px"></select>
-<select size="1" style="-moz-appearance: none; border-width: 6px"></select>
-<select size="1" style="-moz-appearance: none; border-style: dotted"></select>
-<select size="1" style="-moz-appearance: none; border-color: green"></select>
-<select size="1" style="-moz-appearance: none; background-color: transparent"></select>
-<select size="1" style="-moz-appearance: none; background-color: white"></select>
+<select size="1" style="-moz-appearance: none; border-width: 0"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 1px"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 2px"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 3px"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 4px"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 5px"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 6px"></select><br>
+<select size="1" style="-moz-appearance: none; border-style: dotted"></select><br>
+<select size="1" style="-moz-appearance: none; border-color: green"></select><br>
+<select size="1" style="-moz-appearance: none; background-color: transparent"></select><br>
+<select size="1" style="-moz-appearance: none; background-color: white"></select><br>
+</div>
 
 <!-- these should let it stay native -->
 <select size="1"></select>
 <select size="1"></select>
--- a/layout/reftests/native-theme/combobox-nonnative-when-styled.html
+++ b/layout/reftests/native-theme/combobox-nonnative-when-styled.html
@@ -1,17 +1,21 @@
 <!DOCTYPE HTML>
+<div style="position:relative">
+<!-- mask the dropdown button -->
+<div style="position:absolute; width:50px; left:7px; top:0; bottom:0; background:black;"></div>
 <!-- these should make the select non-native -->
-<select size="1" style="border-width: 0"></select>
-<select size="1" style="border-width: 1px"></select>
-<select size="1" style="border-width: 2px"></select>
-<select size="1" style="border-width: 3px"></select>
-<select size="1" style="border-width: 4px"></select>
-<select size="1" style="border-width: 5px"></select>
-<select size="1" style="border-width: 6px"></select>
-<select size="1" style="border-style: dotted"></select>
-<select size="1" style="border-color: green"></select>
-<select size="1" style="background-color: transparent"></select>
-<select size="1" style="background-color: white"></select>
+<select size="1" style="border-width: 0"></select><br>
+<select size="1" style="border-width: 1px"></select><br>
+<select size="1" style="border-width: 2px"></select><br>
+<select size="1" style="border-width: 3px"></select><br>
+<select size="1" style="border-width: 4px"></select><br>
+<select size="1" style="border-width: 5px"></select><br>
+<select size="1" style="border-width: 6px"></select><br>
+<select size="1" style="border-style: dotted"></select><br>
+<select size="1" style="border-color: green"></select><br>
+<select size="1" style="background-color: transparent"></select><br>
+<select size="1" style="background-color: white"></select><br>
+</div>
 
 <!-- these should let it stay native -->
 <select size="1" style="color: black"></select>
 <select size="1" style="font-weight: normal"></select>
--- a/layout/reftests/native-theme/reftest.list
+++ b/layout/reftests/native-theme/reftest.list
@@ -12,17 +12,17 @@
 # The following tests will fail if the platform does not have native
 # theme support (which all platforms should have).
 fails-if(!nativeThemePref) != text-input-native.html text-input-nonnative.html
 == text-input-nonnative-when-styled.html text-input-nonnative-when-styled-ref.html
 fails-if(!nativeThemePref) != textarea-native.html textarea-nonnative.html
 == textarea-nonnative-when-styled.html textarea-nonnative-when-styled-ref.html
 fails-if(!nativeThemePref) != button-native.html button-nonnative.html
 == button-nonnative-when-styled.html button-nonnative-when-styled-ref.html
-fails-if(!nativeThemePref) != combobox-native.html combobox-nonnative.html
+fails-if(!nativeThemePref&&!Android) != combobox-native.html combobox-nonnative.html
 == combobox-nonnative-when-styled.html combobox-nonnative-when-styled-ref.html
 fails-if(!nativeThemePref) needs-focus != listbox-native.html listbox-nonnative.html
 needs-focus == listbox-nonnative-when-styled.html listbox-nonnative-when-styled-ref.html
 fails-if(!nativeThemePref) != radio-native.html radio-nonnative.html
 == radio-still-native-when-styled.html radio-still-native-when-styled-ref.html
 fails-if(!nativeThemePref) != checkbox-native.html checkbox-nonnative.html
 == checkbox-still-native-when-styled.html checkbox-still-native-when-styled-ref.html
 == native-theme-disabled-cascade-levels.html native-theme-disabled-cascade-levels-ref.html
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -176,16 +176,19 @@ include floats/reftest.list
 include font-face/reftest.list
 
 # font features (opentype)
 include font-features/reftest.list
 
 # mobile font size inflation
 skip-if(B2G&&browserIsRemote) include font-inflation/reftest.list # Bug 972697
 
+# CSS Font Loading API
+include font-loading-api/reftest.list
+
 # font matching
 include font-matching/reftest.list
 
 # forms
 include forms/reftest.list
 
 # gfx
 include ../../gfx/tests/reftest/reftest.list
--- a/layout/reftests/text-overflow/combobox-zoom-ref.html
+++ b/layout/reftests/text-overflow/combobox-zoom-ref.html
@@ -14,21 +14,21 @@ html,body {
   color:black; background-color:white; padding:0; margin:0;
 }
 * {
   font-family:DejaVuSansMono!important;
   font-size:16px!important;
 }
 select {
   width: 200px;
-  padding-right: 7px;
+  padding-right: 8px;
 
   -moz-appearance: none;
 }
 </style>
 </head>
 <body>
 <select></select><br>
 
-<select><option>long string long </option></select>
+<select><option>long string long s</option></select>
 
 </body>
 </html>
--- a/layout/reftests/text-overflow/combobox-zoom.html
+++ b/layout/reftests/text-overflow/combobox-zoom.html
@@ -14,17 +14,17 @@ html,body {
   color:black; background-color:white; padding:0; margin:0;
 }
 * {
   font-family:DejaVuSansMono!important;
   font-size:16px!important;
 }
 select {
   width: 200px;
-  padding-right: 7px;
+  padding-right: 8px;
   text-overflow: " ";
   -moz-appearance: none;
 }
 </style>
 </head>
 <body>
 <select></select><br>
 
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -714,20 +714,34 @@ void
 AnimationPlayerCollection::UpdateAnimationGeneration(
   nsPresContext* aPresContext)
 {
   mAnimationGeneration =
     aPresContext->RestyleManager()->GetAnimationGeneration();
 }
 
 bool
-AnimationPlayerCollection::HasCurrentAnimations()
+AnimationPlayerCollection::HasCurrentAnimations() const
 {
   for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
-    if (mPlayers[playerIdx]->IsCurrent()) {
+    if (mPlayers[playerIdx]->HasCurrentSource()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool
+AnimationPlayerCollection::HasCurrentAnimationsForProperty(nsCSSProperty
+                                                             aProperty) const
+{
+  for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
+    const Animation* anim = mPlayers[playerIdx]->GetSource();
+    if (anim && anim->IsCurrent() && anim->HasAnimationOfProperty(aProperty)) {
       return true;
     }
   }
 
   return false;
 }
 
 }
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -299,19 +299,21 @@ struct AnimationPlayerCollection : publi
   // mAnimationGeneration is the sequence number of the last flush where a
   // transition/animation changed.  We keep a similar count on the
   // corresponding layer so we can check that the layer is up to date with
   // the animation manager.
   uint64_t mAnimationGeneration;
   // Update mAnimationGeneration to nsCSSFrameConstructor's count
   void UpdateAnimationGeneration(nsPresContext* aPresContext);
 
-  // Returns true if there is an animation in the before or active phase
-  // at the current time.
-  bool HasCurrentAnimations();
+  // Returns true if there is an animation that has yet to finish.
+  bool HasCurrentAnimations() const;
+  // Returns true if there is an animation of the specified property that
+  // has yet to finish.
+  bool HasCurrentAnimationsForProperty(nsCSSProperty aProperty) const;
 
   // The refresh time associated with mStyleRule.
   TimeStamp mStyleRuleRefreshTime;
 
   // False when we know that our current style rule is valid
   // indefinitely into the future (because all of our animations are
   // either completed or paused).  May be invalidated by a style change.
   bool mNeedsRefreshes;
new file mode 100644
--- /dev/null
+++ b/layout/style/FontFace.cpp
@@ -0,0 +1,876 @@
+/* -*- 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 "mozilla/dom/FontFace.h"
+
+#include "mozilla/dom/FontFaceBinding.h"
+#include "mozilla/dom/FontFaceSet.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/TypedArray.h"
+#include "mozilla/dom/UnionTypes.h"
+#include "mozilla/CycleCollectedJSRuntime.h"
+#include "nsCSSParser.h"
+#include "nsCSSRules.h"
+#include "nsIDocument.h"
+#include "nsStyleUtil.h"
+
+namespace mozilla {
+namespace dom {
+
+// -- FontFaceBufferSource ---------------------------------------------------
+
+/**
+ * An object that wraps a FontFace object and exposes its ArrayBuffer
+ * or ArrayBufferView data in a form the user font set can consume.
+ */
+class FontFaceBufferSource : public gfxFontFaceBufferSource
+{
+public:
+  FontFaceBufferSource(FontFace* aFontFace)
+    : mFontFace(aFontFace) {}
+  virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength);
+
+private:
+  nsRefPtr<FontFace> mFontFace;
+};
+
+void
+FontFaceBufferSource::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength)
+{
+  mFontFace->TakeBuffer(aBuffer, aLength);
+}
+
+// -- FontFaceInitializer ----------------------------------------------------
+
+template<typename T>
+static void
+GetDataFrom(const T& aObject, uint8_t*& aBuffer, uint32_t& aLength)
+{
+  MOZ_ASSERT(!aBuffer);
+  aObject.ComputeLengthAndData();
+  // We use moz_malloc here rather than a FallibleTArray or fallible
+  // operator new[] since the gfxUserFontEntry will be calling moz_free
+  // on it.
+  aBuffer = (uint8_t*) moz_malloc(aObject.Length());
+  if (!aBuffer) {
+    return;
+  }
+  memcpy((void*) aBuffer, aObject.Data(), aObject.Length());
+  aLength = aObject.Length();
+}
+
+/**
+ * A task that is dispatched to the event queue to call Initialize() on a
+ * FontFace object with the source information that was passed to the JS
+ * constructor.
+ */
+class FontFaceInitializer : public nsIRunnable
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  FontFaceInitializer(FontFace* aFontFace)
+    : mFontFace(aFontFace)
+    , mSourceBuffer(nullptr)
+    , mSourceBufferLength(0) {}
+
+  void SetSource(const nsAString& aString);
+  void SetSource(const ArrayBuffer& aArrayBuffer);
+  void SetSource(const ArrayBufferView& aArrayBufferView);
+
+  NS_IMETHOD Run();
+  void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength);
+
+  nsRefPtr<FontFace> mFontFace;
+  FontFace::SourceType mSourceType;
+  nsString mSourceString;
+  uint8_t* mSourceBuffer;  // allocated with NS_Alloc
+  uint32_t mSourceBufferLength;
+
+protected:
+  virtual ~FontFaceInitializer();
+};
+
+NS_IMPL_ISUPPORTS(FontFaceInitializer, nsIRunnable)
+
+FontFaceInitializer::~FontFaceInitializer()
+{
+  if (mSourceBuffer) {
+    NS_Free(mSourceBuffer);
+  }
+}
+
+void
+FontFaceInitializer::SetSource(const nsAString& aString)
+{
+  mSourceType = FontFace::eSourceType_URLs;
+  mSourceString = aString;
+}
+
+void
+FontFaceInitializer::SetSource(const ArrayBuffer& aArrayBuffer)
+{
+  mSourceType = FontFace::eSourceType_Buffer;
+  GetDataFrom(aArrayBuffer, mSourceBuffer, mSourceBufferLength);
+}
+
+void
+FontFaceInitializer::SetSource(const ArrayBufferView& aArrayBufferView)
+{
+  mSourceType = FontFace::eSourceType_Buffer;
+  GetDataFrom(aArrayBufferView, mSourceBuffer, mSourceBufferLength);
+}
+
+NS_IMETHODIMP
+FontFaceInitializer::Run()
+{
+  mFontFace->Initialize(this);
+  return NS_OK;
+}
+
+void
+FontFaceInitializer::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength)
+{
+  aBuffer = mSourceBuffer;
+  aLength = mSourceBufferLength;
+
+  mSourceBuffer = nullptr;
+  mSourceBufferLength = 0;
+}
+
+// -- FontFaceStatusSetter ---------------------------------------------------
+
+/**
+ * A task that is dispatched to the event queue to asynchronously call
+ * SetStatus() on a FontFace object.
+ */
+class FontFaceStatusSetter : public nsIRunnable
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  FontFaceStatusSetter(FontFace* aFontFace,
+                       FontFaceLoadStatus aStatus)
+    : mFontFace(aFontFace)
+    , mStatus(aStatus) {}
+
+  NS_IMETHOD Run();
+
+protected:
+  virtual ~FontFaceStatusSetter() {}
+
+private:
+  nsRefPtr<FontFace> mFontFace;
+  FontFaceLoadStatus mStatus;
+};
+
+NS_IMPL_ISUPPORTS(FontFaceStatusSetter, nsIRunnable)
+
+NS_IMETHODIMP
+FontFaceStatusSetter::Run()
+{
+  mFontFace->SetStatus(mStatus);
+  return NS_OK;
+}
+
+// -- FontFace ---------------------------------------------------------------
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FontFace)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoaded)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRule)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FontFace)
+  if (!tmp->IsInFontFaceSet()) {
+    tmp->mFontFaceSet->RemoveUnavailableFontFace(tmp);
+  }
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoaded)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mRule)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FontFace)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFace)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(FontFace)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(FontFace)
+
+FontFace::FontFace(nsISupports* aParent, nsPresContext* aPresContext)
+  : mParent(aParent)
+  , mPresContext(aPresContext)
+  , mStatus(FontFaceLoadStatus::Unloaded)
+  , mSourceType(SourceType(0))
+  , mSourceBuffer(nullptr)
+  , mSourceBufferLength(0)
+  , mFontFaceSet(aPresContext->Fonts())
+  , mInFontFaceSet(false)
+  , mInitialized(false)
+  , mLoadWhenInitialized(false)
+{
+  MOZ_COUNT_CTOR(FontFace);
+
+  SetIsDOMBinding();
+
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
+
+  if (global) {
+    ErrorResult rv;
+    mLoaded = Promise::Create(global, rv);
+  }
+}
+
+FontFace::~FontFace()
+{
+  MOZ_COUNT_DTOR(FontFace);
+
+  SetUserFontEntry(nullptr);
+
+  if (mFontFaceSet && !IsInFontFaceSet()) {
+    mFontFaceSet->RemoveUnavailableFontFace(this);
+  }
+
+  if (mSourceBuffer) {
+    NS_Free(mSourceBuffer);
+  }
+}
+
+JSObject*
+FontFace::WrapObject(JSContext* aCx)
+{
+  return FontFaceBinding::Wrap(aCx, this);
+}
+
+static FontFaceLoadStatus
+LoadStateToStatus(gfxUserFontEntry::UserFontLoadState aLoadState)
+{
+  switch (aLoadState) {
+    case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED:
+      return FontFaceLoadStatus::Unloaded;
+    case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING:
+      return FontFaceLoadStatus::Loading;
+    case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED:
+      return FontFaceLoadStatus::Loaded;
+    case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED:
+      return FontFaceLoadStatus::Error;
+  }
+  NS_NOTREACHED("invalid aLoadState value");
+  return FontFaceLoadStatus::Error;
+}
+
+already_AddRefed<FontFace>
+FontFace::CreateForRule(nsISupports* aGlobal,
+                        nsPresContext* aPresContext,
+                        nsCSSFontFaceRule* aRule,
+                        gfxUserFontEntry* aUserFontEntry)
+{
+  nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(aGlobal);
+
+  nsRefPtr<FontFace> obj = new FontFace(aGlobal, aPresContext);
+  obj->mInitialized = true;
+  obj->mRule = aRule;
+  obj->mSourceType = eSourceType_FontFaceRule;
+  obj->mInFontFaceSet = true;
+  obj->SetUserFontEntry(aUserFontEntry);
+  return obj.forget();
+}
+
+already_AddRefed<FontFace>
+FontFace::Constructor(const GlobalObject& aGlobal,
+                      const nsAString& aFamily,
+                      const StringOrArrayBufferOrArrayBufferView& aSource,
+                      const FontFaceDescriptors& aDescriptors,
+                      ErrorResult& aRv)
+{
+  nsISupports* global = aGlobal.GetAsSupports();
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
+  nsIDocument* doc = window->GetDoc();
+  if (!doc) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsIPresShell* shell = doc->GetShell();
+  if (!shell) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsPresContext* presContext = shell->GetPresContext();
+  if (!presContext) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<FontFace> obj = new FontFace(global, presContext);
+  obj->mFontFaceSet->AddUnavailableFontFace(obj);
+  if (!obj->SetDescriptors(aFamily, aDescriptors)) {
+    return obj.forget();
+  }
+
+  nsRefPtr<FontFaceInitializer> task = new FontFaceInitializer(obj);
+
+  if (aSource.IsArrayBuffer()) {
+    task->SetSource(aSource.GetAsArrayBuffer());
+  } else if (aSource.IsArrayBufferView()) {
+    task->SetSource(aSource.GetAsArrayBufferView());
+  } else {
+    MOZ_ASSERT(aSource.IsString());
+    task->SetSource(aSource.GetAsString());
+  }
+
+  NS_DispatchToMainThread(task);
+
+  return obj.forget();
+}
+
+void
+FontFace::Initialize(FontFaceInitializer* aInitializer)
+{
+  MOZ_ASSERT(!HasRule());
+  MOZ_ASSERT(mSourceType == SourceType(0));
+
+  if (aInitializer->mSourceType == eSourceType_URLs) {
+    if (!ParseDescriptor(eCSSFontDesc_Src,
+                         aInitializer->mSourceString,
+                         mDescriptors->mSrc)) {
+      if (mLoaded) {
+        // The asynchronous SetStatus call we are about to do assumes that for
+        // FontFace objects with sources other than ArrayBuffer(View)s, that the
+        // mLoaded Promise is rejected with a network error.  We get
+        // in here beforehand to set it to the required syntax error.
+        mLoaded->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
+      }
+
+      // Queue a task to set the status to "error".
+      nsCOMPtr<nsIRunnable> statusSetterTask =
+        new FontFaceStatusSetter(this, FontFaceLoadStatus::Error);
+      NS_DispatchToMainThread(statusSetterTask);
+      return;
+    }
+
+    mSourceType = eSourceType_URLs;
+
+    // Now that we have parsed the src descriptor, we are initialized.
+    OnInitialized();
+    return;
+  }
+
+  // We've been given an ArrayBuffer or ArrayBufferView as the source.
+  MOZ_ASSERT(aInitializer->mSourceType == eSourceType_Buffer);
+
+  mSourceType = aInitializer->mSourceType;
+  aInitializer->TakeBuffer(mSourceBuffer, mSourceBufferLength);
+
+  // Queue a task to set the status to "loading".
+  nsCOMPtr<nsIRunnable> statusSetterTask =
+    new FontFaceStatusSetter(this, FontFaceLoadStatus::Loading);
+  NS_DispatchToMainThread(statusSetterTask);
+
+  // We are initialized.
+  OnInitialized();
+
+  // ArrayBuffer(View)-backed FontFace objects are loaded on construction,
+  // but we need to do this after going through the event loop so that the
+  // FontFaceStatusSetter runs before us.
+  nsCOMPtr<nsIRunnable> loaderTask =
+    NS_NewRunnableMethod(this, &FontFace::DoLoad);
+  NS_DispatchToMainThread(loaderTask);
+}
+
+void
+FontFace::GetFamily(nsString& aResult)
+{
+  mPresContext->FlushUserFontSet();
+
+  // Serialize the same way as in nsCSSFontFaceStyleDecl::GetPropertyValue.
+  nsCSSValue value;
+  GetDesc(eCSSFontDesc_Family, value);
+
+  aResult.Truncate();
+  nsDependentString family(value.GetStringBufferValue());
+  if (!family.IsEmpty()) {
+    // The string length can be zero when the author passed an invalid
+    // family name or an invalid descriptor to the JS FontFace constructor.
+    nsStyleUtil::AppendEscapedCSSString(family, aResult);
+  }
+}
+
+void
+FontFace::SetFamily(const nsAString& aValue, ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+  SetDescriptor(eCSSFontDesc_Family, aValue, aRv);
+}
+
+void
+FontFace::GetStyle(nsString& aResult)
+{
+  mPresContext->FlushUserFontSet();
+  GetDesc(eCSSFontDesc_Style, eCSSProperty_font_style, aResult);
+}
+
+void
+FontFace::SetStyle(const nsAString& aValue, ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+  SetDescriptor(eCSSFontDesc_Style, aValue, aRv);
+}
+
+void
+FontFace::GetWeight(nsString& aResult)
+{
+  mPresContext->FlushUserFontSet();
+  GetDesc(eCSSFontDesc_Weight, eCSSProperty_font_weight, aResult);
+}
+
+void
+FontFace::SetWeight(const nsAString& aValue, ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+  SetDescriptor(eCSSFontDesc_Weight, aValue, aRv);
+}
+
+void
+FontFace::GetStretch(nsString& aResult)
+{
+  mPresContext->FlushUserFontSet();
+  GetDesc(eCSSFontDesc_Stretch, eCSSProperty_font_stretch, aResult);
+}
+
+void
+FontFace::SetStretch(const nsAString& aValue, ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+  SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv);
+}
+
+void
+FontFace::GetUnicodeRange(nsString& aResult)
+{
+  mPresContext->FlushUserFontSet();
+
+  nsCSSValue value;
+  GetDesc(eCSSFontDesc_UnicodeRange, value);
+
+  aResult.Truncate();
+  nsStyleUtil::AppendUnicodeRange(value, aResult);
+}
+
+void
+FontFace::SetUnicodeRange(const nsAString& aValue, ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+  SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv);
+}
+
+void
+FontFace::GetVariant(nsString& aResult)
+{
+  mPresContext->FlushUserFontSet();
+
+  // XXX Just expose the font-variant descriptor as "normal" until we
+  // support it properly (bug 1055385).
+  aResult.AssignLiteral("normal");
+}
+
+void
+FontFace::SetVariant(const nsAString& aValue, ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+
+  // XXX Ignore assignments to variant until we support font-variant
+  // descriptors (bug 1055385).
+}
+
+void
+FontFace::GetFeatureSettings(nsString& aResult)
+{
+  mPresContext->FlushUserFontSet();
+
+  nsCSSValue value;
+  GetDesc(eCSSFontDesc_FontFeatureSettings, value);
+
+  aResult.Truncate();
+  nsStyleUtil::AppendFontFeatureSettings(value, aResult);
+}
+
+void
+FontFace::SetFeatureSettings(const nsAString& aValue, ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+  SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv);
+}
+
+FontFaceLoadStatus
+FontFace::Status()
+{
+  return mStatus;
+}
+
+Promise*
+FontFace::Load(ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+
+  if (!mLoaded) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  // Calling Load on a FontFace constructed with an ArrayBuffer data source,
+  // or on one that is already loading (or has finished loading), has no
+  // effect.
+  if (mSourceType == eSourceType_Buffer ||
+      mStatus != FontFaceLoadStatus::Unloaded) {
+    return mLoaded;
+  }
+
+  // Calling the user font entry's Load method will end up setting our
+  // status to Loading, but the spec requires us to set it to Loading
+  // here.
+  SetStatus(FontFaceLoadStatus::Loading);
+
+  if (mInitialized) {
+    DoLoad();
+  } else {
+    // We can only load an initialized font; this will cause the font to be
+    // loaded once it has been initialized.
+    mLoadWhenInitialized = true;
+  }
+
+  return mLoaded;
+}
+
+void
+FontFace::DoLoad()
+{
+  MOZ_ASSERT(mInitialized);
+
+  if (!mUserFontEntry) {
+    MOZ_ASSERT(!HasRule(),
+               "Rule backed FontFace objects should already have a user font "
+               "entry by the time Load() can be called on them");
+
+    nsRefPtr<gfxUserFontEntry> newEntry =
+      mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
+    if (!newEntry) {
+      return;
+    }
+
+    SetUserFontEntry(newEntry);
+  }
+
+  mUserFontEntry->Load();
+}
+
+Promise*
+FontFace::GetLoaded(ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+
+  if (!mLoaded) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  return mLoaded;
+}
+
+void
+FontFace::SetStatus(FontFaceLoadStatus aStatus)
+{
+  if (mStatus == aStatus) {
+    return;
+  }
+
+  if (aStatus < mStatus) {
+    // We're being asked to go backwards in status!  Normally, this shouldn't
+    // happen.  But it can if the FontFace had a user font entry that had
+    // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
+    // if we used a local() rule.  For now, just ignore the request to
+    // go backwards in status.
+    return;
+  }
+
+  mStatus = aStatus;
+
+  if (mInFontFaceSet) {
+    mFontFaceSet->OnFontFaceStatusChanged(this);
+  }
+
+  if (!mLoaded) {
+    return;
+  }
+
+  if (mStatus == FontFaceLoadStatus::Loaded) {
+    mLoaded->MaybeResolve(this);
+  } else if (mStatus == FontFaceLoadStatus::Error) {
+    if (mSourceType == eSourceType_Buffer) {
+      mLoaded->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
+    } else {
+      mLoaded->MaybeReject(NS_ERROR_DOM_NETWORK_ERR);
+    }
+  }
+}
+
+bool
+FontFace::ParseDescriptor(nsCSSFontDesc aDescID,
+                          const nsAString& aString,
+                          nsCSSValue& aResult)
+{
+  nsCSSParser parser;
+
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
+  nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mParent);
+  nsCOMPtr<nsIURI> base = window->GetDocBaseURI();
+
+  if (!parser.ParseFontFaceDescriptor(aDescID, aString,
+                                      nullptr, // aSheetURL
+                                      base,
+                                      principal,
+                                      aResult)) {
+    aResult.Reset();
+    return false;
+  }
+
+  return true;
+}
+
+void
+FontFace::SetDescriptor(nsCSSFontDesc aFontDesc,
+                        const nsAString& aValue,
+                        ErrorResult& aRv)
+{
+  NS_ASSERTION(!HasRule(),
+               "we don't handle rule backed FontFace objects yet");
+  if (HasRule()) {
+    return;
+  }
+
+  nsCSSValue parsedValue;
+  if (!ParseDescriptor(aFontDesc, aValue, parsedValue)) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+
+  mDescriptors->Get(aFontDesc) = parsedValue;
+
+  // XXX Setting descriptors doesn't actually have any effect on FontFace
+  // objects that have started loading or have already been loaded.
+}
+
+bool
+FontFace::SetDescriptors(const nsAString& aFamily,
+                         const FontFaceDescriptors& aDescriptors)
+{
+  MOZ_ASSERT(!HasRule());
+  MOZ_ASSERT(!mDescriptors);
+
+  mDescriptors = new CSSFontFaceDescriptors;
+
+  // Parse all of the mDescriptors in aInitializer, which are the values
+  // we got from the JS constructor.
+  if (!ParseDescriptor(eCSSFontDesc_Family,
+                       aFamily,
+                       mDescriptors->mFamily) ||
+      *mDescriptors->mFamily.GetStringBufferValue() == 0 ||
+      !ParseDescriptor(eCSSFontDesc_Style,
+                       aDescriptors.mStyle,
+                       mDescriptors->mStyle) ||
+      !ParseDescriptor(eCSSFontDesc_Weight,
+                       aDescriptors.mWeight,
+                       mDescriptors->mWeight) ||
+      !ParseDescriptor(eCSSFontDesc_Stretch,
+                       aDescriptors.mStretch,
+                       mDescriptors->mStretch) ||
+      !ParseDescriptor(eCSSFontDesc_UnicodeRange,
+                       aDescriptors.mUnicodeRange,
+                       mDescriptors->mUnicodeRange) ||
+      !ParseDescriptor(eCSSFontDesc_FontFeatureSettings,
+                       aDescriptors.mFeatureSettings,
+                       mDescriptors->mFontFeatureSettings)) {
+    // XXX Handle font-variant once we support it (bug 1055385).
+
+    // If any of the descriptors failed to parse, none of them should be set
+    // on the FontFace.
+    mDescriptors = new CSSFontFaceDescriptors;
+
+    if (mLoaded) {
+      mLoaded->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
+    }
+
+    SetStatus(FontFaceLoadStatus::Error);
+    return false;
+  }
+
+  return true;
+}
+
+void
+FontFace::OnInitialized()
+{
+  MOZ_ASSERT(!mInitialized);
+
+  mInitialized = true;
+
+  // For a FontFace that was created and immediately had Load() called on
+  // it, before it had a chance to be initialized, we kick off its load now.
+  if (mLoadWhenInitialized) {
+    mLoadWhenInitialized = false;
+    DoLoad();
+  }
+
+  if (mInFontFaceSet) {
+    mFontFaceSet->OnFontFaceInitialized(this);
+  }
+}
+
+void
+FontFace::GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const
+{
+  if (HasRule()) {
+    MOZ_ASSERT(mRule);
+    MOZ_ASSERT(!mDescriptors);
+    mRule->GetDesc(aDescID, aResult);
+  } else {
+    aResult = mDescriptors->Get(aDescID);
+  }
+}
+
+void
+FontFace::GetDesc(nsCSSFontDesc aDescID,
+                  nsCSSProperty aPropID,
+                  nsString& aResult) const
+{
+  nsCSSValue value;
+  GetDesc(aDescID, value);
+
+  aResult.Truncate();
+
+  // Fill in a default value for missing descriptors.
+  if (value.GetUnit() == eCSSUnit_Null) {
+    if (aDescID == eCSSFontDesc_UnicodeRange) {
+      aResult.AssignLiteral("U+0-10FFFF");
+    } else if (aDescID != eCSSFontDesc_Family &&
+               aDescID != eCSSFontDesc_Src) {
+      aResult.AssignLiteral("normal");
+    }
+  } else {
+    value.AppendToString(aPropID, aResult, nsCSSValue::eNormalized);
+  }
+}
+
+void
+FontFace::SetUserFontEntry(gfxUserFontEntry* aEntry)
+{
+  if (mUserFontEntry) {
+    mUserFontEntry->mFontFaces.RemoveElement(this);
+  }
+
+  mUserFontEntry = static_cast<Entry*>(aEntry);
+  if (mUserFontEntry) {
+    mUserFontEntry->mFontFaces.AppendElement(this);
+
+    // Our newly assigned user font entry might be in the process of or
+    // finished loading, so set our status accordingly.  But only do so
+    // if we're not going "backwards" in status, which could otherwise
+    // happen in this case:
+    //
+    //   new FontFace("ABC", "url(x)").load();
+    //
+    // where the SetUserFontEntry call (from the after-initialization
+    // DoLoad call) comes after the author's call to load(), which set mStatus
+    // to Loading.
+    FontFaceLoadStatus newStatus =
+      LoadStateToStatus(mUserFontEntry->LoadState());
+    if (newStatus > mStatus) {
+      SetStatus(newStatus);
+    }
+  }
+}
+
+bool
+FontFace::GetFamilyName(nsString& aResult)
+{
+  nsCSSValue value;
+  GetDesc(eCSSFontDesc_Family, value);
+
+  if (value.GetUnit() == eCSSUnit_String) {
+    nsString familyname;
+    value.GetStringValue(familyname);
+    aResult.Append(familyname);
+  }
+
+  return !aResult.IsEmpty();
+}
+
+void
+FontFace::DisconnectFromRule()
+{
+  MOZ_ASSERT(HasRule());
+
+  // Make a copy of the descriptors.
+  mDescriptors = new CSSFontFaceDescriptors;
+  mRule->GetDescriptors(*mDescriptors);
+
+  mRule->SetFontFace(nullptr);
+  mRule = nullptr;
+  mInFontFaceSet = false;
+}
+
+bool
+FontFace::HasFontData() const
+{
+  return mSourceType == eSourceType_Buffer && mSourceBuffer;
+}
+
+void
+FontFace::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength)
+{
+  MOZ_ASSERT(HasFontData());
+
+  aBuffer = mSourceBuffer;
+  aLength = mSourceBufferLength;
+
+  mSourceBuffer = nullptr;
+  mSourceBufferLength = 0;
+}
+
+already_AddRefed<gfxFontFaceBufferSource>
+FontFace::CreateBufferSource()
+{
+  nsRefPtr<FontFaceBufferSource> bufferSource = new FontFaceBufferSource(this);
+  return bufferSource.forget();
+}
+
+// -- FontFace::Entry --------------------------------------------------------
+
+/* virtual */ void
+FontFace::Entry::SetLoadState(UserFontLoadState aLoadState)
+{
+  gfxUserFontEntry::SetLoadState(aLoadState);
+
+  for (size_t i = 0; i < mFontFaces.Length(); i++) {
+    mFontFaces[i]->SetStatus(LoadStateToStatus(aLoadState));
+  }
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/FontFace.h
@@ -0,0 +1,293 @@
+/* -*- 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 mozilla_dom_FontFace_h
+#define mozilla_dom_FontFace_h
+
+#include "mozilla/dom/FontFaceBinding.h"
+#include "gfxUserFontSet.h"
+#include "nsCSSProperty.h"
+#include "nsCSSValue.h"
+#include "nsWrapperCache.h"
+
+class gfxFontFaceBufferSource;
+class nsCSSFontFaceRule;
+class nsPresContext;
+
+namespace mozilla {
+struct CSSFontFaceDescriptors;
+namespace dom {
+class FontFaceBufferSource;
+struct FontFaceDescriptors;
+class FontFaceSet;
+class FontFaceInitializer;
+class FontFaceStatusSetter;
+class Promise;
+class StringOrArrayBufferOrArrayBufferView;
+}
+}
+
+namespace mozilla {
+namespace dom {
+
+class FontFace MOZ_FINAL : public nsISupports,
+                           public nsWrapperCache
+{
+  friend class mozilla::dom::FontFaceBufferSource;
+  friend class mozilla::dom::FontFaceInitializer;
+  friend class mozilla::dom::FontFaceStatusSetter;
+  friend class Entry;
+
+public:
+  class Entry MOZ_FINAL : public gfxUserFontEntry {
+    friend class FontFace;
+
+  public:
+    Entry(gfxUserFontSet* aFontSet,
+          const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+          uint32_t aWeight,
+          int32_t aStretch,
+          uint32_t aItalicStyle,
+          const nsTArray<gfxFontFeature>& aFeatureSettings,
+          uint32_t aLanguageOverride,
+          gfxSparseBitSet* aUnicodeRanges)
+      : gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch,
+                         aItalicStyle, aFeatureSettings, aLanguageOverride,
+                         aUnicodeRanges) {}
+
+    virtual void SetLoadState(UserFontLoadState aLoadState) MOZ_OVERRIDE;
+
+  protected:
+    // The FontFace objects that use this user font entry.  We need to store
+    // an array of these, not just a single pointer, since the user font
+    // cache can return the same entry for different FontFaces that have
+    // the same descriptor values and come from the same origin.
+    nsAutoTArray<FontFace*,1> mFontFaces;
+  };
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FontFace)
+
+  nsISupports* GetParentObject() const { return mParent; }
+  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  static already_AddRefed<FontFace> CreateForRule(
+                                              nsISupports* aGlobal,
+                                              nsPresContext* aPresContext,
+                                              nsCSSFontFaceRule* aRule,
+                                              gfxUserFontEntry* aUserFontEntry);
+
+  nsCSSFontFaceRule* GetRule() { return mRule; }
+
+  void GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const;
+
+  gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
+  void SetUserFontEntry(gfxUserFontEntry* aEntry);
+
+  /**
+   * Returns whether this object is in a FontFaceSet.
+   */
+  bool IsInFontFaceSet() { return mInFontFaceSet; }
+
+  /**
+   * Sets whether this object is in a FontFaceSet.  This is called by the
+   * FontFaceSet when Add, Remove, etc. are called.
+   */
+  void SetIsInFontFaceSet(bool aInFontFaceSet) {
+    MOZ_ASSERT(!(!aInFontFaceSet && HasRule()),
+               "use DisconnectFromRule instead");
+    mInFontFaceSet = aInFontFaceSet;
+  }
+
+  /**
+   * Returns whether this FontFace is initialized.  A rule backed
+   * FontFace is considered initialized at construction time.  For
+   * FontFace objects created using the FontFace JS constructor, it
+   * is once all the descriptors have been parsed.
+   */
+  bool IsInitialized() const { return mInitialized; }
+
+  FontFaceSet* GetFontFaceSet() const { return mFontFaceSet; }
+
+  /**
+   * Gets the family name of the FontFace as a raw string (such as 'Times', as
+   * opposed to GetFamily, which returns a CSS-escaped string, such as
+   * '"Times"').  Returns whether a valid family name was available.
+   */
+  bool GetFamilyName(nsString& aResult);
+
+  /**
+   * Returns whether this object is CSS-connected, i.e. reflecting an
+   * @font-face rule.
+   */
+  bool HasRule() const { return mRule; }
+
+  /**
+   * Breaks the connection between this FontFace and its @font-face rule.
+   */
+  void DisconnectFromRule();
+
+  /**
+   * Returns whether there is an ArrayBuffer or ArrayBufferView of font
+   * data.
+   */
+  bool HasFontData() const;
+
+  /**
+   * Creates a gfxFontFaceBufferSource to represent the font data
+   * in this object.
+   */
+  already_AddRefed<gfxFontFaceBufferSource> CreateBufferSource();
+
+  /**
+   * Gets a pointer to and the length of the font data stored in the
+   * ArrayBuffer or ArrayBufferView.
+   */
+  bool GetData(uint8_t*& aBuffer, uint32_t& aLength);
+
+  // Web IDL
+  static already_AddRefed<FontFace>
+  Constructor(const GlobalObject& aGlobal,
+              const nsAString& aFamily,
+              const mozilla::dom::StringOrArrayBufferOrArrayBufferView& aSource,
+              const mozilla::dom::FontFaceDescriptors& aDescriptors,
+              ErrorResult& aRV);
+
+  void GetFamily(nsString& aResult);
+  void SetFamily(const nsAString& aValue, mozilla::ErrorResult& aRv);
+  void GetStyle(nsString& aResult);
+  void SetStyle(const nsAString& aValue, mozilla::ErrorResult& aRv);
+  void GetWeight(nsString& aResult);
+  void SetWeight(const nsAString& aValue, mozilla::ErrorResult& aRv);
+  void GetStretch(nsString& aResult);
+  void SetStretch(const nsAString& aValue, mozilla::ErrorResult& aRv);
+  void GetUnicodeRange(nsString& aResult);
+  void SetUnicodeRange(const nsAString& aValue, mozilla::ErrorResult& aRv);
+  void GetVariant(nsString& aResult);
+  void SetVariant(const nsAString& aValue, mozilla::ErrorResult& aRv);
+  void GetFeatureSettings(nsString& aResult);
+  void SetFeatureSettings(const nsAString& aValue, mozilla::ErrorResult& aRv);
+
+  mozilla::dom::FontFaceLoadStatus Status();
+  mozilla::dom::Promise* Load(mozilla::ErrorResult& aRv);
+  mozilla::dom::Promise* GetLoaded(mozilla::ErrorResult& aRv);
+
+private:
+  FontFace(nsISupports* aParent, nsPresContext* aPresContext);
+  ~FontFace();
+
+  /**
+   * Initializes the source and descriptors on this object based on values that
+   * were passed in to the JS constructor.  If the source was specified as
+   * an ArrayBuffer or ArrayBufferView, parsing of the font data in there
+   * will be started.
+   */
+  void Initialize(FontFaceInitializer* aInitializer);
+
+  // Helper function for Load.
+  void DoLoad();
+
+  /**
+   * Parses a @font-face descriptor value, storing the result in aResult.
+   * Returns whether the parsing was successful.
+   */
+  bool ParseDescriptor(nsCSSFontDesc aDescID, const nsAString& aString,
+                       nsCSSValue& aResult);
+
+  // Helper function for the descriptor setter methods.
+  void SetDescriptor(nsCSSFontDesc aFontDesc,
+                     const nsAString& aValue,
+                     mozilla::ErrorResult& aRv);
+
+  /**
+   * Sets all of the descriptor values in mDescriptors using values passed
+   * to the JS constructor.
+   */
+  bool SetDescriptors(const nsAString& aFamily,
+                      const FontFaceDescriptors& aDescriptors);
+
+  /**
+   * Marks the FontFace as initialized and informs the FontFaceSet it is in,
+   * if any.
+   */
+  void OnInitialized();
+
+  /**
+   * Sets the current loading status.
+   */
+  void SetStatus(mozilla::dom::FontFaceLoadStatus aStatus);
+
+  void GetDesc(nsCSSFontDesc aDescID,
+               nsCSSProperty aPropID,
+               nsString& aResult) const;
+
+  /**
+   * Returns and takes ownership of the buffer storing the font data.
+   */
+  void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength);
+
+  nsCOMPtr<nsISupports> mParent;
+  nsPresContext* mPresContext;
+
+  // A Promise that is fulfilled once the font represented by this FontFace
+  // is loaded, and is rejected if the load fails.
+  nsRefPtr<mozilla::dom::Promise> mLoaded;
+
+  // The @font-face rule this FontFace object is reflecting, if it is a
+  // rule backed FontFace.
+  nsRefPtr<nsCSSFontFaceRule> mRule;
+
+  // The FontFace object's user font entry.  This is initially null, but is set
+  // during FontFaceSet::UpdateRules and when a FontFace is explicitly loaded.
+  nsRefPtr<Entry> mUserFontEntry;
+
+  // The current load status of the font represented by this FontFace.
+  // Note that we can't just reflect the value of the gfxUserFontEntry's
+  // status, since the spec sometimes requires us to go through the event
+  // loop before updating the status, rather than doing it immediately.
+  mozilla::dom::FontFaceLoadStatus mStatus;
+
+  // Represents where a FontFace's data is coming from.
+  enum SourceType {
+    eSourceType_FontFaceRule = 1,
+    eSourceType_URLs,
+    eSourceType_Buffer
+  };
+
+  // Where the font data for this FontFace is coming from.
+  SourceType mSourceType;
+
+  // If the FontFace was constructed with an ArrayBuffer(View), this is a
+  // copy of the data from it.
+  uint8_t* mSourceBuffer;
+  uint32_t mSourceBufferLength;
+
+  // The values corresponding to the font face descriptors, if we are not
+  // a rule backed FontFace object.  For rule backed objects, we use
+  // the descriptors stored in mRule.
+  nsAutoPtr<mozilla::CSSFontFaceDescriptors> mDescriptors;
+
+  // The FontFaceSet this FontFace is associated with, regardless of whether
+  // it is currently "in" the set.
+  nsRefPtr<FontFaceSet> mFontFaceSet;
+
+  // Whether this FontFace appears in the FontFaceSet.
+  bool mInFontFaceSet;
+
+  // Whether the FontFace has been fully initialized.  This takes at least one
+  // run around the event loop, as the parsing of the src descriptor is done
+  // off an event queue task.
+  bool mInitialized;
+
+  // Records whether Load() was called on this FontFace before it was
+  // initialized.  When the FontFace eventually does become initialized,
+  // mLoadPending is checked and Load() is called if needed.
+  bool mLoadWhenInitialized;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // !defined(mozilla_dom_FontFace_h)
new file mode 100644
--- /dev/null
+++ b/layout/style/FontFaceSet.cpp
@@ -0,0 +1,1594 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 "FontFaceSet.h"
+
+#ifdef MOZ_LOGGING
+#define FORCE_PR_LOG /* Allow logging in the release build */
+#endif /* MOZ_LOGGING */
+#include "prlog.h"
+
+#include "mozilla/css/Loader.h"
+#include "mozilla/dom/CSSFontFaceLoadEvent.h"
+#include "mozilla/dom/CSSFontFaceLoadEventBinding.h"
+#include "mozilla/dom/FontFaceSetBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/AsyncEventDispatcher.h"
+#include "nsCrossSiteListenerProxy.h"
+#include "nsFontFaceLoader.h"
+#include "nsIChannelPolicy.h"
+#include "nsIConsoleService.h"
+#include "nsIContentPolicy.h"
+#include "nsIContentSecurityPolicy.h"
+#include "nsIDocShell.h"
+#include "nsIDocument.h"
+#include "nsINetworkPredictor.h"
+#include "nsIPresShell.h"
+#include "nsIPrincipal.h"
+#include "nsISupportsPriority.h"
+#include "nsIWebNavigation.h"
+#include "nsNetUtil.h"
+#include "nsPresContext.h"
+#include "nsPrintfCString.h"
+#include "nsStyleSet.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+#ifdef PR_LOGGING
+static PRLogModuleInfo*
+GetFontFaceSetLog()
+{
+  static PRLogModuleInfo* sLog;
+  if (!sLog)
+    sLog = PR_NewLogModule("fontfaceset");
+  return sLog;
+}
+#endif /* PR_LOGGING */
+
+#define LOG(args) PR_LOG(GetFontFaceSetLog(), PR_LOG_DEBUG, args)
+#define LOG_ENABLED() PR_LOG_TEST(GetFontFaceSetLog(), PR_LOG_DEBUG)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(FontFaceSet)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FontFaceSet, DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReady);
+  for (size_t i = 0; i < tmp->mRuleFaces.Length(); i++) {
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleFaces[i].mFontFace);
+  }
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNonRuleFaces);
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FontFaceSet, DOMEventTargetHelper)
+  tmp->Disconnect();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mReady);
+  for (size_t i = 0; i < tmp->mRuleFaces.Length(); i++) {
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(mRuleFaces[i].mFontFace);
+  }
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNonRuleFaces);
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_ADDREF_INHERITED(FontFaceSet, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(FontFaceSet, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FontFaceSet)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
+  NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+FontFaceSet::FontFaceSet(nsPIDOMWindow* aWindow, nsPresContext* aPresContext)
+  : DOMEventTargetHelper(aWindow)
+  , mPresContext(aPresContext)
+  , mDocument(aPresContext->Document())
+  , mStatus(FontFaceSetLoadStatus::Loaded)
+  , mNonRuleFacesDirty(false)
+  , mReadyIsResolved(true)
+  , mDispatchedLoadingEvent(false)
+  , mHasLoadingFontFaces(false)
+  , mHasLoadingFontFacesIsDirty(false)
+{
+  MOZ_COUNT_CTOR(FontFaceSet);
+
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aWindow);
+
+  if (global) {
+    ErrorResult rv;
+    mReady = Promise::Create(global, rv);
+  }
+
+  if (mReady) {
+    mReady->MaybeResolve(this);
+  }
+
+  if (!mDocument->DidFireDOMContentLoaded()) {
+    mDocument->AddSystemEventListener(NS_LITERAL_STRING("DOMContentLoaded"),
+                                      this, false, false);
+  }
+
+  mDocument->CSSLoader()->AddObserver(this);
+}
+
+FontFaceSet::~FontFaceSet()
+{
+  MOZ_COUNT_DTOR(FontFaceSet);
+
+  NS_ASSERTION(mLoaders.Count() == 0, "mLoaders should have been emptied");
+
+  Disconnect();
+}
+
+JSObject*
+FontFaceSet::WrapObject(JSContext* aContext)
+{
+  return FontFaceSetBinding::Wrap(aContext, this);
+}
+
+void
+FontFaceSet::Disconnect()
+{
+  if (mDocument) {
+    mDocument->RemoveSystemEventListener(NS_LITERAL_STRING("DOMContentLoaded"),
+                                         this, false);
+    // We're null checking CSSLoader() since FontFaceSet::Disconnect() might be
+    // being called during unlink, at which time the loader amy already have
+    // been unlinked from the document.
+    if (mDocument->CSSLoader()) {
+      mDocument->CSSLoader()->RemoveObserver(this);
+    }
+  }
+}
+
+FontFaceSet::UserFontSet*
+FontFaceSet::EnsureUserFontSet(nsPresContext* aPresContext)
+{
+  if (!mUserFontSet) {
+    mUserFontSet = new UserFontSet(this);
+    mPresContext = aPresContext;
+  }
+  return mUserFontSet;
+}
+
+already_AddRefed<Promise>
+FontFaceSet::Load(const nsAString& aFont,
+                  const nsAString& aText,
+                  ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  return nullptr;
+}
+
+bool
+FontFaceSet::Check(const nsAString& aFont,
+                   const nsAString& aText,
+                   ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  return false;
+}
+
+Promise*
+FontFaceSet::GetReady(ErrorResult& aRv)
+{
+  if (!mReady) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  mPresContext->FlushUserFontSet();
+  return mReady;
+}
+
+FontFaceSetLoadStatus
+FontFaceSet::Status()
+{
+  mPresContext->FlushUserFontSet();
+  return mStatus;
+}
+
+#ifdef DEBUG
+bool
+FontFaceSet::HasRuleFontFace(FontFace* aFontFace)
+{
+  for (size_t i = 0; i < mRuleFaces.Length(); i++) {
+    if (mRuleFaces[i].mFontFace == aFontFace) {
+      return true;
+    }
+  }
+  return false;
+}
+#endif
+
+FontFaceSet*
+FontFaceSet::Add(FontFace& aFontFace, ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+
+  // We currently only support FontFace objects being in a single FontFaceSet,
+  // and we also restrict the FontFaceSet to contain only FontFaces created
+  // in the same window.
+
+  if (aFontFace.GetFontFaceSet() != this) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return nullptr;
+  }
+
+  if (aFontFace.HasRule()) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_MODIFICATION_ERR);
+    return nullptr;
+  }
+
+  if (aFontFace.IsInFontFaceSet()) {
+    return this;
+  }
+
+  bool removed = mUnavailableFaces.RemoveElement(&aFontFace);
+  if (!removed) {
+    MOZ_ASSERT(false, "should have found aFontFace in mUnavailableFaces");
+    return this;
+  }
+
+  aFontFace.SetIsInFontFaceSet(true);
+
+  MOZ_ASSERT(!mNonRuleFaces.Contains(&aFontFace),
+             "FontFace should not occur in mNonRuleFaces twice");
+
+  mNonRuleFaces.AppendElement(&aFontFace);
+
+  mNonRuleFacesDirty = true;
+  mPresContext->RebuildUserFontSet();
+  mHasLoadingFontFacesIsDirty = true;
+  CheckLoadingStarted();
+  return this;
+}
+
+void
+FontFaceSet::Clear()
+{
+  mPresContext->FlushUserFontSet();
+
+  if (mNonRuleFaces.IsEmpty()) {
+    return;
+  }
+
+  for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
+    FontFace* f = mNonRuleFaces[i];
+    f->SetIsInFontFaceSet(false);
+
+    MOZ_ASSERT(!mUnavailableFaces.Contains(f),
+               "FontFace should not occur in mUnavailableFaces twice");
+
+    mUnavailableFaces.AppendElement(f);
+  }
+
+  mNonRuleFaces.Clear();
+  mNonRuleFacesDirty = true;
+  mPresContext->RebuildUserFontSet();
+  mHasLoadingFontFacesIsDirty = true;
+  CheckLoadingFinished();
+}
+
+bool
+FontFaceSet::Delete(FontFace& aFontFace, ErrorResult& aRv)
+{
+  mPresContext->FlushUserFontSet();
+
+  if (aFontFace.HasRule()) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_MODIFICATION_ERR);
+    return nullptr;
+  }
+
+  if (!mNonRuleFaces.RemoveElement(&aFontFace)) {
+    return false;
+  }
+
+  aFontFace.SetIsInFontFaceSet(false);
+
+  MOZ_ASSERT(!mUnavailableFaces.Contains(&aFontFace),
+             "FontFace should not occur in mUnavailableFaces twice");
+
+  mUnavailableFaces.AppendElement(&aFontFace);
+
+  mNonRuleFacesDirty = true;
+  mPresContext->RebuildUserFontSet();
+  mHasLoadingFontFacesIsDirty = true;
+  CheckLoadingFinished();
+  return true;
+}
+
+bool
+FontFaceSet::HasAvailableFontFace(FontFace* aFontFace)
+{
+  return aFontFace->GetFontFaceSet() == this &&
+         aFontFace->IsInFontFaceSet();
+}
+
+bool
+FontFaceSet::Has(FontFace& aFontFace)
+{
+  mPresContext->FlushUserFontSet();
+
+  return HasAvailableFontFace(&aFontFace);
+}
+
+FontFace*
+FontFaceSet::IndexedGetter(uint32_t aIndex, bool& aFound)
+{
+  mPresContext->FlushUserFontSet();
+
+  if (aIndex < mRuleFaces.Length()) {
+    aFound = true;
+    return mRuleFaces[aIndex].mFontFace;
+  }
+
+  aIndex -= mRuleFaces.Length();
+  if (aIndex < mNonRuleFaces.Length()) {
+    aFound = true;
+    return mNonRuleFaces[aIndex];
+  }
+
+  aFound = false;
+  return nullptr;
+}
+
+uint32_t
+FontFaceSet::Length()
+{
+  mPresContext->FlushUserFontSet();
+
+  // Web IDL objects can only expose array index properties up to INT32_MAX.
+
+  size_t total = mRuleFaces.Length() + mNonRuleFaces.Length();
+  return std::min<size_t>(total, INT32_MAX);
+}
+
+static PLDHashOperator DestroyIterator(nsPtrHashKey<nsFontFaceLoader>* aKey,
+                                       void* aUserArg)
+{
+  aKey->GetKey()->Cancel();
+  return PL_DHASH_REMOVE;
+}
+
+void
+FontFaceSet::DestroyUserFontSet()
+{
+  Disconnect();
+  mDocument = nullptr;
+  mPresContext = nullptr;
+  mLoaders.EnumerateEntries(DestroyIterator, nullptr);
+  for (size_t i = 0; i < mRuleFaces.Length(); i++) {
+    mRuleFaces[i].mFontFace->DisconnectFromRule();
+    mRuleFaces[i].mFontFace->SetUserFontEntry(nullptr);
+  }
+  for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
+    mNonRuleFaces[i]->SetUserFontEntry(nullptr);
+  }
+  for (size_t i = 0; i < mUnavailableFaces.Length(); i++) {
+    mUnavailableFaces[i]->SetUserFontEntry(nullptr);
+  }
+  mRuleFaces.Clear();
+  mNonRuleFaces.Clear();
+  mUnavailableFaces.Clear();
+  mReady = nullptr;
+  mUserFontSet = nullptr;
+}
+
+void
+FontFaceSet::RemoveLoader(nsFontFaceLoader* aLoader)
+{
+  mLoaders.RemoveEntry(aLoader);
+}
+
+nsresult
+FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
+                       const gfxFontFaceSrc* aFontFaceSrc)
+{
+  nsresult rv;
+
+  nsIPresShell* ps = mPresContext->PresShell();
+  if (!ps)
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIStreamLoader> streamLoader;
+  nsCOMPtr<nsILoadGroup> loadGroup(ps->GetDocument()->GetDocumentLoadGroup());
+
+  nsCOMPtr<nsIChannel> channel;
+  // get Content Security Policy from principal to pass into channel
+  nsCOMPtr<nsIChannelPolicy> channelPolicy;
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  rv = aUserFontEntry->GetPrincipal()->GetCsp(getter_AddRefs(csp));
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (csp) {
+    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
+    channelPolicy->SetContentSecurityPolicy(csp);
+    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
+  }
+  // Note we are calling NS_NewChannelInternal() with both a node and a
+  // principal.  This is because the document where the font is being loaded
+  // might have a different origin from the principal of the stylesheet
+  // that initiated the font load.
+  rv = NS_NewChannelInternal(getter_AddRefs(channel),
+                             aFontFaceSrc->mURI,
+                             ps->GetDocument(),
+                             aUserFontEntry->GetPrincipal(),
+                             nsILoadInfo::SEC_NORMAL,
+                             nsIContentPolicy::TYPE_FONT,
+                             channelPolicy,
+                             loadGroup);
+
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsRefPtr<nsFontFaceLoader> fontLoader =
+    new nsFontFaceLoader(aUserFontEntry, aFontFaceSrc->mURI, this, channel);
+
+  if (!fontLoader)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+#ifdef PR_LOGGING
+  if (LOG_ENABLED()) {
+    nsAutoCString fontURI, referrerURI;
+    aFontFaceSrc->mURI->GetSpec(fontURI);
+    if (aFontFaceSrc->mReferrer)
+      aFontFaceSrc->mReferrer->GetSpec(referrerURI);
+    LOG(("fontdownloader (%p) download start - font uri: (%s) "
+         "referrer uri: (%s)\n",
+         fontLoader.get(), fontURI.get(), referrerURI.get()));
+  }
+#endif
+
+  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
+  if (httpChannel)
+    httpChannel->SetReferrer(aFontFaceSrc->mReferrer);
+  nsCOMPtr<nsISupportsPriority> priorityChannel(do_QueryInterface(channel));
+  if (priorityChannel) {
+    priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH);
+  }
+
+  rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsIDocument *document = ps->GetDocument();
+  mozilla::net::PredictorLearn(aFontFaceSrc->mURI, document->GetDocumentURI(),
+                               nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
+                               loadGroup);
+
+  bool inherits = false;
+  rv = NS_URIChainHasFlags(aFontFaceSrc->mURI,
+                           nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
+                           &inherits);
+  if (NS_SUCCEEDED(rv) && inherits) {
+    // allow data, javascript, etc URI's
+    rv = channel->AsyncOpen(streamLoader, nullptr);
+  } else {
+    nsRefPtr<nsCORSListenerProxy> listener =
+      new nsCORSListenerProxy(streamLoader, aUserFontEntry->GetPrincipal(), false);
+    rv = listener->Init(channel);
+    if (NS_SUCCEEDED(rv)) {
+      rv = channel->AsyncOpen(listener, nullptr);
+    }
+    if (NS_FAILED(rv)) {
+      fontLoader->DropChannel();  // explicitly need to break ref cycle
+    }
+  }
+
+  if (NS_SUCCEEDED(rv)) {
+    mLoaders.PutEntry(fontLoader);
+    fontLoader->StartedLoading(streamLoader);
+    aUserFontEntry->SetLoader(fontLoader); // let the font entry remember the
+                                           // loader, in case we need to cancel it
+  }
+
+  return rv;
+}
+
+static PLDHashOperator DetachFontEntries(const nsAString& aKey,
+                                         nsRefPtr<gfxUserFontFamily>& aFamily,
+                                         void* aUserArg)
+{
+  aFamily->DetachFontEntries();
+  return PL_DHASH_NEXT;
+}
+
+static PLDHashOperator RemoveIfEmpty(const nsAString& aKey,
+                                     nsRefPtr<gfxUserFontFamily>& aFamily,
+                                     void* aUserArg)
+{
+  return aFamily->GetFontList().Length() ? PL_DHASH_NEXT : PL_DHASH_REMOVE;
+}
+
+bool
+FontFaceSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
+{
+  MOZ_ASSERT(mUserFontSet);
+
+  // If there was a change to the mNonRuleFaces array, then there could
+  // have been a modification to the user font set.
+  bool modified = mNonRuleFacesDirty;
+  mNonRuleFacesDirty = false;
+
+  // The @font-face rules that make up the user font set have changed,
+  // so we need to update the set. However, we want to preserve existing
+  // font entries wherever possible, so that we don't discard and then
+  // re-download resources in the (common) case where at least some of the
+  // same rules are still present.
+
+  nsTArray<FontFaceRecord> oldRecords;
+  mRuleFaces.SwapElements(oldRecords);
+
+  // Remove faces from the font family records; we need to re-insert them
+  // because we might end up with faces in a different order even if they're
+  // the same font entries as before. (The order can affect font selection
+  // where multiple faces match the requested style, perhaps with overlapping
+  // unicode-range coverage.)
+  mUserFontSet->mFontFamilies.Enumerate(DetachFontEntries, nullptr);
+
+  // Sometimes aRules has duplicate @font-face rules in it; we should make
+  // that not happen, but in the meantime, don't try to insert the same
+  // FontFace object more than once into mRuleFaces.  We track which
+  // ones we've handled in this table.
+  nsTHashtable<nsPtrHashKey<nsCSSFontFaceRule>> handledRules;
+
+  for (size_t i = 0, i_end = aRules.Length(); i < i_end; ++i) {
+    // Insert each FontFace objects for each rule into our list, migrating old
+    // font entries if possible rather than creating new ones; set  modified  to
+    // true if we detect that rule ordering has changed, or if a new entry is
+    // created.
+    if (handledRules.Contains(aRules[i].mRule)) {
+      continue;