merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 22 Dec 2015 11:47:07 +0100
changeset 277273 ad16863d1d45bd3fd7906c76fa1ac1e12d24a133
parent 277146 1696c9dfdd050957145c1d408f61d9c7e4f04b00 (current diff)
parent 277272 9a391c10014fa0c9f74f90ece95f1ac855e899d3 (diff)
child 277281 be401039fb14fdd9679121c634eeb873be2e7f08
child 277314 641269d204eb50397e0b788fd963a6a4c3ce640c
child 277373 38bee2a18df23089ca629dae53920867a63a2fc8
push id29819
push usercbook@mozilla.com
push dateTue, 22 Dec 2015 10:47:17 +0000
treeherdermozilla-central@ad16863d1d45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone46.0a1
first release with
nightly linux32
ad16863d1d45 / 46.0a1 / 20151222030207 / files
nightly linux64
ad16863d1d45 / 46.0a1 / 20151222030207 / files
nightly mac
ad16863d1d45 / 46.0a1 / 20151222030207 / files
nightly win32
ad16863d1d45 / 46.0a1 / 20151222030207 / files
nightly win64
ad16863d1d45 / 46.0a1 / 20151222030207 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
dom/media/test/test_can_play_type_no_wave.html
dom/media/test/test_can_play_type_no_webm.html
gfx/layers/YCbCrImageDataSerializer.cpp
gfx/layers/YCbCrImageDataSerializer.h
gfx/layers/apz/src/TaskThrottler.cpp
gfx/layers/apz/src/TaskThrottler.h
toolkit/components/telemetry/Histograms.json
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4747,17 +4747,17 @@ var CombinedStopReload = {
       this._timer = 0;
     }
   }
 };
 
 var TabsProgressListener = {
   onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
     // Collect telemetry data about tab load times.
-    if (aWebProgress.isTopLevel) {
+    if (aWebProgress.isTopLevel && (!aRequest.originalURI || aRequest.originalURI.spec.scheme != "about")) {
       if (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
         if (aStateFlags & Ci.nsIWebProgressListener.STATE_START) {
           TelemetryStopwatch.start("FX_PAGE_LOAD_MS", aBrowser);
           Services.telemetry.getHistogramById("FX_TOTAL_TOP_VISITS").add(true);
         } else if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
           TelemetryStopwatch.finish("FX_PAGE_LOAD_MS", aBrowser);
         }
       } else if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
--- a/browser/base/content/test/popupNotifications/browser.ini
+++ b/browser/base/content/test/popupNotifications/browser.ini
@@ -1,14 +1,14 @@
 [DEFAULT]
 support-files =
   head.js
 
 [browser_displayURI.js]
 skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification.js]
-skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
+skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification_2.js]
-skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
+skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification_3.js]
-skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
+skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification_4.js]
-skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
+skip-if = (os == "linux" && (debug || asan))
--- a/browser/modules/BrowserUITelemetry.jsm
+++ b/browser/modules/BrowserUITelemetry.jsm
@@ -530,17 +530,17 @@ this.BrowserUITelemetry = {
       }
     }
 
     // Now go through the items in the palette to see what default
     // items are in there.
     let paletteItems =
       CustomizableUI.getUnusedWidgets(aWindow.gNavToolbox.palette);
     let defaultRemoved = [];
-    for (item of paletteItems) {
+    for (let item of paletteItems) {
       if (DEFAULT_ITEMS.indexOf(item.id) != -1) {
         defaultRemoved.push(item.id);
       }
     }
 
     result.defaultKept = defaultKept;
     result.defaultMoved = defaultMoved;
     result.nondefaultAdded = nondefaultAdded;
--- a/config/external/moz.build
+++ b/config/external/moz.build
@@ -21,23 +21,20 @@ if CONFIG['MOZ_UPDATER']:
 external_dirs += ['modules/brotli']
 
 if CONFIG['MOZ_VORBIS']:
     external_dirs += ['media/libvorbis']
 
 if CONFIG['MOZ_TREMOR']:
     external_dirs += ['media/libtremor']
 
-if CONFIG['MOZ_WEBM']:
-    external_dirs += ['media/libnestegg']
-
 if CONFIG['MOZ_WEBM_ENCODER']:
     external_dirs += ['media/libmkv']
 
-if CONFIG['MOZ_VPX'] and not CONFIG['MOZ_NATIVE_LIBVPX']:
+if not CONFIG['MOZ_NATIVE_LIBVPX']:
     external_dirs += ['media/libvpx']
 
 if not CONFIG['MOZ_NATIVE_PNG']:
     external_dirs += ['media/libpng']
 
 if CONFIG['CPU_ARCH'] == 'arm':
     external_dirs += ['media/openmax_dl']
 
@@ -45,16 +42,17 @@ if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
     external_dirs += [
         'media/sphinxbase',
         'media/pocketsphinx',
     ]
 
 external_dirs += [
     'media/kiss_fft',
     'media/libcubeb',
+    'media/libnestegg',
     'media/libogg',
     'media/libopus',
     'media/libtheora',
     'media/libspeex_resampler',
     'media/libstagefright',
     'media/libsoundtouch',
 ]
 
--- a/configure.in
+++ b/configure.in
@@ -87,18 +87,18 @@ AC_PROG_AWK
 dnl Initialize the Pthread test variables early so they can be
 dnl  overridden by each platform.
 dnl ========================================================
 MOZ_USE_PTHREADS=
 _PTHREAD_LDFLAGS=""
 
 dnl Do not allow objdir == srcdir builds.
 dnl ==============================================================
-_topsrcdir=`cd \`dirname $0\`; pwd -W 2>/dev/null || pwd`
-_objdir=`pwd`
+_topsrcdir=`cd \`dirname $0\`; pwd -W 2>/dev/null || pwd -P`
+_objdir=`pwd -P`
 
 dnl TODO Don't exempt L10N builds once bug 842760 is resolved.
 if test "$_topsrcdir" = "$_objdir" -a "${with_l10n_base+set}" != set; then
   echo "  ***"
   echo "  * Building directly in the main source directory is not allowed."
   echo "  *"
   echo "  * To build, you must run configure from a separate directory"
   echo "  * (referred to as an object directory)."
@@ -129,17 +129,17 @@ if test "$_conflict_files"; then
   *   To clean up the source tree:
   *     1. cd $_topsrcdir
   *     2. gmake distclean
   ***
 EOF
   exit 1
   break
 fi
-MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd`
+MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd -P`
 DIST="$MOZ_BUILD_ROOT/dist"
 
 MOZ_PYTHON
 
 MOZ_BUILD_BACKEND
 
 MOZ_DEFAULT_COMPILER
 
@@ -152,17 +152,17 @@ AC_SUBST(COMPILE_ENVIRONMENT)
 
 MOZ_ARG_WITH_STRING(l10n-base,
 [  --with-l10n-base=DIR    path to l10n repositories],
     L10NBASEDIR=$withval)
 if test -n "$L10NBASEDIR"; then
     if test "$L10NBASEDIR" = "yes" -o "$L10NBASEDIR" = "no"; then
         AC_MSG_ERROR([--with-l10n-base must specify a path])
     elif test -d "$L10NBASEDIR"; then
-        L10NBASEDIR=`cd "$L10NBASEDIR" && pwd`
+        L10NBASEDIR=`cd "$L10NBASEDIR" && pwd -P`
     else
         AC_MSG_ERROR([Invalid value --with-l10n-base, $L10NBASEDIR doesn't exist])
     fi
 fi
 AC_SUBST(L10NBASEDIR)
 
 dnl Check for Perl first -- needed for win32 SDK checks
 MOZ_PATH_PROGS(PERL, $PERL perl5 perl )
@@ -3687,20 +3687,18 @@ MOZ_FEEDS=1
 MOZ_WEBAPP_RUNTIME=
 MOZ_AUTH_EXTENSION=1
 if test "$MOZ_IOS"; then
    MOZ_AUTH_EXTENSION=
 fi
 MOZ_RAW=
 MOZ_VORBIS=
 MOZ_TREMOR=
-MOZ_WAVE=1
 MOZ_SAMPLE_TYPE_FLOAT32=
 MOZ_SAMPLE_TYPE_S16=
-MOZ_WEBM=1
 MOZ_GSTREAMER=
 MOZ_DIRECTSHOW=
 MOZ_WMF=
 if test -n "$MOZ_FMP4"; then
   MOZ_FMP4=1
 else
   MOZ_FMP4=
 fi
@@ -3710,17 +3708,16 @@ MOZ_PEERCONNECTION=
 MOZ_SRTP=
 MOZ_WEBRTC_SIGNALING=
 MOZ_WEBRTC_ASSERT_ALWAYS=1
 MOZ_WEBRTC_HARDWARE_AEC_NS=
 MOZ_SCTP=
 MOZ_ANDROID_OMX=
 MOZ_MEDIA_NAVIGATOR=
 MOZ_OMX_PLUGIN=
-MOZ_VPX=
 MOZ_VPX_ERROR_CONCEALMENT=
 MOZ_WEBSPEECH=1
 MOZ_WEBSPEECH_MODELS=
 MOZ_WEBSPEECH_POCKETSPHINX=
 MOZ_WEBSPEECH_TEST_BACKEND=1
 VPX_AS=
 VPX_ASFLAGS=
 VPX_AS_CONVERSION=
@@ -4993,17 +4990,16 @@ MOZ_ARG_DISABLE_BOOL(webrtc,
     MOZ_WEBRTC=1)
 
 if test -n "$MOZ_WEBRTC"; then
     AC_DEFINE(MOZ_WEBRTC)
     dnl MOZ_WEBRTC_ASSERT_ALWAYS turns on a number of safety asserts in
     dnl opt/production builds (via MOZ_CRASH())
     AC_DEFINE(MOZ_WEBRTC_ASSERT_ALWAYS)
     MOZ_RAW=1
-    MOZ_VPX=1
     MOZ_VPX_ERROR_CONCEALMENT=1
 
 dnl enable once Signaling lands
     MOZ_WEBRTC_SIGNALING=1
     AC_DEFINE(MOZ_WEBRTC_SIGNALING)
 dnl enable once PeerConnection lands
     MOZ_PEERCONNECTION=1
     AC_DEFINE(MOZ_PEERCONNECTION)
@@ -5139,29 +5135,16 @@ AC_CACHE_CHECK([__attribute__ ((aligned 
      done
        CFLAGS="${CFLAGS_save}"])
 if test "${ac_cv_c_attribute_aligned}" != "0"; then
   AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX],
                      [${ac_cv_c_attribute_aligned}],[Maximum supported data alignment])
 fi
 
 dnl ========================================================
-dnl = Disable VP8 decoder support
-dnl ========================================================
-MOZ_ARG_DISABLE_BOOL(webm,
-[  --disable-webm          Disable support for WebM media (VP8 video and Vorbis audio)],
-    MOZ_WEBM=,
-    MOZ_WEBM=1)
-
-if test -n "$MOZ_WEBM"; then
-    AC_DEFINE(MOZ_WEBM)
-    MOZ_VPX=1
-fi;
-
-dnl ========================================================
 dnl = Apple platform decoder support
 dnl ========================================================
 if test "$MOZ_WIDGET_TOOLKIT" = "cocoa" || test "$MOZ_WIDGET_TOOLKIT" = "uikit"; then
   MOZ_APPLEMEDIA=1
 fi
 
 if test "$COMPILE_ENVIRONMENT"; then
 if test -n "$MOZ_APPLEMEDIA"; then
@@ -5356,64 +5339,59 @@ dnl system libvpx Support
 dnl ========================================================
 MOZ_ARG_WITH_BOOL(system-libvpx,
 [  --with-system-libvpx    Use system libvpx (located with pkgconfig)],
     MOZ_NATIVE_LIBVPX=1)
 
 MOZ_LIBVPX_CFLAGS=
 MOZ_LIBVPX_LIBS=
 
-if test -n "$MOZ_VPX"; then
-    AC_DEFINE(MOZ_VPX)
-    if test -n "$MOZ_VPX_ERROR_CONCEALMENT" ; then
-        AC_DEFINE(MOZ_VPX_ERROR_CONCEALMENT)
-    fi
-
-    _SAVE_CFLAGS=$CFLAGS
-    _SAVE_LIBS=$LIBS
-    if test -n "$MOZ_NATIVE_LIBVPX"; then
-        dnl ============================
-        dnl === libvpx Version check ===
-        dnl ============================
-        dnl Check to see if we have a system libvpx package.
-        PKG_CHECK_MODULES(MOZ_LIBVPX, vpx >= 1.3.0)
-
-        CFLAGS="$CFLAGS $MOZ_LIBVPX_CFLAGS"
-        LIBS="$LIBS $MOZ_LIBVPX_LIBS"
-
-        MOZ_CHECK_HEADER([vpx/vpx_decoder.h], [],
-         [AC_MSG_ERROR([Couldn't find vpx/vpx_decoder.h which is required for build with system libvpx. Use --without-system-libvpx to build with in-tree libvpx.])])
-
-        AC_CHECK_LIB(vpx, vpx_codec_dec_init_ver, [],
-         [AC_MSG_ERROR([--with-system-libvpx requested but symbol vpx_codec_dec_init_ver not found])])
-
-        MOZ_CHECK_HEADER([vpx_mem/vpx_mem.h],
-         [AC_CHECK_FUNC(vpx_mem_set_functions)])
-        if test "$ac_cv_header_vpx_mem_vpx_mem_h" = no -o \
-                "$ac_cv_func_vpx_mem_set_functions" = no; then
-            AC_DEFINE(MOZ_VPX_NO_MEM_REPORTING)
-        fi
-    fi
-    CFLAGS=$_SAVE_CFLAGS
-    LIBS=$_SAVE_LIBS
-fi
+if test -n "$MOZ_VPX_ERROR_CONCEALMENT" ; then
+    AC_DEFINE(MOZ_VPX_ERROR_CONCEALMENT)
+fi
+
+_SAVE_CFLAGS=$CFLAGS
+_SAVE_LIBS=$LIBS
+if test -n "$MOZ_NATIVE_LIBVPX"; then
+    dnl ============================
+    dnl === libvpx Version check ===
+    dnl ============================
+    dnl Check to see if we have a system libvpx package.
+    PKG_CHECK_MODULES(MOZ_LIBVPX, vpx >= 1.3.0)
+
+    CFLAGS="$CFLAGS $MOZ_LIBVPX_CFLAGS"
+    LIBS="$LIBS $MOZ_LIBVPX_LIBS"
+
+    MOZ_CHECK_HEADER([vpx/vpx_decoder.h], [],
+     [AC_MSG_ERROR([Couldn't find vpx/vpx_decoder.h which is required for build with system libvpx. Use --without-system-libvpx to build with in-tree libvpx.])])
+
+    AC_CHECK_LIB(vpx, vpx_codec_dec_init_ver, [],
+     [AC_MSG_ERROR([--with-system-libvpx requested but symbol vpx_codec_dec_init_ver not found])])
+
+    MOZ_CHECK_HEADER([vpx_mem/vpx_mem.h],
+     [AC_CHECK_FUNC(vpx_mem_set_functions)])
+    if test "$ac_cv_header_vpx_mem_vpx_mem_h" = no -o \
+            "$ac_cv_func_vpx_mem_set_functions" = no; then
+        AC_DEFINE(MOZ_VPX_NO_MEM_REPORTING)
+    fi
+fi
+CFLAGS=$_SAVE_CFLAGS
+LIBS=$_SAVE_LIBS
 
 AC_SUBST(MOZ_NATIVE_LIBVPX)
 AC_SUBST_LIST(MOZ_LIBVPX_CFLAGS)
 AC_SUBST_LIST(MOZ_LIBVPX_LIBS)
 
-if test "$MOZ_WEBM"; then
-    if test "$MOZ_SAMPLE_TYPE_FLOAT32"; then
-        MOZ_VORBIS=1
-    else
-        MOZ_TREMOR=1
-    fi
-fi
-
-if test -n "$MOZ_VPX" -a -z "$MOZ_NATIVE_LIBVPX"; then
+if test "$MOZ_SAMPLE_TYPE_FLOAT32"; then
+    MOZ_VORBIS=1
+else
+    MOZ_TREMOR=1
+fi
+
+if test -z "$MOZ_NATIVE_LIBVPX"; then
 
     dnl Detect if we can use an assembler to compile optimized assembly for libvpx.
     dnl We currently require yasm on all x86 platforms and require yasm 1.1.0 on Win32.
     dnl We currently require gcc on all arm platforms.
     VPX_AS=$YASM
     VPX_ASM_SUFFIX=asm
     VPX_NEED_OBJ_INT_EXTRACT=
 
@@ -5506,28 +5484,16 @@ if test -n "$MOZ_VPX" -a -z "$MOZ_NATIVE
       AC_MSG_WARN([No assembler or assembly support for libvpx. Using unoptimized C routines.])
     fi
 
     dnl native libvpx no longer has vpx_mem_set_functions
     AC_DEFINE(MOZ_VPX_NO_MEM_REPORTING)
 fi
 
 dnl ========================================================
-dnl = Disable Wave decoder support
-dnl ========================================================
-MOZ_ARG_DISABLE_BOOL(wave,
-[  --disable-wave          Disable Wave decoder support],
-    MOZ_WAVE=,
-    MOZ_WAVE=1)
-
-if test -n "$MOZ_WAVE"; then
-    AC_DEFINE(MOZ_WAVE)
-fi
-
-dnl ========================================================
 dnl = Handle dependent MEDIA defines
 dnl ========================================================
 
 if test -n "$MOZ_VORBIS" -a -n "$MOZ_TREMOR"; then
     AC_MSG_ERROR([MOZ_VORBIS and MOZ_TREMOR are mutually exclusive!  The build system should not allow them both to be set, but they are.  Please file a bug at https://bugzilla.mozilla.org/])
 fi
 
 if test -n "$MOZ_VORBIS"; then
@@ -8921,30 +8887,27 @@ AC_SUBST(IMPORT_LIB_SUFFIX)
 AC_SUBST(USE_N32)
 AC_SUBST(CC_VERSION)
 AC_SUBST(CXX_VERSION)
 AC_SUBST(MSMANIFEST_TOOL)
 AC_SUBST(NS_ENABLE_TSF)
 AC_SUBST(WIN32_CONSOLE_EXE_LDFLAGS)
 AC_SUBST(WIN32_GUI_EXE_LDFLAGS)
 
-AC_SUBST(MOZ_WAVE)
 AC_SUBST(MOZ_VORBIS)
 AC_SUBST(MOZ_TREMOR)
-AC_SUBST(MOZ_WEBM)
 AC_SUBST(MOZ_WMF)
 AC_SUBST(MOZ_FFMPEG)
 AC_SUBST(MOZ_FMP4)
 AC_SUBST(MOZ_EME)
 AC_SUBST(MOZ_DIRECTSHOW)
 AC_SUBST(MOZ_ANDROID_OMX)
 AC_SUBST(MOZ_APPLEMEDIA)
 AC_SUBST(MOZ_OMX_PLUGIN)
 AC_SUBST(MOZ_VPX_ERROR_CONCEALMENT)
-AC_SUBST(MOZ_VPX)
 AC_SUBST(VPX_AS)
 AC_SUBST_LIST(VPX_ASFLAGS)
 AC_SUBST(VPX_AS_CONVERSION)
 AC_SUBST(VPX_ASM_SUFFIX)
 AC_SUBST(VPX_X86_ASM)
 AC_SUBST(VPX_ARM_ASM)
 AC_SUBST(VPX_NEED_OBJ_INT_EXTRACT)
 AC_SUBST(MOZ_INSTRUMENT_EVENT_LOOP)
--- a/devtools/server/actors/script.js
+++ b/devtools/server/actors/script.js
@@ -7,17 +7,17 @@
 "use strict";
 
 const Services = require("Services");
 const { Cc, Ci, Cu, components, ChromeWorker } = require("chrome");
 const { ActorPool, OriginalLocation, GeneratedLocation } = require("devtools/server/actors/common");
 const { ObjectActor, createValueGrip, longStringGrip } = require("devtools/server/actors/object");
 const { DebuggerServer } = require("devtools/server/main");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
-const { assert, dbg_assert, dumpn, update, fetch } = DevToolsUtils;
+const { assert, dumpn, update, fetch } = DevToolsUtils;
 const { dirname, joinURI } = require("devtools/shared/path");
 const promise = require("promise");
 const PromiseDebugging = require("PromiseDebugging");
 const xpcInspector = require("xpcInspector");
 const ScriptStore = require("./utils/ScriptStore");
 const { DevToolsWorker } = require("devtools/shared/worker/worker");
 
 const { defer, resolve, reject, all } = promise;
@@ -349,18 +349,16 @@ EventLoop.prototype = {
     // Keep exiting nested event loops while the last requestor is resolved.
     if (xpcInspector.eventLoopNestLevel > 0) {
       const { resolved } = xpcInspector.lastNestRequestor;
       if (resolved) {
         xpcInspector.exitNestedEventLoop();
       }
     }
 
-    dbg_assert(this._thread.state === "running", "Should be in the running state");
-
     if (this._hooks.postNest) {
       this._hooks.postNest(nestData);
     }
   },
 
   /**
    * Resolve this nested event loop.
    *
--- a/devtools/shared/DevToolsUtils.js
+++ b/devtools/shared/DevToolsUtils.js
@@ -178,18 +178,22 @@ exports.compose = function compose(...fu
 
 /**
  * Waits for the next tick in the event loop to execute a callback.
  */
 exports.executeSoon = function executeSoon(aFn) {
   if (isWorker) {
     setImmediate(aFn);
   } else {
+    let stack = components.stack;
+    let executor = () => {
+      Cu.callFunctionWithAsyncStack(aFn, stack, "DevToolsUtils.executeSoon");
+    };
     Services.tm.mainThread.dispatch({
-      run: exports.makeInfallible(aFn)
+      run: exports.makeInfallible(executor)
     }, Ci.nsIThread.DISPATCH_NORMAL);
   }
 };
 
 /**
  * Waits for the next tick in the event loop.
  *
  * @return Promise
@@ -452,34 +456,16 @@ exports.defineLazyGetter = function defi
       delete aObject[aName];
       return aObject[aName] = aLambda.apply(aObject);
     },
     configurable: true,
     enumerable: true
   });
 };
 
-// DEPRECATED: use DevToolsUtils.assert(condition, message) instead!
-let haveLoggedDeprecationMessage = false;
-exports.dbg_assert = function dbg_assert(cond, e) {
-  if (!haveLoggedDeprecationMessage) {
-    haveLoggedDeprecationMessage = true;
-    const deprecationMessage = "DevToolsUtils.dbg_assert is deprecated! Use DevToolsUtils.assert instead!\n"
-          + Error().stack;
-    dump(deprecationMessage);
-    if (typeof console === "object" && console && console.warn) {
-      console.warn(deprecationMessage);
-    }
-  }
-
-  if (!cond) {
-    return e;
-  }
-};
-
 exports.defineLazyGetter(this, "AppConstants", () => {
   if (isWorker) {
     return {};
   }
   const scope = {};
   Cu.import("resource://gre/modules/AppConstants.jsm", scope);
   return scope.AppConstants;
 });
new file mode 100644
--- /dev/null
+++ b/devtools/shared/tests/unit/test_executeSoon.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Client request stacks should span the entire process from before making the
+ * request to handling the reply from the server.  The server frames are not
+ * included, nor can they be in most cases, since the server can be a remote
+ * device.
+ */
+
+var { executeSoon } = require("devtools/shared/DevToolsUtils");
+var promise = require("promise");
+var Services = require("Services");
+
+var asyncStackEnabled =
+  Services.prefs.getBoolPref("javascript.options.asyncstack");
+
+do_register_cleanup(() => {
+  Services.prefs.setBoolPref("javascript.options.asyncstack",
+                             asyncStackEnabled);
+});
+
+add_task(function*() {
+  Services.prefs.setBoolPref("javascript.options.asyncstack", true);
+
+  yield waitForTick();
+
+  let stack = Components.stack;
+  while (stack) {
+    do_print(stack.name);
+    if (stack.name == "waitForTick") {
+      // Reached back to outer function before executeSoon
+      ok(true, "Complete stack");
+      return;
+    }
+    stack = stack.asyncCaller || stack.caller;
+  }
+  ok(false, "Incomplete stack");
+});
+
+function waitForTick() {
+  let deferred = promise.defer();
+  executeSoon(deferred.resolve);
+  return deferred.promise;
+}
--- a/devtools/shared/tests/unit/xpcshell.ini
+++ b/devtools/shared/tests/unit/xpcshell.ini
@@ -19,8 +19,9 @@ support-files =
 [test_defineLazyPrototypeGetter.js]
 [test_async-utils.js]
 [test_consoleID.js]
 [test_cssColor.js]
 [test_prettifyCSS.js]
 [test_require_lazy.js]
 [test_require.js]
 [test_stack.js]
+[test_executeSoon.js]
--- a/dom/animation/DocumentTimeline.cpp
+++ b/dom/animation/DocumentTimeline.cpp
@@ -105,16 +105,18 @@ DocumentTimeline::NotifyAnimationUpdated
     }
   }
 }
 
 void
 DocumentTimeline::WillRefresh(mozilla::TimeStamp aTime)
 {
   MOZ_ASSERT(mIsObservingRefreshDriver);
+  MOZ_ASSERT(GetRefreshDriver(),
+             "Should be able to reach refresh driver from within WillRefresh");
 
   bool needsTicks = false;
   nsTArray<Animation*> animationsToRemove(mAnimations.Count());
 
   nsAutoAnimationMutationBatch mb(mDocument);
 
   for (Animation* animation = mAnimationOrder.getFirst(); animation;
        animation = animation->getNext()) {
@@ -138,20 +140,23 @@ DocumentTimeline::WillRefresh(mozilla::T
     }
   }
 
   for (Animation* animation : animationsToRemove) {
     RemoveAnimation(animation);
   }
 
   if (!needsTicks) {
-    // If another refresh driver observer destroys the nsPresContext,
-    // nsRefreshDriver will detect it and we won't be called.
+    // We already assert that GetRefreshDriver() is non-null at the beginning
+    // of this function but we check it again here to be sure that ticking
+    // animations does not have any side effects that cause us to lose the
+    // connection with the refresh driver, such as triggering the destruction
+    // of mDocument's PresShell.
     MOZ_ASSERT(GetRefreshDriver(),
-               "Refresh driver should still be valid inside WillRefresh");
+               "Refresh driver should still be valid at end of WillRefresh");
     GetRefreshDriver()->RemoveRefreshObserver(this, Flush_Style);
     mIsObservingRefreshDriver = false;
   }
 }
 
 void
 DocumentTimeline::NotifyRefreshDriverCreated(nsRefreshDriver* aDriver)
 {
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -91,17 +91,16 @@ KeyframeEffectReadOnly::KeyframeEffectRe
   nsCSSPseudoElements::Type aPseudoType,
   const AnimationTiming& aTiming)
   : AnimationEffectReadOnly(aDocument)
   , mTarget(aTarget)
   , mTiming(aTiming)
   , mPseudoType(aPseudoType)
 {
   MOZ_ASSERT(aTarget, "null animation target is not yet supported");
-  ResetIsRunningOnCompositor();
 }
 
 JSObject*
 KeyframeEffectReadOnly::WrapObject(JSContext* aCx,
                                    JS::Handle<JSObject*> aGivenProto)
 {
   return KeyframeEffectReadOnlyBinding::Wrap(aCx, this, aGivenProto);
 }
@@ -462,74 +461,55 @@ KeyframeEffectReadOnly::ComposeStyle(Ref
                                        segment->mFromValue,
                                        segment->mToValue,
                                        valuePosition, *val);
     MOZ_ASSERT(result, "interpolate must succeed now");
   }
 }
 
 bool
-KeyframeEffectReadOnly::IsPropertyRunningOnCompositor(
-  nsCSSProperty aProperty) const
-{
-  const auto& info = LayerAnimationInfo::sRecords;
-  for (size_t i = 0; i < ArrayLength(mIsPropertyRunningOnCompositor); i++) {
-    if (info[i].mProperty == aProperty) {
-      return mIsPropertyRunningOnCompositor[i];
-    }
-  }
-  return false;
-}
-
-bool
 KeyframeEffectReadOnly::IsRunningOnCompositor() const
 {
   // We consider animation is running on compositor if there is at least
   // one property running on compositor.
   // Animation.IsRunningOnCompotitor will return more fine grained
   // information in bug 1196114.
-  for (bool isPropertyRunningOnCompositor : mIsPropertyRunningOnCompositor) {
-    if (isPropertyRunningOnCompositor) {
+  for (const AnimationProperty& property : mProperties) {
+    if (property.mIsRunningOnCompositor) {
       return true;
     }
   }
   return false;
 }
 
 void
 KeyframeEffectReadOnly::SetIsRunningOnCompositor(nsCSSProperty aProperty,
                                                  bool aIsRunning)
 {
-  static_assert(
-    MOZ_ARRAY_LENGTH(LayerAnimationInfo::sRecords) ==
-      MOZ_ARRAY_LENGTH(mIsPropertyRunningOnCompositor),
-    "The length of mIsPropertyRunningOnCompositor should equal to"
-    "the length of LayserAnimationInfo::sRecords");
   MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
                                       CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
              "Property being animated on compositor is a recognized "
              "compositor-animatable property");
-  const auto& info = LayerAnimationInfo::sRecords;
-  for (size_t i = 0; i < ArrayLength(mIsPropertyRunningOnCompositor); i++) {
-    if (info[i].mProperty == aProperty) {
-      mIsPropertyRunningOnCompositor[i] = aIsRunning;
+  for (AnimationProperty& property : mProperties) {
+    if (property.mProperty == aProperty) {
+      property.mIsRunningOnCompositor = aIsRunning;
       return;
     }
   }
 }
 
 KeyframeEffectReadOnly::~KeyframeEffectReadOnly()
 {
 }
 
 void
 KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
 {
-  for (bool& isPropertyRunningOnCompositor : mIsPropertyRunningOnCompositor) {
-    isPropertyRunningOnCompositor = false;
+  for (AnimationProperty& property : mProperties) {
+    property.mIsRunningOnCompositor = false;
   }
 }
 
 void
 KeyframeEffectReadOnly::UpdateTargetRegistration()
 {
   if (!mTarget) {
     return;
@@ -551,19 +531,17 @@ KeyframeEffectReadOnly::UpdateTargetRegi
   } else {
     EffectSet* effectSet = EffectSet::GetEffectSet(mTarget, mPseudoType);
     if (effectSet) {
       effectSet->RemoveEffect(*this);
     }
     // Any effects not in the effect set will not be included in the set of
     // candidate effects for running on the compositor and hence they won't
     // have their compositor status updated so we should do that now.
-    for (bool& isRunningOnCompositor : mIsPropertyRunningOnCompositor) {
-      isRunningOnCompositor = false;
-    }
+    ResetIsRunningOnCompositor();
   }
 }
 
 #ifdef DEBUG
 void
 DumpAnimationProperties(nsTArray<AnimationProperty>& aAnimationProperties)
 {
   for (auto& p : aAnimationProperties) {
@@ -1817,17 +1795,17 @@ KeyframeEffectReadOnly::CanThrottle() co
     // b) The target element has no frame, e.g. because it is in a display:none
     //    subtree.
     // In either case we can throttle the animation because there is no
     // need to update on the main thread.
     return true;
   }
 
   // First we need to check layer generation and transform overflow
-  // prior to the IsPropertyRunningOnCompositor check because we should
+  // prior to the property.mIsRunningOnCompositor check because we should
   // occasionally unthrottle these animations even if the animations are
   // already running on compositor.
   for (const LayerAnimationInfo::Record& record :
         LayerAnimationInfo::sRecords) {
     // Skip properties that are overridden in the cascade.
     // (GetAnimationOfProperty, as called by HasAnimationOfProperty,
     // only returns an animation if it currently wins in the cascade.)
     if (!HasAnimationOfProperty(record.mProperty)) {
@@ -1849,17 +1827,17 @@ KeyframeEffectReadOnly::CanThrottle() co
     // we should unthrottle the animation periodically.
     if (record.mProperty == eCSSProperty_transform &&
         !CanThrottleTransformChanges(*frame)) {
       return false;
     }
   }
 
   for (const AnimationProperty& property : mProperties) {
-    if (!IsPropertyRunningOnCompositor(property.mProperty)) {
+    if (!property.mIsRunningOnCompositor) {
       return false;
     }
   }
 
   return true;
 }
 
 bool
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -113,17 +113,17 @@ struct AnimationPropertySegment
   }
   bool operator!=(const AnimationPropertySegment& aOther) const {
     return !(*this == aOther);
   }
 };
 
 struct AnimationProperty
 {
-  nsCSSProperty mProperty;
+  nsCSSProperty mProperty = eCSSProperty_UNKNOWN;
 
   // Does this property win in the CSS Cascade?
   //
   // For CSS transitions, this is true as long as a CSS animation on the
   // same property and element is not running, in which case we set this
   // to false so that the animation (lower in the cascade) can win.  We
   // then use this to decide whether to apply the style both in the CSS
   // cascade and for OMTA.
@@ -131,26 +131,36 @@ struct AnimationProperty
   // For CSS Animations, which are overridden by !important rules in the
   // cascade, we actually determine this from the CSS cascade
   // computations, and then use it for OMTA.
   // **NOTE**: For CSS animations, we only bother setting mWinsInCascade
   // accurately for properties that we can animate on the compositor.
   // For other properties, we make it always be true.
   // **NOTE 2**: This member is not included when comparing AnimationProperty
   // objects for equality.
-  bool mWinsInCascade;
+  bool mWinsInCascade = true;
+
+  // If true, the propery is currently being animated on the compositor.
+  //
+  // Note that when the owning Animation requests a non-throttled restyle, in
+  // between calling RequestRestyle on its AnimationCollection and when the
+  // restyle is performed, this member may temporarily become false even if
+  // the animation remains on the layer after the restyle.
+  bool mIsRunningOnCompositor = false;
 
   InfallibleTArray<AnimationPropertySegment> mSegments;
 
-  // NOTE: This operator does *not* compare the mWinsInCascade member.
+  // NOTE: This operator does *not* compare the mWinsInCascade member *or* the
+  // mIsRunningOnCompositor member.
   // This is because AnimationProperty objects are compared when recreating
   // CSS animations to determine if mutation observer change records need to
   // be created or not. However, at the point when these objects are compared
-  // the mWinsInCascade will not have been set on the new objects so we ignore
-  // this member to avoid generating spurious change records.
+  // neither the mWinsInCascade nor the mIsRunningOnCompositor will have been
+  // set on the new objects so we ignore these members to avoid generating
+  // spurious change records.
   bool operator==(const AnimationProperty& aOther) const {
     return mProperty == aOther.mProperty &&
            mSegments == aOther.mSegments;
   }
   bool operator!=(const AnimationProperty& aOther) const {
     return !(*this == aOther);
   }
 };
@@ -274,18 +284,16 @@ public:
   }
 
   // Updates |aStyleRule| with the animation values produced by this
   // AnimationEffect for the current time except any properties already
   // contained in |aSetProperties|.
   // Any updated properties are added to |aSetProperties|.
   void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
                     nsCSSPropertySet& aSetProperties);
-  // Returns true if |aProperty| is currently being animated on compositor.
-  bool IsPropertyRunningOnCompositor(nsCSSProperty aProperty) const;
   // Returns true if at least one property is being animated on compositor.
   bool IsRunningOnCompositor() const;
   void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
 
   bool CanThrottle() const;
 
   // Returns true if this effect, applied to |aFrame|, contains
   // properties that mean we shouldn't run *any* compositor animations on this
@@ -336,27 +344,16 @@ protected:
   nsCOMPtr<Element> mTarget;
   RefPtr<Animation> mAnimation;
 
   AnimationTiming mTiming;
   nsCSSPseudoElements::Type mPseudoType;
 
   InfallibleTArray<AnimationProperty> mProperties;
 
-  // Parallel array corresponding to CommonAnimationManager::sLayerAnimationInfo
-  // such that mIsPropertyRunningOnCompositor[x] is true only if this effect has
-  // an animation of CommonAnimationManager::sLayerAnimationInfo[x].mProperty
-  // that is currently running on the compositor.
-  //
-  // Note that when the owning Animation requests a non-throttled restyle, in
-  // between calling RequestRestyle on its AnimationCollection and when the
-  // restyle is performed, this member may temporarily become false even if
-  // the animation remains on the layer after the restyle.
-  bool mIsPropertyRunningOnCompositor[LayerAnimationInfo::kRecords];
-
 private:
   nsIFrame* GetAnimationFrame() const;
 
   bool CanThrottleTransformChanges(nsIFrame& aFrame) const;
 
   // Returns true unless Gecko limitations prevent performing transform
   // animations for |aFrame|. Any limitations that are encountered are
   // logged using |aContent| to describe the affected content.
--- a/dom/animation/test/chrome/test_running_on_compositor.html
+++ b/dom/animation/test/chrome/test_running_on_compositor.html
@@ -202,16 +202,19 @@ promise_test(function(t) {
         assert_true(!!changedAnimation, 'The animation should be recorded '
           + 'as one of the changedAnimations');
         assert_equals(animation.isRunningOnCompositor, omtaEnabled,
           'Animation reports that it is running on the compositor'
            + ' in MutationObserver callback');
         resolve();
       }));
       observer.observe(div, { animations: true, subtree: false });
+      t.add_cleanup(function() {
+        observer.disconnect();
+      });
       div.style.animationDuration = "200s";
     }));
   }));
 }, 'isRunningOnCompositor is true in MutationObserver callback');
 
 // This is to test that we don't temporarily clear the flag when forcing
 // an unthrottled sample.
 promise_test(function(t) {
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2112,17 +2112,25 @@ nsDocument::Reset(nsIChannel* aChannel, 
     }
   }
 
   ResetToURI(uri, aLoadGroup, principal);
 
   // Note that, since mTiming does not change during a reset, the
   // navigationStart time remains unchanged and therefore any future new
   // timeline will have the same global clock time as the old one.
-  mDocumentTimeline = nullptr;
+  if (mDocumentTimeline) {
+    nsRefreshDriver* rd = mPresShell && mPresShell->GetPresContext() ?
+                          mPresShell->GetPresContext()->RefreshDriver() :
+                          nullptr;
+    if (rd) {
+      mDocumentTimeline->NotifyRefreshDriverDestroying(rd);
+    }
+    mDocumentTimeline = nullptr;
+  }
 
   nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
   if (bag) {
     nsCOMPtr<nsIURI> baseURI;
     bag->GetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
                                 NS_GET_IID(nsIURI), getter_AddRefs(baseURI));
     if (baseURI) {
       mDocumentBaseURI = baseURI;
--- a/dom/bindings/test/mochitest.ini
+++ b/dom/bindings/test/mochitest.ini
@@ -59,15 +59,16 @@ skip-if = debug == false
 skip-if = debug == false
 [test_exception_options_from_jsimplemented.html]
 skip-if = debug == false
 [test_promise_rejections_from_jsimplemented.html]
 skip-if = debug == false
 [test_worker_UnwrapArg.html]
 [test_unforgeablesonexpando.html]
 [test_crossOriginWindowSymbolAccess.html]
+[test_primitive_this.html]
 [test_callback_exceptions.html]
 [test_bug1123516_maplikesetlike.html]
 skip-if = debug == false
 [test_jsimplemented_eventhandler.html]
 skip-if = debug == false
 [test_iterable.html]
 skip-if = debug == false
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_primitive_this.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=603201
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 603201</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 603201 **/
+
+  SimpleTest.waitForExplicitFinish();
+  function runTest()
+  {
+    var nodes = document.body.childNodes;
+
+    Object.setPrototypeOf(Number.prototype, nodes);
+
+    Object.defineProperty(nodes, "getter", {get: function() {
+      "use strict";
+      is(this, 1);
+      return "getter";
+    }});
+    Object.defineProperty(Object.getPrototypeOf(nodes), "getter2", {get: function() {
+      "use strict";
+      is(this, 1);
+      return "getter2";
+    }});
+
+    var number = 1;
+    is(number.getter, "getter");
+    is(number.getter2, "getter2");
+
+    SimpleTest.finish();
+  }
+
+  </script>
+</head>
+<body onload="runTest();">
+<pre>Test</pre>
+</body>
+</html>
--- a/dom/html/HTMLAudioElement.cpp
+++ b/dom/html/HTMLAudioElement.cpp
@@ -20,21 +20,18 @@
 #include "mozilla/dom/TimeRanges.h"
 #include "AudioStream.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Audio)
 
 namespace mozilla {
 namespace dom {
 
-extern bool IsAudioAPIEnabled();
-
 NS_IMPL_ELEMENT_CLONE(HTMLAudioElement)
 
-
 HTMLAudioElement::HTMLAudioElement(already_AddRefed<NodeInfo>& aNodeInfo)
   : HTMLMediaElement(aNodeInfo)
 {
 }
 
 HTMLAudioElement::~HTMLAudioElement()
 {
 }
@@ -74,23 +71,19 @@ HTMLAudioElement::Audio(const GlobalObje
   }
 
   return audio.forget();
 }
 
 nsresult HTMLAudioElement::SetAcceptHeader(nsIHttpChannel* aChannel)
 {
     nsAutoCString value(
-#ifdef MOZ_WEBM
       "audio/webm,"
-#endif
       "audio/ogg,"
-#ifdef MOZ_WAVE
       "audio/wav,"
-#endif
       "audio/*;q=0.9,"
       "application/ogg;q=0.7,"
       "video/*;q=0.6,*/*;q=0.5");
 
     return aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                       value,
                                       false);
 }
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -931,24 +931,26 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
                                                   nsGenericHTMLFormElementWithState)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
   if (tmp->IsSingleLineTextControl(false)) {
     tmp->mInputData.mState->Traverse(cb);
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesAndDirectoriesPromise)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,
                                                 nsGenericHTMLFormElementWithState)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesAndDirectoriesPromise)
   if (tmp->IsSingleLineTextControl(false)) {
     tmp->mInputData.mState->Unlink();
   }
   //XXX should unlink more?
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ADDREF_INHERITED(HTMLInputElement, Element)
 NS_IMPL_RELEASE_INHERITED(HTMLInputElement, Element)
--- a/dom/html/HTMLVideoElement.cpp
+++ b/dom/html/HTMLVideoElement.cpp
@@ -108,19 +108,17 @@ nsMapRuleToAttributesFunc
 HTMLVideoElement::GetAttributeMappingFunction() const
 {
   return &MapAttributesIntoRule;
 }
 
 nsresult HTMLVideoElement::SetAcceptHeader(nsIHttpChannel* aChannel)
 {
   nsAutoCString value(
-#ifdef MOZ_WEBM
       "video/webm,"
-#endif
       "video/ogg,"
       "video/*;q=0.9,"
       "application/ogg;q=0.7,"
       "audio/*;q=0.6,*/*;q=0.5");
 
   return aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                     value,
                                     false);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -453,44 +453,66 @@ static void LogChannelRelevantInfo(nsIUR
                                                 loadingOrigin.get(),
                                                 aContentPolicyType);
 
   nsCString resultPrincipalOrigin;
   aChannelResultPrincipal->GetOrigin(resultPrincipalOrigin);
   LOG("Result principal origin: %s\n", resultPrincipalOrigin.get());
 }
 
+// This is similar to nsIScriptSecurityManager.getChannelResultPrincipal
+// but taking signedPkg into account. The reason we can't rely on channel
+// loadContext/loadInfo is it's dangerous to mutate them on parent process.
+static already_AddRefed<nsIPrincipal>
+GetChannelPrincipalWithSingedPkg(nsIChannel* aChannel, const nsACString& aSignedPkg)
+{
+  NeckoOriginAttributes neckoAttrs;
+  NS_GetOriginAttributes(aChannel, neckoAttrs);
+
+  PrincipalOriginAttributes attrs;
+  attrs.InheritFromNecko(neckoAttrs);
+  attrs.mSignedPkg = NS_ConvertUTF8toUTF16(aSignedPkg);
+
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  nsCOMPtr<nsIPrincipal> principal =
+    BasePrincipal::CreateCodebasePrincipal(uri, attrs);
+
+  return principal.forget();
+}
+
 bool
-TabParent::ShouldSwitchProcess(nsIChannel* aChannel)
+TabParent::ShouldSwitchProcess(nsIChannel* aChannel, const nsACString& aSignedPkg)
 {
   // If we lack of any information which is required to decide the need of
   // process switch, consider that we should switch process.
 
   // Prepare the channel loading principal.
   nsCOMPtr<nsILoadInfo> loadInfo;
   aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
   NS_ENSURE_TRUE(loadInfo, true);
   nsCOMPtr<nsIPrincipal> loadingPrincipal;
   loadInfo->GetLoadingPrincipal(getter_AddRefs(loadingPrincipal));
   NS_ENSURE_TRUE(loadingPrincipal, true);
 
   // Prepare the channel result principal.
-  nsCOMPtr<nsIPrincipal> resultPrincipal;
-  nsContentUtils::GetSecurityManager()->
-    GetChannelResultPrincipal(aChannel, getter_AddRefs(resultPrincipal));
+  nsCOMPtr<nsIPrincipal> channelPrincipal =
+    GetChannelPrincipalWithSingedPkg(aChannel, aSignedPkg);
 
   // Log the debug info which is used to decide the need of proces switch.
   nsCOMPtr<nsIURI> uri;
   aChannel->GetURI(getter_AddRefs(uri));
-  LogChannelRelevantInfo(uri, loadingPrincipal, resultPrincipal,
+  LogChannelRelevantInfo(uri, loadingPrincipal, channelPrincipal,
                          loadInfo->InternalContentPolicyType());
 
   // Check if the signed package is loaded from the same origin.
   bool sameOrigin = false;
-  loadingPrincipal->Equals(resultPrincipal, &sameOrigin);
+  loadingPrincipal->Equals(channelPrincipal, &sameOrigin);
   if (sameOrigin) {
     LOG("Loading singed package from the same origin. Don't switch process.\n");
     return false;
   }
 
   // If this is not a top level document, there's no need to switch process.
   if (nsIContentPolicy::TYPE_DOCUMENT != loadInfo->InternalContentPolicyType()) {
     LOG("Subresource of a document. No need to switch process.\n");
@@ -511,17 +533,17 @@ TabParent::ShouldSwitchProcess(nsIChanne
 
   return true;
 }
 
 void
 TabParent::OnStartSignedPackageRequest(nsIChannel* aChannel,
                                        const nsACString& aPackageId)
 {
-  if (!ShouldSwitchProcess(aChannel)) {
+  if (!ShouldSwitchProcess(aChannel, aPackageId)) {
     return;
   }
 
   nsCOMPtr<nsIURI> uri;
   aChannel->GetURI(getter_AddRefs(uri));
 
   aChannel->Cancel(NS_BINDING_FAILED);
 
@@ -2342,17 +2364,17 @@ TabParent::RecvStartPluginIME(const Widg
                               const int32_t& aPanelX, const int32_t& aPanelY,
                               nsString* aCommitted)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
   widget->StartPluginIME(aKeyboardEvent,
-                         (int32_t&)aPanelX, 
+                         (int32_t&)aPanelX,
                          (int32_t&)aPanelY,
                          *aCommitted);
   return true;
 }
 
 bool
 TabParent::RecvSetPluginFocused(const bool& aFocused)
 {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -490,17 +490,17 @@ protected:
     virtual bool RecvAudioChannelActivityNotification(const uint32_t& aAudioChannel,
                                                       const bool& aActive) override;
 
     bool InitBrowserConfiguration(const nsCString& aURI,
                                   BrowserConfiguration& aConfiguration);
 
     // Decide whether we have to use a new process to reload the URI associated
     // with the given channel.
-    bool ShouldSwitchProcess(nsIChannel* aChannel);
+    bool ShouldSwitchProcess(nsIChannel* aChannel, const nsACString& aSignedPkg);
 
     ContentCacheInParent mContentCache;
 
     nsIntRect mRect;
     ScreenIntSize mDimensions;
     ScreenOrientationInternal mOrientation;
     float mDPI;
     CSSToLayoutDeviceScale mDefaultScale;
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -7,25 +7,24 @@
 #include "DecoderTraits.h"
 #include "MediaDecoder.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsMimeTypes.h"
 #include "mozilla/Preferences.h"
 
 #include "OggDecoder.h"
 #include "OggReader.h"
-#ifdef MOZ_WAVE
+
 #include "WaveDecoder.h"
 #include "WaveReader.h"
-#endif
-#ifdef MOZ_WEBM
+
 #include "WebMDecoder.h"
 #include "WebMReader.h"
 #include "WebMDemuxer.h"
-#endif
+
 #ifdef MOZ_RAW
 #include "RawDecoder.h"
 #include "RawReader.h"
 #endif
 #ifdef MOZ_GSTREAMER
 #include "GStreamerDecoder.h"
 #include "GStreamerReader.h"
 #endif
@@ -123,17 +122,16 @@ IsOggType(const nsACString& aType)
 {
   if (!MediaDecoder::IsOggEnabled()) {
     return false;
   }
 
   return CodecListContains(gOggTypes, aType);
 }
 
-#ifdef MOZ_WAVE
 // See http://www.rfc-editor.org/rfc/rfc2361.txt for the definitions
 // of WAVE media types and codec types. However, the audio/vnd.wave
 // MIME type described there is not used.
 static const char* const gWaveTypes[5] = {
   "audio/x-wav",
   "audio/wav",
   "audio/wave",
   "audio/x-pn-wav",
@@ -149,43 +147,34 @@ static bool
 IsWaveType(const nsACString& aType)
 {
   if (!MediaDecoder::IsWaveEnabled()) {
     return false;
   }
 
   return CodecListContains(gWaveTypes, aType);
 }
-#endif
 
-#ifdef MOZ_WEBM
 static bool
 IsWebMSupportedType(const nsACString& aType,
                     const nsAString& aCodecs = EmptyString())
 {
   return WebMDecoder::CanHandleMediaType(aType, aCodecs);
 }
-#endif
 
 /* static */ bool
 DecoderTraits::IsWebMTypeAndEnabled(const nsACString& aType)
 {
-#ifdef MOZ_WEBM
   return IsWebMSupportedType(aType);
-#endif
-  return false;
 }
 
 /* static */ bool
 DecoderTraits::IsWebMAudioType(const nsACString& aType)
 {
-#ifdef MOZ_WEBM
   return aType.EqualsASCII("audio/webm");
-#endif
-  return false;
 }
 
 #ifdef MOZ_GSTREAMER
 static bool
 IsGStreamerSupportedType(const nsACString& aMimeType)
 {
   if (DecoderTraits::IsWebMTypeAndEnabled(aMimeType))
     return false;
@@ -362,26 +351,24 @@ IsAACSupportedType(const nsACString& aTy
                    const nsAString& aCodecs = EmptyString())
 {
   return ADTSDecoder::CanHandleMediaType(aType, aCodecs);
 }
 
 /* static */
 bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType)
 {
-#ifdef MOZ_WAVE
   if (IsWaveType(nsDependentCString(aMIMEType))) {
     // We should not return true for Wave types, since there are some
     // Wave codecs actually in use in the wild that we don't support, and
     // we should allow those to be handled by plugins or helper apps.
     // Furthermore people can play Wave files on most platforms by other
     // means.
     return false;
   }
-#endif
   return CanHandleMediaType(aMIMEType, false, EmptyString()) != CANPLAY_NO;
 }
 
 /* static */
 CanPlayStatus
 DecoderTraits::CanHandleCodecsType(const char* aMIMEType,
                                    const nsAString& aRequestedCodecs)
 {
@@ -389,21 +376,19 @@ DecoderTraits::CanHandleCodecsType(const
 #ifdef MOZ_RAW
   if (IsRawType(nsDependentCString(aMIMEType))) {
     codecList = gRawCodecs;
   }
 #endif
   if (IsOggType(nsDependentCString(aMIMEType))) {
     codecList = MediaDecoder::IsOpusEnabled() ? gOggCodecsWithOpus : gOggCodecs;
   }
-#ifdef MOZ_WAVE
   if (IsWaveType(nsDependentCString(aMIMEType))) {
     codecList = gWaveCodecs;
   }
-#endif
 #if !defined(MOZ_OMX_WEBM_DECODER)
   if (IsWebMTypeAndEnabled(nsDependentCString(aMIMEType))) {
     if (IsWebMSupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
       return CANPLAY_YES;
     } else {
       // We can only reach this position if a particular codec was requested,
       // webm is supported and working: the codec must be invalid.
       return CANPLAY_NO;
@@ -491,21 +476,19 @@ DecoderTraits::CanHandleMediaType(const 
 #ifdef MOZ_RAW
   if (IsRawType(nsDependentCString(aMIMEType))) {
     return CANPLAY_MAYBE;
   }
 #endif
   if (IsOggType(nsDependentCString(aMIMEType))) {
     return CANPLAY_MAYBE;
   }
-#ifdef MOZ_WAVE
   if (IsWaveType(nsDependentCString(aMIMEType))) {
     return CANPLAY_MAYBE;
   }
-#endif
   if (IsMP4TypeAndEnabled(nsDependentCString(aMIMEType))) {
     return CANPLAY_MAYBE;
   }
 #if !defined(MOZ_OMX_WEBM_DECODER)
   if (IsWebMTypeAndEnabled(nsDependentCString(aMIMEType))) {
     return CANPLAY_MAYBE;
   }
 #endif
@@ -578,22 +561,20 @@ InstantiateDecoder(const nsACString& aTy
     decoder = new RawDecoder(aOwner);
     return decoder.forget();
   }
 #endif
   if (IsOggType(aType)) {
     decoder = new OggDecoder(aOwner);
     return decoder.forget();
   }
-#ifdef MOZ_WAVE
   if (IsWaveType(aType)) {
     decoder = new WaveDecoder(aOwner);
     return decoder.forget();
   }
-#endif
 #ifdef MOZ_OMX_DECODER
   if (IsOmxSupportedType(aType)) {
     // we are discouraging Web and App developers from using those formats in
     // gB2GOnlyTypes, thus we only allow them to be played on WebApps.
     if (IsB2GSupportOnlyType(aType)) {
       dom::HTMLMediaElement* element = aOwner->GetMediaElement();
       if (!element) {
         return nullptr;
@@ -618,22 +599,22 @@ InstantiateDecoder(const nsACString& aTy
 #endif
 #ifdef MOZ_ANDROID_OMX
   if (MediaDecoder::IsAndroidMediaEnabled() &&
       EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
     decoder = new AndroidMediaDecoder(aOwner, aType);
     return decoder.forget();
   }
 #endif
-#ifdef MOZ_WEBM
+
   if (IsWebMSupportedType(aType)) {
     decoder = new WebMDecoder(aOwner);
     return decoder.forget();
   }
-#endif
+
 #ifdef MOZ_DIRECTSHOW
   // Note: DirectShow should come before WMF, so that we prefer DirectShow's
   // MP3 support over WMF's.
   if (IsDirectShowSupportedType(aType)) {
     decoder = new DirectShowDecoder(aOwner);
     return decoder.forget();
   }
 #endif
@@ -677,39 +658,37 @@ MediaDecoderReader* DecoderTraits::Creat
 #ifdef MOZ_RAW
   if (IsRawType(aType)) {
     decoderReader = new RawReader(aDecoder);
   } else
 #endif
   if (IsOggType(aType)) {
     decoderReader = new OggReader(aDecoder);
   } else
-#ifdef MOZ_WAVE
   if (IsWaveType(aType)) {
     decoderReader = new WaveReader(aDecoder);
   } else
-#endif
 #ifdef MOZ_OMX_DECODER
   if (IsOmxSupportedType(aType)) {
     decoderReader = new MediaOmxReader(aDecoder);
   } else
 #endif
 #ifdef MOZ_ANDROID_OMX
   if (MediaDecoder::IsAndroidMediaEnabled() &&
       EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
     decoderReader = new AndroidMediaReader(aDecoder, aType);
   } else
 #endif
-#ifdef MOZ_WEBM
+
   if (IsWebMSupportedType(aType)) {
     decoderReader = Preferences::GetBool("media.format-reader.webm", true) ?
       static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new WebMDemuxer(aDecoder->GetResource()))) :
       new WebMReader(aDecoder);
   } else
-#endif
+
 #ifdef MOZ_DIRECTSHOW
   if (IsDirectShowSupportedType(aType)) {
     decoderReader = new DirectShowReader(aDecoder);
   } else
 #endif
   if (false) {} // dummy if to take care of the dangling else
 
   return decoderReader;
@@ -730,19 +709,17 @@ bool DecoderTraits::IsSupportedInVideoDo
     IsOggType(aType) ||
 #ifdef MOZ_OMX_DECODER
     // We support the formats in gB2GOnlyTypes only inside WebApps on firefoxOS
     // but not in general web content. Ensure we dont create a VideoDocument
     // when accessing those format URLs directly.
     (IsOmxSupportedType(aType) &&
      !IsB2GSupportOnlyType(aType)) ||
 #endif
-#ifdef MOZ_WEBM
     IsWebMSupportedType(aType) ||
-#endif
 #ifdef MOZ_GSTREAMER
     IsGStreamerSupportedType(aType) ||
 #endif
 #ifdef MOZ_ANDROID_OMX
     (MediaDecoder::IsAndroidMediaEnabled() && IsAndroidMediaType(aType)) ||
 #endif
 #ifdef MOZ_FMP4
     IsMP4SupportedType(aType) ||
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1636,31 +1636,27 @@ MediaDecoder::IsOpusEnabled()
 }
 
 bool
 MediaDecoder::IsOggEnabled()
 {
   return Preferences::GetBool("media.ogg.enabled");
 }
 
-#ifdef MOZ_WAVE
 bool
 MediaDecoder::IsWaveEnabled()
 {
   return Preferences::GetBool("media.wave.enabled");
 }
-#endif
 
-#ifdef MOZ_WEBM
 bool
 MediaDecoder::IsWebMEnabled()
 {
   return Preferences::GetBool("media.webm.enabled");
 }
-#endif
 
 #ifdef NECKO_PROTOCOL_rtsp
 bool
 MediaDecoder::IsRtspEnabled()
 {
   //Currently the Rtsp decoded by omx.
   return (Preferences::GetBool("media.rtsp.enabled", false) && IsOmxEnabled());
 }
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -657,24 +657,19 @@ private:
   void EnsureTelemetryReported();
 
 #ifdef MOZ_RAW
   static bool IsRawEnabled();
 #endif
 
   static bool IsOggEnabled();
   static bool IsOpusEnabled();
+  static bool IsWaveEnabled();
+  static bool IsWebMEnabled();
 
-#ifdef MOZ_WAVE
-  static bool IsWaveEnabled();
-#endif
-
-#ifdef MOZ_WEBM
-  static bool IsWebMEnabled();
-#endif
 #ifdef NECKO_PROTOCOL_rtsp
   static bool IsRtspEnabled();
 #endif
 
 #ifdef MOZ_GSTREAMER
   static bool IsGStreamerEnabled();
 #endif
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -219,16 +219,17 @@ MediaDecoderStateMachine::MediaDecoderSt
   mPlaybackRate(1.0),
   mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
   mAmpleAudioThresholdUsecs(detail::AMPLE_AUDIO_USECS),
   mQuickBufferingLowDataThresholdUsecs(detail::QUICK_BUFFERING_LOW_DATA_USECS),
   mIsAudioPrerolling(false),
   mIsVideoPrerolling(false),
   mAudioCaptured(false, "MediaDecoderStateMachine::mAudioCaptured"),
   mAudioCompleted(false, "MediaDecoderStateMachine::mAudioCompleted"),
+  mVideoCompleted(false, "MediaDecoderStateMachine::mVideoCompleted"),
   mNotifyMetadataBeforeFirstFrame(false),
   mDispatchedEventToDecode(false),
   mQuickBuffering(false),
   mMinimizePreroll(false),
   mDecodeThreadWaiting(false),
   mDropAudioUntilNextDiscontinuity(false),
   mDropVideoUntilNextDiscontinuity(false),
   mDecodeToSeekTarget(false),
@@ -350,16 +351,17 @@ MediaDecoderStateMachine::Initialization
   mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable());
   mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition());
   mMediaSeekable.Connect(aDecoder->CanonicalMediaSeekable());
 
   // Initialize watchers.
   mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated);
   mWatchManager.Watch(mState, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mAudioCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
+  mWatchManager.Watch(mVideoCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
   mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged);
   mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
   mWatchManager.Watch(mEstimatedDuration, &MediaDecoderStateMachine::RecomputeDuration);
   mWatchManager.Watch(mExplicitDuration, &MediaDecoderStateMachine::RecomputeDuration);
   mWatchManager.Watch(mObservedDuration, &MediaDecoderStateMachine::RecomputeDuration);
   mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
   mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::LogicallySeekingChanged);
@@ -2347,20 +2349,18 @@ nsresult MediaDecoderStateMachine::RunSt
 
     case DECODER_STATE_COMPLETED: {
       if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying()) {
         StopPlayback();
       }
       // Play the remaining media. We want to run AdvanceFrame() at least
       // once to ensure the current playback position is advanced to the
       // end of the media, and so that we update the readyState.
-      if (VideoQueue().GetSize() > 1 ||
-          (HasAudio() && !mAudioCompleted) ||
-          (mAudioCaptured && !mStreamSink->IsFinished()))
-      {
+      if ((HasVideo() && !mVideoCompleted) ||
+          (HasAudio() && !mAudioCompleted)) {
         // Start playback if necessary to play the remaining media.
         MaybeStartPlayback();
         UpdatePlaybackPositionPeriodically();
         NS_ASSERTION(!IsPlaying() ||
                      mLogicallySeeking ||
                      IsStateMachineScheduled(),
                      "Must have timer scheduled");
         return NS_OK;
@@ -2420,16 +2420,17 @@ MediaDecoderStateMachine::Reset()
   // Stop the audio thread. Otherwise, MediaSink might be accessing AudioQueue
   // outside of the decoder monitor while we are clearing the queue and causes
   // crash for no samples to be popped.
   StopMediaSink();
 
   mDecodedVideoEndTime = -1;
   mDecodedAudioEndTime = -1;
   mAudioCompleted = false;
+  mVideoCompleted = false;
   AudioQueue().Reset();
   VideoQueue().Reset();
   mFirstVideoFrameAfterSeek = nullptr;
   mDropAudioUntilNextDiscontinuity = true;
   mDropVideoUntilNextDiscontinuity = true;
   mDecodeToSeekTarget = false;
 
   mMetadataRequest.DisconnectIfExists();
@@ -2831,55 +2832,59 @@ MediaDecoderStateMachine::VideoEndTime()
   }
   return -1;
 }
 
 void
 MediaDecoderStateMachine::OnMediaSinkVideoComplete()
 {
   MOZ_ASSERT(OnTaskQueue());
+  MOZ_ASSERT(mInfo.HasVideo());
   VERBOSE_LOG("[%s]", __func__);
 
   mMediaSinkVideoPromise.Complete();
+  mVideoCompleted = true;
   ScheduleStateMachine();
 }
 
 void
 MediaDecoderStateMachine::OnMediaSinkVideoError()
 {
   MOZ_ASSERT(OnTaskQueue());
+  MOZ_ASSERT(mInfo.HasVideo());
   VERBOSE_LOG("[%s]", __func__);
 
   mMediaSinkVideoPromise.Complete();
+  mVideoCompleted = true;
   if (HasAudio()) {
     return;
   }
   DecodeError();
 }
 
 void MediaDecoderStateMachine::OnMediaSinkAudioComplete()
 {
   MOZ_ASSERT(OnTaskQueue());
+  MOZ_ASSERT(mInfo.HasAudio());
   VERBOSE_LOG("[%s]", __func__);
 
   mMediaSinkAudioPromise.Complete();
-  // Set true only when we have audio.
-  mAudioCompleted = mInfo.HasAudio();
+  mAudioCompleted = true;
   // To notify PlaybackEnded as soon as possible.
   ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::OnMediaSinkAudioError()
 {
   MOZ_ASSERT(OnTaskQueue());
+  MOZ_ASSERT(mInfo.HasAudio());
   VERBOSE_LOG("[%s]", __func__);
 
   mMediaSinkAudioPromise.Complete();
-  // Set true only when we have audio.
-  mAudioCompleted = mInfo.HasAudio();
+  mAudioCompleted = true;
 
   // Make the best effort to continue playback when there is video.
   if (HasVideo()) {
     return;
   }
 
   // Otherwise notify media decoder/element about this error for it makes
   // no sense to play an audio-only file without sound output.
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -1096,16 +1096,19 @@ private:
   // when either all the audio frames have completed playing, or we've moved
   // into shutdown state, and the threads are to be
   // destroyed. Written by the audio playback thread and read and written by
   // the state machine thread. Synchronised via decoder monitor.
   // When data is being sent to a MediaStream, this is true when all data has
   // been written to the MediaStream.
   Watchable<bool> mAudioCompleted;
 
+  // True if all video frames are already rendered.
+  Watchable<bool> mVideoCompleted;
+
   // Set if MDSM receives dormant request during reading metadata.
   Maybe<bool> mPendingDormant;
 
   // Flag whether we notify metadata before decoding the first frame or after.
   //
   // Note that the odd semantics here are designed to replicate the current
   // behavior where we notify the decoder each time we come out of dormant, but
   // send suppressed event visibility for those cases. This code can probably be
--- a/dom/media/mediasink/DecodedStream.cpp
+++ b/dom/media/mediasink/DecodedStream.cpp
@@ -21,17 +21,16 @@ namespace mozilla {
 class DecodedStreamGraphListener : public MediaStreamListener {
   typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
 public:
   DecodedStreamGraphListener(MediaStream* aStream,
                              MozPromiseHolder<GenericPromise>&& aPromise)
     : mMutex("DecodedStreamGraphListener::mMutex")
     , mStream(aStream)
     , mLastOutputTime(aStream->StreamTimeToMicroseconds(aStream->GetCurrentTime()))
-    , mStreamFinishedOnMainThread(false)
   {
     mFinishPromise = Move(aPromise);
   }
 
   void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) override
   {
     MutexAutoLock lock(mMutex);
     if (mStream) {
@@ -47,46 +46,37 @@ public:
         NS_NewRunnableMethod(this, &DecodedStreamGraphListener::DoNotifyFinished);
       aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
     }
   }
 
   void DoNotifyFinished()
   {
     mFinishPromise.ResolveIfExists(true, __func__);
-    MutexAutoLock lock(mMutex);
-    mStreamFinishedOnMainThread = true;
   }
 
   int64_t GetLastOutputTime()
   {
     MutexAutoLock lock(mMutex);
     return mLastOutputTime;
   }
 
   void Forget()
   {
     MOZ_ASSERT(NS_IsMainThread());
     mFinishPromise.ResolveIfExists(true, __func__);
     MutexAutoLock lock(mMutex);
     mStream = nullptr;
   }
 
-  bool IsFinishedOnMainThread()
-  {
-    MutexAutoLock lock(mMutex);
-    return mStreamFinishedOnMainThread;
-  }
-
 private:
   Mutex mMutex;
   // Members below are protected by mMutex.
   RefPtr<MediaStream> mStream;
   int64_t mLastOutputTime; // microseconds
-  bool mStreamFinishedOnMainThread;
   // Main thread only.
   MozPromiseHolder<GenericPromise> mFinishPromise;
 };
 
 static void
 UpdateStreamSuspended(MediaStream* aStream, bool aBlocking)
 {
   if (NS_IsMainThread()) {
@@ -114,17 +104,16 @@ UpdateStreamSuspended(MediaStream* aStre
  * replaying after the input as ended. In the latter case, the new source is
  * not connected to streams created by captureStreamUntilEnded.
  */
 class DecodedStreamData {
 public:
   DecodedStreamData(SourceMediaStream* aStream,
                     MozPromiseHolder<GenericPromise>&& aPromise);
   ~DecodedStreamData();
-  bool IsFinished() const;
   int64_t GetPosition() const;
   void SetPlaying(bool aPlaying);
 
   /* The following group of fields are protected by the decoder's monitor
    * and can be read or written on any thread.
    */
   // Count of audio frames written to the stream
   int64_t mAudioFramesWritten;
@@ -175,22 +164,16 @@ DecodedStreamData::DecodedStreamData(Sou
 }
 
 DecodedStreamData::~DecodedStreamData()
 {
   mListener->Forget();
   mStream->Destroy();
 }
 
-bool
-DecodedStreamData::IsFinished() const
-{
-  return mListener->IsFinishedOnMainThread();
-}
-
 int64_t
 DecodedStreamData::GetPosition() const
 {
   return mListener->GetLastOutputTime();
 }
 
 void
 DecodedStreamData::SetPlaying(bool aPlaying)
@@ -341,23 +324,24 @@ DecodedStream::SetPlaybackParams(const P
 }
 
 RefPtr<GenericPromise>
 DecodedStream::OnEnded(TrackType aType)
 {
   AssertOwnerThread();
   MOZ_ASSERT(mStartTime.isSome());
 
-  if (aType == TrackInfo::kAudioTrack) {
+  if (aType == TrackInfo::kAudioTrack && mInfo.HasAudio()) {
     // TODO: we should return a promise which is resolved when the audio track
     // is finished. For now this promise is resolved when the whole stream is
     // finished.
     return mFinishPromise;
+  } else if (aType == TrackInfo::kVideoTrack && mInfo.HasVideo()) {
+    return mFinishPromise;
   }
-  // TODO: handle video track.
   return nullptr;
 }
 
 void
 DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo)
 {
   AssertOwnerThread();
   MOZ_ASSERT(mStartTime.isNothing(), "playback already started.");
@@ -878,23 +862,16 @@ DecodedStream::GetPosition(TimeStamp* aT
   // guaranteed to be something.
   MOZ_ASSERT(mStartTime.isSome());
   if (aTimeStamp) {
     *aTimeStamp = TimeStamp::Now();
   }
   return mStartTime.ref() + (mData ? mData->GetPosition() : 0);
 }
 
-bool
-DecodedStream::IsFinished() const
-{
-  AssertOwnerThread();
-  return mData && mData->IsFinished();
-}
-
 void
 DecodedStream::ConnectListener()
 {
   AssertOwnerThread();
 
   mAudioPushListener = mAudioQueue.PushEvent().Connect(
     mOwnerThread, this, &DecodedStream::SendData);
   mAudioFinishListener = mAudioQueue.FinishEvent().Connect(
--- a/dom/media/mediasink/DecodedStream.h
+++ b/dom/media/mediasink/DecodedStream.h
@@ -118,17 +118,16 @@ public:
   void Stop() override;
   bool IsStarted() const override;
   bool IsPlaying() const override;
 
   // TODO: fix these functions that don't fit into the interface of MediaSink.
   void AddOutput(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
   void RemoveOutput(MediaStream* aStream);
   void SetSameOrigin(bool aSameOrigin);
-  bool IsFinished() const;
   bool HasConsumers() const;
 
 protected:
   virtual ~DecodedStream();
 
 private:
   void CreateData(MozPromiseHolder<GenericPromise>&& aPromise);
   void DestroyData(UniquePtr<DecodedStreamData> aData);
--- a/dom/media/mediasink/VideoSink.cpp
+++ b/dom/media/mediasink/VideoSink.cpp
@@ -161,34 +161,56 @@ VideoSink::Start(int64_t aStartTime, con
   VSINK_LOG("[%s]", __func__);
 
   mAudioSink->Start(aStartTime, aInfo);
 
   mHasVideo = aInfo.HasVideo();
 
   if (mHasVideo) {
     mEndPromise = mEndPromiseHolder.Ensure(__func__);
+
+    // If the underlying MediaSink has an end promise for the video track (which
+    // happens when mAudioSink refers to a DecodedStream), we must wait for it
+    // to complete before resolving our own end promise. Otherwise, MDSM might
+    // stop playback before DecodedStream plays to the end and cause
+    // test_streams_element_capture.html to time out.
+    RefPtr<GenericPromise> p = mAudioSink->OnEnded(TrackInfo::kVideoTrack);
+    if (p) {
+      RefPtr<VideoSink> self = this;
+      mVideoSinkEndRequest.Begin(p->Then(mOwnerThread, __func__,
+        [self] () {
+          self->mVideoSinkEndRequest.Complete();
+          self->TryUpdateRenderedVideoFrames();
+        }, [self] () {
+          self->mVideoSinkEndRequest.Complete();
+          self->TryUpdateRenderedVideoFrames();
+        }));
+    }
+
     ConnectListener();
-    TryUpdateRenderedVideoFrames();
+    // Run the render loop at least once so we can resolve the end promise
+    // when video duration is 0.
+    UpdateRenderedVideoFrames();
   }
 }
 
 void
 VideoSink::Stop()
 {
   AssertOwnerThread();
   MOZ_ASSERT(mAudioSink->IsStarted(), "playback not started.");
   VSINK_LOG("[%s]", __func__);
 
   mAudioSink->Stop();
 
   mUpdateScheduler.Reset();
   if (mHasVideo) {
     DisconnectListener();
-    mEndPromiseHolder.Resolve(true, __func__);
+    mVideoSinkEndRequest.DisconnectIfExists();
+    mEndPromiseHolder.ResolveIfExists(true, __func__);
     mEndPromise = nullptr;
   }
   mVideoFrameEndTime = -1;
 }
 
 bool
 VideoSink::IsStarted() const
 {
@@ -211,31 +233,43 @@ VideoSink::Shutdown()
   AssertOwnerThread();
   MOZ_ASSERT(!mAudioSink->IsStarted(), "must be called after playback stops.");
   VSINK_LOG("[%s]", __func__);
 
   mAudioSink->Shutdown();
 }
 
 void
-VideoSink::OnVideoQueueEvent(RefPtr<MediaData>&& aSample)
+VideoSink::OnVideoQueuePushed(RefPtr<MediaData>&& aSample)
 {
   AssertOwnerThread();
   // Listen to push event, VideoSink should try rendering ASAP if first frame
   // arrives but update scheduler is not triggered yet.
   VideoData* v = aSample->As<VideoData>();
   if (!v->mSentToCompositor) {
     // Since we push rendered frames back to the queue, we will receive
     // push events for them. We only need to trigger render loop
     // when this frame is not rendered yet.
     TryUpdateRenderedVideoFrames();
   }
 }
 
 void
+VideoSink::OnVideoQueueFinished()
+{
+  AssertOwnerThread();
+  // Run render loop if the end promise is not resolved yet.
+  if (!mUpdateScheduler.IsScheduled() &&
+      mAudioSink->IsPlaying() &&
+      !mEndPromiseHolder.IsEmpty()) {
+    UpdateRenderedVideoFrames();
+  }
+}
+
+void
 VideoSink::Redraw()
 {
   AssertOwnerThread();
   RenderVideoFrames(1);
 }
 
 void
 VideoSink::TryUpdateRenderedVideoFrames()
@@ -255,24 +289,27 @@ VideoSink::UpdateRenderedVideoFramesByTi
   UpdateRenderedVideoFrames();
 }
 
 void
 VideoSink::ConnectListener()
 {
   AssertOwnerThread();
   mPushListener = VideoQueue().PushEvent().Connect(
-    mOwnerThread, this, &VideoSink::OnVideoQueueEvent);
+    mOwnerThread, this, &VideoSink::OnVideoQueuePushed);
+  mFinishListener = VideoQueue().FinishEvent().Connect(
+    mOwnerThread, this, &VideoSink::OnVideoQueueFinished);
 }
 
 void
 VideoSink::DisconnectListener()
 {
   AssertOwnerThread();
   mPushListener.Disconnect();
+  mFinishListener.Disconnect();
 }
 
 void
 VideoSink::RenderVideoFrames(int32_t aMaxFrames,
                              int64_t aClockTime,
                              const TimeStamp& aClockTimeStamp)
 {
   AssertOwnerThread();
@@ -366,16 +403,23 @@ VideoSink::UpdateRenderedVideoFrames()
     }
     VideoQueue().PushFront(currentFrame);
     if (framesRemoved > 0) {
       mVideoFrameEndTime = currentFrame->GetEndTime();
       mFrameStats.NotifyPresentedFrame();
     }
   }
 
+  // All frames are rendered, Let's resolve the promise.
+  if (VideoQueue().IsFinished() &&
+      VideoQueue().GetSize() <= 1 &&
+      !mVideoSinkEndRequest.Exists()) {
+    mEndPromiseHolder.ResolveIfExists(true, __func__);
+  }
+
   RenderVideoFrames(mVideoQueueSendToCompositorSize, clockTime, nowTime);
 
   // No next fame to render. There is no need to schedule next render
   // loop. We will run render loops again upon incoming frames.
   if (remainingTime < 0) {
     return;
   }
 
--- a/dom/media/mediasink/VideoSink.h
+++ b/dom/media/mediasink/VideoSink.h
@@ -67,17 +67,18 @@ public:
   bool IsPlaying() const override;
 
   void Shutdown() override;
 
 private:
   virtual ~VideoSink();
 
   // VideoQueue listener related.
-  void OnVideoQueueEvent(RefPtr<MediaData>&& aSample);
+  void OnVideoQueuePushed(RefPtr<MediaData>&& aSample);
+  void OnVideoQueueFinished();
   void ConnectListener();
   void DisconnectListener();
 
   // Sets VideoQueue images into the VideoFrameContainer. Called on the shared
   // state machine thread. The first aMaxFrames (at most) are set.
   // aClockTime and aClockTimeStamp are used as the baseline for deriving
   // timestamps for the frames; when omitted, aMaxFrames must be 1 and
   // a null timestamp is passed to the VideoFrameContainer.
@@ -124,16 +125,17 @@ private:
   // The presentation end time of the last video frame which has been displayed
   // in microseconds.
   int64_t mVideoFrameEndTime;
 
   uint32_t mOldDroppedCount;
 
   // Event listeners for VideoQueue
   MediaEventListener mPushListener;
+  MediaEventListener mFinishListener;
 
   // True if this sink is going to handle video track.
   bool mHasVideo;
 
   // Used to trigger another update of rendered frames in next round.
   DelayedScheduler mUpdateScheduler;
 
   // Max frame number sent to compositor at a time.
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -7,20 +7,17 @@
 #include "TrackBuffersManager.h"
 #include "ContainerParser.h"
 #include "MediaSourceDemuxer.h"
 #include "MediaSourceUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StateMirroring.h"
 #include "SourceBufferResource.h"
 #include "SourceBuffer.h"
-
-#ifdef MOZ_WEBM
 #include "WebMDemuxer.h"
-#endif
 
 #ifdef MOZ_FMP4
 #include "MP4Demuxer.h"
 #endif
 
 #include <limits>
 
 extern mozilla::LogModule* GetMediaSourceLog();
@@ -793,22 +790,20 @@ TrackBuffersManager::ShutdownDemuxers()
   mLastParsedEndTime.reset();
 }
 
 void
 TrackBuffersManager::CreateDemuxerforMIMEType()
 {
   ShutdownDemuxers();
 
-#ifdef MOZ_WEBM
   if (mType.LowerCaseEqualsLiteral("video/webm") || mType.LowerCaseEqualsLiteral("audio/webm")) {
     mInputDemuxer = new WebMDemuxer(mCurrentInputBuffer, true /* IsMediaSource*/ );
     return;
   }
-#endif
 
 #ifdef MOZ_FMP4
   if (mType.LowerCaseEqualsLiteral("video/mp4") || mType.LowerCaseEqualsLiteral("audio/mp4")) {
     mInputDemuxer = new MP4Demuxer(mCurrentInputBuffer);
     return;
   }
 #endif
   NS_WARNING("Not supported (yet)");
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -25,32 +25,28 @@ DIRS += [
     'gmp-plugin',
     'gmp-plugin-openh264',
     'imagecapture',
     'mediasink',
     'mediasource',
     'ogg',
     'platforms',
     'systemservices',
+    'wave',
     'webaudio',
+    'webm',
     'webrtc',
     'webspeech',
     'webvtt',
     'standalone',
 ]
 
 if CONFIG['MOZ_RAW']:
     DIRS += ['raw']
 
-if CONFIG['MOZ_WAVE']:
-    DIRS += ['wave']
-
-if CONFIG['MOZ_WEBM']:
-    DIRS += ['webm']
-
 if CONFIG['MOZ_GSTREAMER']:
     DIRS += ['gstreamer']
 
 if CONFIG['MOZ_DIRECTSHOW']:
     DIRS += ['directshow']
 
 if CONFIG['MOZ_ANDROID_OMX']:
     DIRS += ['android']
--- a/dom/media/platforms/omx/OmxDataDecoder.cpp
+++ b/dom/media/platforms/omx/OmxDataDecoder.cpp
@@ -63,17 +63,17 @@ void GetPortIndex(nsTArray<uint32_t>& aP
 OmxDataDecoder::OmxDataDecoder(const TrackInfo& aTrackInfo,
                                MediaDataDecoderCallback* aCallback)
   : mMonitor("OmxDataDecoder")
   , mOmxTaskQueue(CreateMediaDecodeTaskQueue())
   , mWatchManager(this, mOmxTaskQueue)
   , mOmxState(OMX_STATETYPE::OMX_StateInvalid, "OmxDataDecoder::mOmxState")
   , mTrackInfo(aTrackInfo.Clone())
   , mFlushing(false)
-  , mShutdown(false)
+  , mShuttingDown(false)
   , mCheckingInputExhausted(false)
   , mPortSettingsChanged(-1, "OmxDataDecoder::mPortSettingsChanged")
   , mAudioCompactor(mAudioQueue)
   , mCallback(aCallback)
 {
   LOG("(%p)", this);
   mOmxLayer = new OmxPromiseLayer(mOmxTaskQueue, this);
 
@@ -81,17 +81,16 @@ OmxDataDecoder::OmxDataDecoder(const Tra
     NS_NewRunnableMethod(this, &OmxDataDecoder::InitializationTask);
   mOmxTaskQueue->Dispatch(r.forget());
 }
 
 OmxDataDecoder::~OmxDataDecoder()
 {
   LOG("(%p)", this);
   mWatchManager.Shutdown();
-  mOmxTaskQueue->AwaitShutdownAndIdle();
 }
 
 void
 OmxDataDecoder::InitializationTask()
 {
   mWatchManager.Watch(mOmxState, &OmxDataDecoder::OmxStateRunner);
   mWatchManager.Watch(mPortSettingsChanged, &OmxDataDecoder::PortSettingsChanged);
 }
@@ -202,22 +201,35 @@ OmxDataDecoder::Drain()
   return NS_OK;
 }
 
 nsresult
 OmxDataDecoder::Shutdown()
 {
   LOG("(%p)", this);
 
-  mShutdown = true;
+  mShuttingDown = true;
 
   nsCOMPtr<nsIRunnable> r =
     NS_NewRunnableMethod(this, &OmxDataDecoder::DoAsyncShutdown);
   mOmxTaskQueue->Dispatch(r.forget());
 
+  {
+    // DoAsyncShutdown() will be running for a while, it could be still running
+    // when reader releasing the decoder and then it causes problem. To avoid it,
+    // Shutdown() must block until DoAsyncShutdown() is completed.
+    MonitorAutoLock lock(mMonitor);
+    while (mShuttingDown) {
+      lock.Wait();
+    }
+  }
+
+  mOmxTaskQueue->BeginShutdown();
+  mOmxTaskQueue->AwaitShutdownAndIdle();
+
   return NS_OK;
 }
 
 void
 OmxDataDecoder::DoAsyncShutdown()
 {
   LOG("(%p)", this);
   MOZ_ASSERT(mOmxTaskQueue->IsCurrentThreadIn());
@@ -268,19 +280,27 @@ OmxDataDecoder::DoAsyncShutdown()
            [self] () {
              self->mOmxLayer->Shutdown();
            })
     ->CompletionPromise()
     ->Then(mOmxTaskQueue, __func__,
            [self] () {
              LOG("DoAsyncShutdown: OMX_StateLoaded, it is safe to shutdown omx");
              self->mOmxLayer->Shutdown();
+
+             MonitorAutoLock lock(self->mMonitor);
+             self->mShuttingDown = false;
+             self->mMonitor.Notify();
            },
            [self] () {
              self->mOmxLayer->Shutdown();
+
+             MonitorAutoLock lock(self->mMonitor);
+             self->mShuttingDown = false;
+             self->mMonitor.Notify();
            });
 }
 
 void
 OmxDataDecoder::CheckIfInputExhausted()
 {
   MOZ_ASSERT(mOmxTaskQueue->IsCurrentThreadIn());
   MOZ_ASSERT(!mCheckingInputExhausted);
@@ -395,22 +415,18 @@ OmxDataDecoder::NotifyError(OMX_ERRORTYP
 }
 
 void
 OmxDataDecoder::FillAndEmptyBuffers()
 {
   MOZ_ASSERT(mOmxTaskQueue->IsCurrentThreadIn());
   MOZ_ASSERT(mOmxState == OMX_StateExecuting);
 
-  // During the port setting changed, it is forbided to do any buffer operations.
-  if (mPortSettingsChanged != -1 || mShutdown) {
-    return;
-  }
-
-  if (mFlushing) {
+  // During the port setting changed, it is forbidden to do any buffer operation.
+  if (mPortSettingsChanged != -1 || mShuttingDown || mFlushing) {
     return;
   }
 
   // Trigger input port.
   while (!!mMediaRawDatas.Length()) {
     // input buffer must be usedi by component if there is data available.
     RefPtr<BufferData> inbuf = FindAvailableBuffer(OMX_DirInput);
     if (!inbuf) {
@@ -837,17 +853,16 @@ OmxDataDecoder::SendEosBuffer()
 
 void
 OmxDataDecoder::DoFlush()
 {
   MOZ_ASSERT(mOmxTaskQueue->IsCurrentThreadIn());
 
   // 1. Call OMX command OMX_CommandFlush in Omx TaskQueue.
   // 2. Remove all elements in mMediaRawDatas when flush is completed.
-  RefPtr<OmxDataDecoder> self = this;
   mOmxLayer->SendCommand(OMX_CommandFlush, OMX_ALL, nullptr)
     ->Then(mOmxTaskQueue, __func__, this,
            &OmxDataDecoder::FlushComplete,
            &OmxDataDecoder::FlushFailure);
 }
 
 void
 OmxDataDecoder::FlushComplete(OMX_COMMANDTYPE aCommandType)
--- a/dom/media/platforms/omx/OmxDataDecoder.h
+++ b/dom/media/platforms/omx/OmxDataDecoder.h
@@ -158,17 +158,17 @@ protected:
   RefPtr<OmxPromiseLayer> mOmxLayer;
 
   UniquePtr<TrackInfo> mTrackInfo;
 
   // It is accessed in both omx and reader TaskQueue.
   Atomic<bool> mFlushing;
 
   // It is accessed in Omx/reader TaskQeueu.
-  Atomic<bool> mShutdown;
+  Atomic<bool> mShuttingDown;
 
   // It is accessed in Omx TaskQeueu.
   bool mCheckingInputExhausted;
 
   // It is accessed in reader TaskQueue.
   MozPromiseHolder<InitPromise> mInitPromise;
 
   // It is written in Omx TaskQeueu. Read in Omx TaskQueue.
--- a/dom/media/platforms/omx/OmxPromiseLayer.cpp
+++ b/dom/media/platforms/omx/OmxPromiseLayer.cpp
@@ -17,19 +17,20 @@ extern mozilla::LogModule* GetPDMLog();
 #ifdef LOG
 #undef LOG
 #endif
 
 #define LOG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, ("OmxPromiseLayer:: " arg, ##__VA_ARGS__))
 
 namespace mozilla {
 
+extern void GetPortIndex(nsTArray<uint32_t>& aPortIndex);
+
 OmxPromiseLayer::OmxPromiseLayer(TaskQueue* aTaskQueue, OmxDataDecoder* aDataDecoder)
   : mTaskQueue(aTaskQueue)
-  , mFlushPortIndex(0)
 {
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 21
   mPlatformLayer = new GonkOmxPlatformLayer(aDataDecoder, this, aTaskQueue);
 #endif
   MOZ_ASSERT(!!mPlatformLayer);
 }
 
 RefPtr<OmxPromiseLayer::OmxCommandPromise>
@@ -191,47 +192,65 @@ OmxPromiseLayer::EmptyFillBufferDone(OMX
     holder->mStatus = BufferData::BufferStatus::OMX_CLIENT;
     holder->mPromise.Resolve(holder, __func__);
   }
 }
 
 RefPtr<OmxPromiseLayer::OmxCommandPromise>
 OmxPromiseLayer::SendCommand(OMX_COMMANDTYPE aCmd, OMX_U32 aParam1, OMX_PTR aCmdData)
 {
-  // No need to issue flush because of buffers are in client already.
-  //
-  // Some components fail to respond flush event when all of buffers are in
-  // client.
   if (aCmd == OMX_CommandFlush) {
-    bool needFlush = false;
-    if ((aParam1 & OMX_DirInput && mInbufferHolders.Length()) ||
-        (aParam1 & OMX_DirOutput && mOutbufferHolders.Length())) {
-      needFlush = true;
+    // It doesn't support another flush commands before previous one is completed.
+    MOZ_RELEASE_ASSERT(!mFlushCommands.Length());
+
+    // Some coomponents don't send event with OMX_ALL, they send flush complete
+    // event with input port and another event for output port.
+    // In prupose of better compatibility, we inteprete the OMX_ALL to OMX_DirInput
+    // and OMX_DirOutput flush separately.
+    OMX_DIRTYPE types[] = {OMX_DIRTYPE::OMX_DirInput, OMX_DIRTYPE::OMX_DirOutput};
+    for(const auto type : types) {
+      if ((aParam1 == type) || (aParam1 == OMX_ALL)) {
+        mFlushCommands.AppendElement(FlushCommand({type, aCmdData}));
+      }
+
+      if (type == OMX_DirInput) {
+        // Clear all buffered raw data.
+        mRawDatas.Clear();
+      }
     }
-    if (!needFlush) {
-      LOG("SendCommand: buffers are in client already, no need to flush");
-      mRawDatas.Clear();
-      return OmxCommandPromise::CreateAndResolve(OMX_CommandFlush, __func__);
+
+    // Don't overlay more than one fush command, some components can't overlay flush commands.
+    // So here we send another flush after receiving the previous flush completed event.
+    if (mFlushCommands.Length()) {
+      OMX_ERRORTYPE err =
+        mPlatformLayer->SendCommand(OMX_CommandFlush,
+                                    mFlushCommands.ElementAt(0).type,
+                                    mFlushCommands.ElementAt(0).cmd);
+      if (err != OMX_ErrorNone) {
+        OmxCommandFailureHolder failure(OMX_ErrorNotReady, OMX_CommandFlush);
+        return OmxCommandPromise::CreateAndReject(failure, __func__);
+      }
+    } else {
+      LOG("SendCommand: OMX_CommandFlush parameter error");
+      OmxCommandFailureHolder failure(OMX_ErrorNotReady, OMX_CommandFlush);
+      return OmxCommandPromise::CreateAndReject(failure, __func__);
     }
-  }
-
-  OMX_ERRORTYPE err = mPlatformLayer->SendCommand(aCmd, aParam1, aCmdData);
-  if (err != OMX_ErrorNone) {
-    OmxCommandFailureHolder failure(OMX_ErrorNotReady, aCmd);
-    return OmxCommandPromise::CreateAndReject(failure, __func__);
+  } else {
+    OMX_ERRORTYPE err = mPlatformLayer->SendCommand(aCmd, aParam1, aCmdData);
+    if (err != OMX_ErrorNone) {
+      OmxCommandFailureHolder failure(OMX_ErrorNotReady, aCmd);
+      return OmxCommandPromise::CreateAndReject(failure, __func__);
+    }
   }
 
   RefPtr<OmxCommandPromise> p;
   if (aCmd == OMX_CommandStateSet) {
     p = mCommandStatePromise.Ensure(__func__);
   } else if (aCmd == OMX_CommandFlush) {
     p = mFlushPromise.Ensure(__func__);
-    mFlushPortIndex = aParam1;
-    // Clear all buffered raw data.
-    mRawDatas.Clear();
   } else if (aCmd == OMX_CommandPortEnable) {
     p = mPortEnablePromise.Ensure(__func__);
   } else if (aCmd == OMX_CommandPortDisable) {
     p = mPortDisablePromise.Ensure(__func__);
   } else {
     LOG("SendCommand: error unsupport command");
     MOZ_ASSERT(0);
   }
@@ -243,31 +262,47 @@ bool
 OmxPromiseLayer::Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1, OMX_U32 aData2)
 {
   OMX_COMMANDTYPE cmd = (OMX_COMMANDTYPE) aData1;
   switch (aEvent) {
     case OMX_EventCmdComplete:
     {
       if (cmd == OMX_CommandStateSet) {
         mCommandStatePromise.Resolve(OMX_CommandStateSet, __func__);
-      } else if (cmd == OMX_CommandFlush && mFlushPortIndex == aData2) {
-        mFlushPromise.Resolve(OMX_CommandFlush, __func__);
+      } else if (cmd == OMX_CommandFlush) {
+        MOZ_RELEASE_ASSERT(mFlushCommands.ElementAt(0).type == aData2);
+        LOG("Event: OMX_CommandFlush completed port type %d", aData2);
+        mFlushCommands.RemoveElementAt(0);
+
+        // Sending next flush command.
+        if (mFlushCommands.Length()) {
+          OMX_ERRORTYPE err =
+            mPlatformLayer->SendCommand(OMX_CommandFlush,
+                                        mFlushCommands.ElementAt(0).type,
+                                        mFlushCommands.ElementAt(0).cmd);
+          if (err != OMX_ErrorNone) {
+            OmxCommandFailureHolder failure(OMX_ErrorNotReady, OMX_CommandFlush);
+            mFlushPromise.Reject(failure, __func__);
+          }
+        } else {
+          mFlushPromise.Resolve(OMX_CommandFlush, __func__);
+        }
       } else if (cmd == OMX_CommandPortDisable) {
         mPortDisablePromise.Resolve(OMX_CommandPortDisable, __func__);
       } else if (cmd == OMX_CommandPortEnable) {
         mPortEnablePromise.Resolve(OMX_CommandPortEnable, __func__);
       }
       break;
     }
     case OMX_EventError:
     {
       if (cmd == OMX_CommandStateSet) {
         OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandStateSet);
         mCommandStatePromise.Reject(failure, __func__);
-      } else if (cmd == OMX_CommandFlush && mFlushPortIndex == aData2) {
+      } else if (cmd == OMX_CommandFlush) {
         OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandFlush);
         mFlushPromise.Reject(failure, __func__);
       } else if (cmd == OMX_CommandPortDisable) {
         OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandPortDisable);
         mPortDisablePromise.Reject(failure, __func__);
       } else if (cmd == OMX_CommandPortEnable) {
         OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandPortEnable);
         mPortEnablePromise.Reject(failure, __func__);
--- a/dom/media/platforms/omx/OmxPromiseLayer.h
+++ b/dom/media/platforms/omx/OmxPromiseLayer.h
@@ -178,31 +178,36 @@ public:
 
   already_AddRefed<BufferData>
   FindAndRemoveBufferHolder(OMX_DIRTYPE aType, BufferData::BufferID aId);
 
   // Return truen if event is handled.
   bool Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1, OMX_U32 aData2);
 
 protected:
+  struct FlushCommand {
+    OMX_DIRTYPE type;
+    OMX_PTR cmd;
+  };
+
   BUFFERLIST* GetBufferHolders(OMX_DIRTYPE aType);
 
   already_AddRefed<MediaRawData> FindAndRemoveRawData(OMX_TICKS aTimecode);
 
   RefPtr<TaskQueue> mTaskQueue;
 
   MozPromiseHolder<OmxCommandPromise> mCommandStatePromise;
 
   MozPromiseHolder<OmxCommandPromise> mPortDisablePromise;
 
   MozPromiseHolder<OmxCommandPromise> mPortEnablePromise;
 
   MozPromiseHolder<OmxCommandPromise> mFlushPromise;
 
-  OMX_U32 mFlushPortIndex;
+  nsTArray<FlushCommand> mFlushCommands;
 
   nsAutoPtr<OmxPlatformLayer> mPlatformLayer;
 
 private:
   // Elements are added to holders when FillBuffer() or FillBuffer(). And
   // removing elelments when the promise is resolved. Buffers in these lists
   // should NOT be used by other component; for example, output it to audio
   // output. These list should be empty when engine is about to shutdown.
--- a/dom/media/platforms/wrappers/FuzzingWrapper.cpp
+++ b/dom/media/platforms/wrappers/FuzzingWrapper.cpp
@@ -45,21 +45,22 @@ DecoderFuzzingWrapper::Input(MediaRawDat
   DFW_LOGV("aData.mTime=%lld", aData->mTime);
   MOZ_ASSERT(mDecoder);
   return mDecoder->Input(aData);
 }
 
 nsresult
 DecoderFuzzingWrapper::Flush()
 {
-  DFW_LOGV("");
+  DFW_LOGV("Calling mDecoder[%p]->Flush()", mDecoder.get());
   MOZ_ASSERT(mDecoder);
   // Flush may output some frames (though unlikely).
   // Flush may block a bit, it's ok if we output some frames in the meantime.
   nsresult result = mDecoder->Flush();
+  DFW_LOGV("mDecoder[%p]->Flush() -> result=%u", mDecoder.get(), uint32_t(result));
   // Clear any delayed output we may have.
   mCallbackWrapper->ClearDelayedOutput();
   return result;
 }
 
 nsresult
 DecoderFuzzingWrapper::Drain()
 {
@@ -249,23 +250,38 @@ DecoderCallbackFuzzingWrapper::OnReaderT
   MOZ_ASSERT(mCallback);
   return mCallback->OnReaderTaskQueue();
 }
 
 void
 DecoderCallbackFuzzingWrapper::ScheduleOutputDelayedFrame()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+  if (mDelayedOutputRequest.Exists()) {
+    // A delayed output is already scheduled, no need for more than one timer.
+    return;
+  }
   RefPtr<DecoderCallbackFuzzingWrapper> self = this;
-  mDelayedOutputTimer->WaitUntil(
-    mPreviousOutput + mFrameOutputMinimumInterval,
-    __func__)
-  ->Then(mTaskQueue, __func__,
-         [self] () -> void { self->OutputDelayedFrame(); },
-         [self] () -> void { self->OutputDelayedFrame(); });
+  mDelayedOutputRequest.Begin(
+    mDelayedOutputTimer->WaitUntil(
+      mPreviousOutput + mFrameOutputMinimumInterval,
+      __func__)
+    ->Then(mTaskQueue, __func__,
+           [self] () -> void {
+             if (self->mDelayedOutputRequest.Exists()) {
+               self->mDelayedOutputRequest.Complete();
+               self->OutputDelayedFrame();
+             }
+           },
+           [self] () -> void {
+             if (self->mDelayedOutputRequest.Exists()) {
+               self->mDelayedOutputRequest.Complete();
+               self->ClearDelayedOutput();
+             }
+           }));
 }
 
 void
 DecoderCallbackFuzzingWrapper::OutputDelayedFrame()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   if (mDelayedOutput.empty()) {
     if (mDraining) {
@@ -295,27 +311,38 @@ DecoderCallbackFuzzingWrapper::OutputDel
     mCallback->DrainComplete();
   }
 }
 
 void
 DecoderCallbackFuzzingWrapper::ClearDelayedOutput()
 {
   if (!mTaskQueue->IsCurrentThreadIn()) {
+    DFW_LOGV("(dispatching self)");
     nsCOMPtr<nsIRunnable> task =
       NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::ClearDelayedOutput);
     mTaskQueue->Dispatch(task.forget());
     return;
   }
+  DFW_LOGV("");
+  // In case a timer hasn't lapsed yet, before destroying the timer and its
+  // attached waitUntil() promise, the 'Then' request must be disconnected.
+  mDelayedOutputRequest.DisconnectIfExists();
   mDelayedOutputTimer = nullptr;
   mDelayedOutput.clear();
 }
 
 void
 DecoderCallbackFuzzingWrapper::Shutdown()
 {
-  DFW_LOGV("Shutting down mTaskQueue");
+  CFW_LOGV("Clear delayed output (if any) before shutting down mTaskQueue");
+  ClearDelayedOutput();
+  // Await idle here, so that 'ClearDelayedOutput' runs to completion before
+  // the task queue is shutdown (and tasks can't be queued anymore).
+  mTaskQueue->AwaitIdle();
+
+  CFW_LOGV("Shutting down mTaskQueue");
   mTaskQueue->BeginShutdown();
   mTaskQueue->AwaitIdle();
-  DFW_LOGV("mTaskQueue shut down");
+  CFW_LOGV("mTaskQueue shut down");
 }
 
 } // namespace mozilla
--- a/dom/media/platforms/wrappers/FuzzingWrapper.h
+++ b/dom/media/platforms/wrappers/FuzzingWrapper.h
@@ -76,16 +76,17 @@ private:
   // should only be accessed on mTaskQueue.
   TimeStamp mPreviousOutput;
   // First member is the frame to be delayed.
   // Second member is true if an 'InputExhausted' arrived after that frame; in
   // which case an InputExhausted will be sent after finally outputting the frame.
   typedef Pair<RefPtr<MediaData>, bool> MediaDataAndInputExhausted;
   std::deque<MediaDataAndInputExhausted> mDelayedOutput;
   RefPtr<MediaTimer> mDelayedOutputTimer;
+  MozPromiseRequestHolder<MediaTimerPromise> mDelayedOutputRequest;
   // If draining, a 'DrainComplete' will be sent after all delayed frames have
   // been output.
   bool mDraining;
   // All callbacks are redirected through this task queue, both to avoid locking
   // and to have a consistent sequencing of callbacks.
   RefPtr<TaskQueue> mTaskQueue;
   void ScheduleOutputDelayedFrame();
   void OutputDelayedFrame();
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -846,19 +846,11 @@ skip-if = (toolkit == 'android' && proce
 [test_VideoPlaybackQuality_disabled.html]
 [test_volume.html]
 [test_vttparser.html]
 [test_webvtt_disabled.html]
 
 # The tests below contain backend-specific tests. Write backend independent
 # tests rather than adding to this list.
 [test_can_play_type_webm.html]
-skip-if = !webm
-[test_can_play_type_no_webm.html]
-skip-if = webm
 [test_can_play_type_wave.html]
-skip-if = !wave
-[test_can_play_type_no_wave.html]
-skip-if = wave
 [test_fragment_noplay.html]
-skip-if = !wave
 [test_fragment_play.html]
-skip-if = !wave
deleted file mode 100644
--- a/dom/media/test/test_can_play_type_no_wave.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=469247
--->
-<head>
-  <title>Test for Bug 469247: WAVE backend disabled</title>
-  <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="text/javascript" src="manifest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=469247">Mozill
-a Bug 469247</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-
-<video id="v"></video>
-
-<pre id="test">
-<script src="can_play_type_wave.js"></script>
-
-check_wave(document.getElementById('v'), false);
-
-mediaTestCleanup();
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/media/test/test_can_play_type_no_webm.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=566245
--->
-<head>
-  <title>Test for Bug 566245: WebM backend disabled</title>
-  <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="text/javascript" src="manifest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=566245">Mozill
-a Bug 566245</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-
-<video id="v"></video>
-
-<pre id="test">
-<script src="can_play_type_webm.js"></script>
-
-check_webm(document.getElementById('v'), false);
-
-mediaTestCleanup();
-
-</script>
-</pre>
-</body>
-</html>
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -85,21 +85,21 @@ skip-if = toolkit == 'gonk' || buildapp 
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_basicAudioVideoNoRtcpMux.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_basicVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_basicScreenshare.html]
 # no screenshare on b2g/android
 # frequent timeouts/crashes on e10s (bug 1048455)
-skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s # Bug 1141029 Mulet parity with B2G Desktop for TC
+skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_peerConnection_basicWindowshare.html]
 # no screenshare on b2g/android
 # frequent timeouts/crashes on e10s (bug 1048455)
-skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s # Bug 1141029 Mulet parity with B2G Desktop for TC
+skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_peerConnection_basicH264Video.html]
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || os == 'android' # bug 1043403 # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_peerConnection_bug822674.html]
 [test_peerConnection_bug825703.html]
 [test_peerConnection_bug827843.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_bug834153.html]
 [test_peerConnection_bug1013809.html]
@@ -156,56 +156,56 @@ skip-if = toolkit == 'gonk' || buildapp 
 [test_peerConnection_trackDisabling.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_twoAudioStreams.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_twoAudioTracksInOneStream.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_twoAudioVideoStreams.html]
 # b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18'
 [test_peerConnection_twoAudioVideoStreamsCombined.html]
 # b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18'
 [test_peerConnection_twoVideoStreams.html]
 # b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18'
 [test_peerConnection_twoVideoTracksInOneStream.html]
 # b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug)
 [test_peerConnection_addSecondAudioStream.html]
 skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_answererAddSecondAudioStream.html]
 skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
 [test_peerConnection_removeAudioTrack.html]
 skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_removeThenAddAudioTrack.html]
 skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_addSecondVideoStream.html]
 # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
+skip-if = toolkit == 'gonk' || android_version == '18'
 [test_peerConnection_removeVideoTrack.html]
 # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
+skip-if = toolkit == 'gonk' || (android_version == '18' && debug)
 [test_peerConnection_removeThenAddVideoTrack.html]
 # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
+skip-if = toolkit == 'gonk' || (android_version == '18' && debug)
 [test_peerConnection_replaceVideoThenRenegotiate.html]
 # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
+skip-if = toolkit == 'gonk' || (android_version == '18' && debug)
 [test_peerConnection_addSecondAudioStreamNoBundle.html]
 skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_removeThenAddAudioTrackNoBundle.html]
 skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_addSecondVideoStreamNoBundle.html]
 # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
+skip-if = toolkit == 'gonk' || android_version == '18'
 [test_peerConnection_removeThenAddVideoTrackNoBundle.html]
 # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
-skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
+skip-if = toolkit == 'gonk' || android_version == '18'
 [test_peerConnection_addDataChannel.html]
 skip-if = toolkit == 'gonk' # B2G emulator seems to be so slow that DTLS cannot establish properly
 [test_peerConnection_addDataChannelNoBundle.html]
 skip-if = toolkit == 'gonk' # B2G emulator seems to be so slow that DTLS cannot establish properly
 [test_peerConnection_webAudio.html]
 tags = webaudio webrtc
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_localRollback.html]
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -2645,17 +2645,22 @@ Notification::CreateAndShow(nsIGlobalObj
                             const nsAString& aTitle,
                             const NotificationOptions& aOptions,
                             const nsAString& aScope,
                             ErrorResult& aRv)
 {
   MOZ_ASSERT(aGlobal);
 
   AutoJSAPI jsapi;
-  jsapi.Init(aGlobal);
+  if (NS_WARN_IF(!jsapi.Init(aGlobal)))
+  {
+    aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
+    return nullptr;
+  }
+
   JSContext* cx = jsapi.cx();
 
   RefPtr<Notification> notification = CreateInternal(aGlobal, EmptyString(),
                                                        aTitle, aOptions);
 
   // Make a structured clone of the aOptions.mData object
   JS::Rooted<JS::Value> data(cx, aOptions.mData);
   notification->InitFromJSVal(cx, data, aRv);
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1157,16 +1157,21 @@ public:
   /** Make sure that the given dimensions don't overflow a 32-bit signed int
    * using 4 bytes per pixel; optionally, make sure that either dimension
    * doesn't exceed the given limit.
    */
   static bool CheckSurfaceSize(const IntSize &sz,
                                int32_t limit = 0,
                                int32_t allocLimit = 0);
 
+  /**
+   * Make sure that the given buffer size doesn't exceed the allocation limit.
+   */
+  static bool CheckBufferSize(int32_t bufSize);
+
   /** Make sure the given dimension satisfies the CheckSurfaceSize and is
    * within 8k limit.  The 8k value is chosen a bit randomly.
    */
   static bool ReasonableSurfaceSize(const IntSize &aSize);
 
   static bool AllowedSurfaceSize(const IntSize &aSize);
 
   static already_AddRefed<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr);
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -328,16 +328,20 @@ cairo_surface_t* ExtractSubImage(cairo_s
  * In either case, the caller must call cairo_surface_destroy on the
  * result when it is done with it.
  */
 cairo_surface_t*
 GetCairoSurfaceForSourceSurface(SourceSurface *aSurface,
                                 bool aExistingOnly = false,
                                 const IntRect& aSubImage = IntRect())
 {
+  if (!aSurface) {
+    return nullptr;
+  }
+
   IntRect subimage = IntRect(IntPoint(), aSurface->GetSize());
   if (!aSubImage.IsEmpty()) {
     MOZ_ASSERT(!aExistingOnly);
     MOZ_ASSERT(subimage.Contains(aSubImage));
     subimage = aSubImage;
   }
 
   if (aSurface->GetType() == SurfaceType::CAIRO) {
@@ -787,17 +791,17 @@ DrawTargetCairo::DrawSurface(SourceSurfa
                              const Rect &aSource,
                              const DrawSurfaceOptions &aSurfOptions,
                              const DrawOptions &aOptions)
 {
   if (mTransformSingular) {
     return;
   }
 
-  if (!IsValid()) {
+  if (!IsValid() || !aSurface) {
     gfxCriticalNote << "DrawSurface with bad surface " << cairo_surface_status(mSurface);
     return;
   }
 
   AutoPrepareForDrawing prep(this, mContext);
   AutoClearDeviceOffset clear(aSurface);
 
   float sx = aSource.Width() / aDest.Width();
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -260,16 +260,22 @@ Factory::AllowedSurfaceSize(const IntSiz
                                      sConfig->mMaxTextureSize,
                                      sConfig->mMaxAllocSize);
   }
 
   return CheckSurfaceSize(aSize);
 }
 
 bool
+Factory::CheckBufferSize(int32_t bufSize)
+{
+  return !sConfig || bufSize < sConfig->mMaxAllocSize;
+}
+
+bool
 Factory::CheckSurfaceSize(const IntSize &sz,
                           int32_t extentLimit,
                           int32_t allocLimit)
 {
   if (sz.width <= 0 || sz.height <= 0) {
     gfxDebug() << "Surface width or height <= 0!";
     return false;
   }
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -17,16 +17,17 @@
 #include "gfxPoint.h"
 #include "gfxRect.h"
 #include "nsRect.h"
 #include "nsRegion.h"
 #include "gfxTypes.h"
 #include "mozilla/layers/AsyncDragMetrics.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/CompositorTypes.h"
+#include "ImageTypes.h"
 #include "FrameMetrics.h"
 #include "FilterSupport.h"
 #include "mozilla/layers/GeckoContentController.h"
 
 #ifdef _MSC_VER
 #pragma warning( disable : 4800 )
 #endif
 
@@ -709,16 +710,17 @@ struct ParamTraits<mozilla::layers::Fram
     WriteParam(aMsg, aParam.mSmoothScrollOffset);
     WriteParam(aMsg, aParam.GetLineScrollAmount());
     WriteParam(aMsg, aParam.GetPageScrollAmount());
     WriteParam(aMsg, aParam.AllowVerticalScrollWithWheel());
     WriteParam(aMsg, aParam.mClipRect);
     WriteParam(aMsg, aParam.mMaskLayerIndex);
     WriteParam(aMsg, aParam.mIsLayersIdRoot);
     WriteParam(aMsg, aParam.mUsesContainerScrolling);
+    WriteParam(aMsg, aParam.mIsScrollInfoLayer);
     WriteParam(aMsg, aParam.GetContentDescription());
   }
 
   static bool ReadContentDescription(const Message* aMsg, void** aIter, paramType* aResult)
   {
     nsCString str;
     if (!ReadParam(aMsg, aIter, &str)) {
       return false;
@@ -755,16 +757,17 @@ struct ParamTraits<mozilla::layers::Fram
             ReadParam(aMsg, aIter, &aResult->mSmoothScrollOffset) &&
             ReadParam(aMsg, aIter, &aResult->mLineScrollAmount) &&
             ReadParam(aMsg, aIter, &aResult->mPageScrollAmount) &&
             ReadParam(aMsg, aIter, &aResult->mAllowVerticalScrollWithWheel) &&
             ReadParam(aMsg, aIter, &aResult->mClipRect) &&
             ReadParam(aMsg, aIter, &aResult->mMaskLayerIndex) &&
             ReadParam(aMsg, aIter, &aResult->mIsLayersIdRoot) &&
             ReadParam(aMsg, aIter, &aResult->mUsesContainerScrolling) &&
+            ReadParam(aMsg, aIter, &aResult->mIsScrollInfoLayer) &&
             ReadContentDescription(aMsg, aIter, aResult));
   }
 };
 
 template<>
 struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
 {
   typedef mozilla::layers::TextureFactoryIdentifier paramType;
@@ -792,17 +795,17 @@ struct ParamTraits<mozilla::layers::Text
     return result;
   }
 };
 
 template<>
 struct ParamTraits<mozilla::layers::TextureInfo>
 {
   typedef mozilla::layers::TextureInfo paramType;
-  
+
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mCompositableType);
     WriteParam(aMsg, aParam.mTextureFlags);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
@@ -823,16 +826,24 @@ template <>
 struct ParamTraits<mozilla::gfx::SurfaceFormat>
   : public ContiguousEnumSerializer<
              mozilla::gfx::SurfaceFormat,
              mozilla::gfx::SurfaceFormat::B8G8R8A8,
              mozilla::gfx::SurfaceFormat::UNKNOWN>
 {};
 
 template <>
+struct ParamTraits<mozilla::StereoMode>
+  : public ContiguousEnumSerializer<
+             mozilla::StereoMode,
+             mozilla::StereoMode::MONO,
+             mozilla::StereoMode::TOP_BOTTOM>
+{};
+
+template <>
 struct ParamTraits<mozilla::layers::ScrollableLayerGuid>
 {
   typedef mozilla::layers::ScrollableLayerGuid paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mLayersId);
     WriteParam(aMsg, aParam.mPresShellId);
@@ -842,16 +853,17 @@ struct ParamTraits<mozilla::layers::Scro
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mLayersId) &&
             ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
             ReadParam(aMsg, aIter, &aResult->mScrollId));
   }
 };
 
+
 template <>
 struct ParamTraits<mozilla::layers::ZoomConstraints>
 {
   typedef mozilla::layers::ZoomConstraints paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mAllowZoom);
--- a/gfx/layers/BufferTexture.cpp
+++ b/gfx/layers/BufferTexture.cpp
@@ -25,20 +25,20 @@ public:
   CreateSimilar(ISurfaceAllocator* aAllocator,
                 TextureFlags aFlags = TextureFlags::DEFAULT,
                 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
 
   virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
 
   virtual void Deallocate(ISurfaceAllocator*) override;
 
-  MemoryTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
+  MemoryTextureData(const BufferDescriptor& aDesc,
                     gfx::BackendType aMoz2DBackend,
                     uint8_t* aBuffer, size_t aBufferSize)
-  : BufferTextureData(aSize, aFormat, aMoz2DBackend)
+  : BufferTextureData(aDesc, aMoz2DBackend)
   , mBuffer(aBuffer)
   , mBufferSize(aBufferSize)
   {
     MOZ_ASSERT(aBuffer);
     MOZ_ASSERT(aBufferSize);
   }
 
   virtual uint8_t* GetBuffer() override { return mBuffer; }
@@ -62,19 +62,19 @@ public:
   CreateSimilar(ISurfaceAllocator* aAllocator,
                 TextureFlags aFlags = TextureFlags::DEFAULT,
                 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
 
   virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
 
   virtual void Deallocate(ISurfaceAllocator* aAllocator) override;
 
-  ShmemTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
+  ShmemTextureData(const BufferDescriptor& aDesc,
                    gfx::BackendType aMoz2DBackend, mozilla::ipc::Shmem aShmem)
-  : BufferTextureData(aSize, aFormat, aMoz2DBackend)
+  : BufferTextureData(aDesc, aMoz2DBackend)
   , mShmem(aShmem)
   {
     MOZ_ASSERT(mShmem.Size<uint8_t>());
   }
 
   virtual uint8_t* GetBuffer() override { return mShmem.get<uint8_t>(); }
 
   virtual size_t GetBufferSize() override { return mShmem.Size<uint8_t>(); }
@@ -92,80 +92,100 @@ BufferTextureData::Create(gfx::IntSize a
   if (!aAllocator || aAllocator->IsSameProcess()) {
     return MemoryTextureData::Create(aSize, aFormat, aMoz2DBackend, aFlags, aAllocFlags, aAllocator);
   } else {
     return ShmemTextureData::Create(aSize, aFormat, aMoz2DBackend, aFlags, aAllocFlags, aAllocator);
   }
 }
 
 BufferTextureData*
-BufferTextureData::CreateWithBufferSize(ISurfaceAllocator* aAllocator,
-                                        gfx::SurfaceFormat aFormat,
-                                        size_t aSize,
-                                        TextureFlags aTextureFlags)
+BufferTextureData::CreateInternal(ISurfaceAllocator* aAllocator,
+                                  const BufferDescriptor& aDesc,
+                                  gfx::BackendType aMoz2DBackend,
+                                  int32_t aBufferSize,
+                                  TextureFlags aTextureFlags)
 {
-  if (aSize == 0) {
-    return nullptr;
-  }
-
-  BufferTextureData* data;
   if (!aAllocator || aAllocator->IsSameProcess()) {
-    uint8_t* buffer = new (fallible) uint8_t[aSize];
+    uint8_t* buffer = new (fallible) uint8_t[aBufferSize];
     if (!buffer) {
       return nullptr;
     }
 
-    data = new MemoryTextureData(gfx::IntSize(), aFormat, gfx::BackendType::NONE, buffer, aSize);
+    return new MemoryTextureData(aDesc, aMoz2DBackend, buffer, aBufferSize);
   } else {
     ipc::Shmem shm;
-    if (!aAllocator->AllocUnsafeShmem(aSize, OptimalShmemType(), &shm)) {
+    if (!aAllocator->AllocUnsafeShmem(aBufferSize, OptimalShmemType(), &shm)) {
       return nullptr;
     }
 
-    data = new ShmemTextureData(gfx::IntSize(), aFormat, gfx::BackendType::NONE, shm);
+    return new ShmemTextureData(aDesc, aMoz2DBackend, shm);
+  }
+}
+
+BufferTextureData*
+BufferTextureData::CreateForYCbCrWithBufferSize(ISurfaceAllocator* aAllocator,
+                                                gfx::SurfaceFormat aFormat,
+                                                int32_t aBufferSize,
+                                                TextureFlags aTextureFlags)
+{
+  if (aBufferSize == 0 || !gfx::Factory::CheckBufferSize(aBufferSize)) {
+    return nullptr;
   }
 
   // Initialize the metadata with something, even if it will have to be rewritten
   // afterwards since we don't know the dimensions of the texture at this point.
-  if (aFormat == gfx::SurfaceFormat::YUV) {
-    YCbCrImageDataSerializer serializer(data->GetBuffer(), data->GetBufferSize());
-    serializer.InitializeBufferInfo(gfx::IntSize(0,0), gfx::IntSize(0,0), StereoMode::MONO);
-  } else {
-    ImageDataSerializer serializer(data->GetBuffer(), data->GetBufferSize());
-    serializer.InitializeBufferInfo(gfx::IntSize(0, 0), aFormat);
-  }
+  BufferDescriptor desc = YCbCrDescriptor(gfx::IntSize(), gfx::IntSize(),
+                                          0, 0, 0, StereoMode::MONO);
 
-  return data;
+  return CreateInternal(aAllocator, desc, gfx::BackendType::NONE, aBufferSize,
+                        aTextureFlags);
 }
 
 BufferTextureData*
 BufferTextureData::CreateForYCbCr(ISurfaceAllocator* aAllocator,
                                   gfx::IntSize aYSize,
                                   gfx::IntSize aCbCrSize,
                                   StereoMode aStereoMode,
                                   TextureFlags aTextureFlags)
 {
-  size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize, aCbCrSize);
-  BufferTextureData* texture = CreateWithBufferSize(aAllocator, gfx::SurfaceFormat::YUV,
-                                                    bufSize, aTextureFlags);
-  if (!texture) {
+  uint32_t bufSize = ImageDataSerializer::ComputeYCbCrBufferSize(aYSize, aCbCrSize);
+  if (bufSize == 0) {
     return nullptr;
   }
 
-  YCbCrImageDataSerializer serializer(texture->GetBuffer(), texture->GetBufferSize());
-  serializer.InitializeBufferInfo(aYSize, aCbCrSize, aStereoMode);
-  texture->mSize = aYSize;
+  uint32_t yOffset;
+  uint32_t cbOffset;
+  uint32_t crOffset;
+  ImageDataSerializer::ComputeYCbCrOffsets(aYSize.width, aYSize.height,
+                                          aCbCrSize.width, aCbCrSize.height,
+                                          yOffset, cbOffset, crOffset);
+
+  YCbCrDescriptor descriptor = YCbCrDescriptor(aYSize, aCbCrSize, yOffset, cbOffset,
+                                               crOffset, aStereoMode);
 
-  return texture;
+ return CreateInternal(aAllocator, descriptor, gfx::BackendType::NONE, bufSize,
+                       aTextureFlags);
+}
+
+gfx::IntSize
+BufferTextureData::GetSize() const
+{
+  return ImageDataSerializer::SizeFromBufferDescriptor(mDescriptor);
+}
+
+gfx::SurfaceFormat
+BufferTextureData::GetFormat() const
+{
+  return ImageDataSerializer::FormatFromBufferDescriptor(mDescriptor);
 }
 
 bool
 BufferTextureData::SupportsMoz2D() const
 {
-  switch (mFormat) {
+  switch (GetFormat()) {
     case gfx::SurfaceFormat::YUV:
     case gfx::SurfaceFormat::NV12:
     case gfx::SurfaceFormat::UNKNOWN:
       return false;
     default:
       return true;
   }
 }
@@ -174,97 +194,111 @@ already_AddRefed<gfx::DrawTarget>
 BufferTextureData::BorrowDrawTarget()
 {
   if (mDrawTarget) {
     mDrawTarget->SetTransform(gfx::Matrix());
     RefPtr<gfx::DrawTarget> dt = mDrawTarget;
     return dt.forget();
   }
 
-  ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
-  if (!serializer.IsValid()) {
+  if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
     return nullptr;
   }
 
-  mDrawTarget = serializer.GetAsDrawTarget(mMoz2DBackend);
+  const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
+
+  uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
+  mDrawTarget = gfx::Factory::CreateDrawTargetForData(mMoz2DBackend,
+                                                      GetBuffer(), rgb.size(),
+                                                      stride, rgb.format());
+
   if (mDrawTarget) {
     RefPtr<gfx::DrawTarget> dt = mDrawTarget;
     return dt.forget();
   }
 
   // TODO - should we warn? should we really fallback to cairo? perhaps
   // at least update mMoz2DBackend...
-  mDrawTarget = serializer.GetAsDrawTarget(gfx::BackendType::CAIRO);
+  if (mMoz2DBackend != gfx::BackendType::CAIRO) {
+    mDrawTarget = gfx::Factory::CreateDrawTargetForData(gfx::BackendType::CAIRO,
+                                                        GetBuffer(), rgb.size(),
+                                                        stride, rgb.format());
+  }
+
   if (!mDrawTarget) {
     gfxCriticalNote << "BorrowDrawTarget failure, original backend " << (int)mMoz2DBackend;
   }
 
   RefPtr<gfx::DrawTarget> dt = mDrawTarget;
   return dt.forget();
 }
 
 bool
 BufferTextureData::BorrowMappedData(MappedTextureData& aData)
 {
-  if (mFormat == gfx::SurfaceFormat::YUV) {
+  if (GetFormat() == gfx::SurfaceFormat::YUV) {
     return false;
   }
 
-  ImageDataDeserializer view(GetBuffer(), GetBufferSize());
-  if (!view.IsValid()) {
-    return false;
-  }
+  gfx::IntSize size = GetSize();
 
-  aData.data = view.GetData();
-  aData.size = view.GetSize();
-  aData.stride = view.GetStride();
-  aData.format = mFormat;
+  aData.data = GetBuffer();
+  aData.size = size;
+  aData.format = GetFormat();
+  aData.stride = ImageDataSerializer::ComputeRGBStride(aData.format, size.width);
 
   return true;
 }
 
 bool
 BufferTextureData::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap)
 {
-  if (mFormat != gfx::SurfaceFormat::YUV) {
-    return false;
-  }
-
-  YCbCrImageDataDeserializer view(GetBuffer(), GetBufferSize());
-  if (!view.IsValid()) {
+  if (mDescriptor.type() != BufferDescriptor::TYCbCrDescriptor) {
     return false;
   }
 
-  aMap.stereoMode = view.GetStereoMode();
-  aMap.metadata = GetBuffer();
+  const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
+
+  uint8_t* data = GetBuffer();
+  auto ySize = desc.ySize();
+  auto cbCrSize = desc.cbCrSize();
 
-  aMap.y.data = view.GetYData();
-  aMap.y.size = view.GetYSize();
-  aMap.y.stride = view.GetYStride();
+  aMap.stereoMode = desc.stereoMode();
+  aMap.metadata = nullptr;
+
+  aMap.y.data = data + desc.yOffset();
+  aMap.y.size = ySize;
+  aMap.y.stride = ySize.width;
   aMap.y.skip = 0;
 
-  aMap.cb.data = view.GetCbData();
-  aMap.cb.size = view.GetCbCrSize();
-  aMap.cb.stride = view.GetCbCrStride();
+  aMap.cb.data = data + desc.cbOffset();
+  aMap.cb.size = cbCrSize;
+  aMap.cb.stride = cbCrSize.width;
   aMap.cb.skip = 0;
 
-  aMap.cr.data = view.GetCrData();
-  aMap.cr.size = view.GetCbCrSize();
-  aMap.cr.stride = view.GetCbCrStride();
+  aMap.cr.data = data + desc.crOffset();
+  aMap.cr.size = cbCrSize;
+  aMap.cr.stride = cbCrSize.width;
   aMap.cr.skip = 0;
 
   return true;
 }
 
 bool
 BufferTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
 {
-  ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
+  if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
+    return false;
+  }
+  const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
 
-  RefPtr<gfx::DataSourceSurface> surface = serializer.GetAsSurface();
+  uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
+  RefPtr<gfx::DataSourceSurface> surface =
+    gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(), stride,
+                                                  rgb.size(), rgb.format());
 
   if (!surface) {
     gfxCriticalError() << "Failed to get serializer as surface!";
     return false;
   }
 
   RefPtr<gfx::DataSourceSurface> srcSurf = aSurface->GetDataSurface();
 
@@ -299,148 +333,164 @@ BufferTextureData::UpdateFromSurface(gfx
   }
 
   srcSurf->Unmap();
   surface->Unmap();
 
   return true;
 }
 
+void
+BufferTextureData::SetDesciptor(const BufferDescriptor& aDescriptor)
+{
+  MOZ_ASSERT(mDescriptor.type() == BufferDescriptor::TYCbCrDescriptor);
+  MOZ_ASSERT(mDescriptor.get_YCbCrDescriptor().ySize() == gfx::IntSize());
+  mDescriptor = aDescriptor;
+}
+
 bool
 MemoryTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
 {
   MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN);
   if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
     return false;
   }
 
-  aOutDescriptor = SurfaceDescriptorMemory(reinterpret_cast<uintptr_t>(mBuffer),
-                                           GetFormat());
+  uintptr_t ptr = reinterpret_cast<uintptr_t>(mBuffer);
+  aOutDescriptor = SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(ptr));
+
   return true;
 }
 
-static bool InitBuffer(uint8_t* buf, size_t bufSize,
-                       gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
-                       TextureAllocationFlags aAllocFlags)
+static bool InitBuffer(uint8_t* buf, size_t bufSize, TextureAllocationFlags aAllocFlags)
 {
   if (!buf) {
     gfxDebug() << "BufferTextureData: Failed to allocate " << bufSize << " bytes";
     return false;
   }
 
   if (aAllocFlags & ALLOC_CLEAR_BUFFER) {
     memset(buf, 0, bufSize);
   }
   if (aAllocFlags & ALLOC_CLEAR_BUFFER_WHITE) {
     memset(buf, 0xFF, bufSize);
   }
 
-  ImageDataSerializer serializer(buf, bufSize);
-  serializer.InitializeBufferInfo(aSize, aFormat);
   return true;
 }
 
 MemoryTextureData*
 MemoryTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
                           gfx::BackendType aMoz2DBackend, TextureFlags aFlags,
                           TextureAllocationFlags aAllocFlags,
                           ISurfaceAllocator*)
 {
+  // Should have used CreateForYCbCr.
+  MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV);
+
   if (aSize.width <= 0 || aSize.height <= 0) {
     gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height;
     return nullptr;
   }
 
-  uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, aFormat);
+  uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
   if (!bufSize) {
     return nullptr;
   }
 
   uint8_t* buf = new (fallible) uint8_t[bufSize];
-
-  if (InitBuffer(buf, bufSize, aSize, aFormat, aAllocFlags)) {
-    GfxMemoryImageReporter::DidAlloc(buf);
-    return new MemoryTextureData(aSize, aFormat, aMoz2DBackend, buf, bufSize);
+  if (!InitBuffer(buf, bufSize, aAllocFlags)) {
+    return nullptr;
   }
 
-  return nullptr;
+  GfxMemoryImageReporter::DidAlloc(buf);
+
+  BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat);
+
+  return new MemoryTextureData(descriptor, aMoz2DBackend, buf, bufSize);
 }
 
 void
 MemoryTextureData::Deallocate(ISurfaceAllocator*)
 {
   MOZ_ASSERT(mBuffer);
   GfxMemoryImageReporter::WillFree(mBuffer);
   delete [] mBuffer;
   mBuffer = nullptr;
 }
 
 TextureData*
 MemoryTextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
                                  TextureFlags aFlags,
                                  TextureAllocationFlags aAllocFlags) const
 {
-  return MemoryTextureData::Create(mSize, mFormat, mMoz2DBackend,
+  return MemoryTextureData::Create(GetSize(), GetFormat(), mMoz2DBackend,
                                    aFlags, aAllocFlags, aAllocator);
 }
 
 bool
 ShmemTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
 {
   MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN);
   if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
     return false;
   }
 
-  aOutDescriptor = SurfaceDescriptorShmem(mShmem, GetFormat());
+  aOutDescriptor = SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(mShmem));
 
   return true;
 }
 
 ShmemTextureData*
 ShmemTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
                          gfx::BackendType aMoz2DBackend, TextureFlags aFlags,
                          TextureAllocationFlags aAllocFlags,
                          ISurfaceAllocator* aAllocator)
 {
   MOZ_ASSERT(aAllocator);
+  // Should have used CreateForYCbCr.
+  MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV);
+
   if (!aAllocator) {
     return nullptr;
   }
 
   if (aSize.width <= 0 || aSize.height <= 0) {
     gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height;
     return nullptr;
   }
 
-  uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, aFormat);
+  uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
   if (!bufSize) {
     return nullptr;
   }
 
   mozilla::ipc::Shmem shm;
   if (!aAllocator->AllocUnsafeShmem(bufSize, OptimalShmemType(), &shm)) {
     return nullptr;
   }
 
   uint8_t* buf = shm.get<uint8_t>();
+  if (!InitBuffer(buf, bufSize, aAllocFlags)) {
+    return nullptr;
+  }
 
-  if (InitBuffer(buf, bufSize, aSize, aFormat, aAllocFlags)) {
-    return new ShmemTextureData(aSize, aFormat, aMoz2DBackend, shm);
-  }
+  BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat);
+
+  return new ShmemTextureData(descriptor, aMoz2DBackend, shm);
 
   return nullptr;
 }
 
 TextureData*
 ShmemTextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
                                 TextureFlags aFlags,
                                 TextureAllocationFlags aAllocFlags) const
 {
-  return ShmemTextureData::Create(mSize, mFormat, mMoz2DBackend,
+  return ShmemTextureData::Create(GetSize(), GetFormat(), mMoz2DBackend,
                                   aFlags, aAllocFlags, aAllocator);
 }
 
 void
 ShmemTextureData::Deallocate(ISurfaceAllocator* aAllocator)
 {
   aAllocator->DeallocShmem(mShmem);
 }
--- a/gfx/layers/BufferTexture.h
+++ b/gfx/layers/BufferTexture.h
@@ -1,18 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; 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_LAYERS_BUFFERETEXTURE
 #define MOZILLA_LAYERS_BUFFERETEXTURE
 
-#include "mozilla/layers/ImageDataSerializer.h"
-#include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/ipc/SharedMemory.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
 namespace layers {
@@ -20,62 +18,72 @@ namespace layers {
 class BufferTextureData : public TextureData
 {
 public:
   static BufferTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
                                    gfx::BackendType aMoz2DBackend,TextureFlags aFlags,
                                    TextureAllocationFlags aAllocFlags,
                                    ISurfaceAllocator* aAllocator);
 
-  static BufferTextureData* CreateWithBufferSize(ISurfaceAllocator* aAllocator,
-                                                 gfx::SurfaceFormat aFormat,
-                                                 size_t aSize,
-                                                 TextureFlags aTextureFlags);
-
   static BufferTextureData* CreateForYCbCr(ISurfaceAllocator* aAllocator,
                                            gfx::IntSize aYSize,
                                            gfx::IntSize aCbCrSize,
                                            StereoMode aStereoMode,
                                            TextureFlags aTextureFlags);
 
+  // It is generally better to use CreateForYCbCr instead.
+  // This creates a half-initialized texture since we don't know the sizes and
+  // offsets in the buffer.
+  static BufferTextureData* CreateForYCbCrWithBufferSize(ISurfaceAllocator* aAllocator,
+                                                         gfx::SurfaceFormat aFormat,
+                                                         int32_t aSize,
+                                                         TextureFlags aTextureFlags);
+
   virtual bool Lock(OpenMode aMode, FenceHandle*) override { return true; }
 
   virtual void Unlock() override {}
 
-  virtual gfx::IntSize GetSize() const override { return mSize; }
+  virtual gfx::IntSize GetSize() const override;
 
-  virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
+  virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
 
   virtual bool CanExposeMappedData() const override { return true; }
 
   virtual bool BorrowMappedData(MappedTextureData& aMap) override;
 
   virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap) override;
 
   virtual bool SupportsMoz2D() const override;
 
   virtual bool HasInternalBuffer() const override { return true; }
 
   // use TextureClient's default implementation
   virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
 
+  // Don't use this.
+  void SetDesciptor(const BufferDescriptor& aDesc);
+
 protected:
+  static BufferTextureData* CreateInternal(ISurfaceAllocator* aAllocator,
+                                           const BufferDescriptor& aDesc,
+                                           gfx::BackendType aMoz2DBackend,
+                                           int32_t aBufferSize,
+                                           TextureFlags aTextureFlags);
+
   virtual uint8_t* GetBuffer() = 0;
   virtual size_t GetBufferSize() = 0;
 
-  BufferTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, gfx::BackendType aMoz2DBackend)
-  : mSize(aSize)
-  , mFormat(aFormat)
+  BufferTextureData(const BufferDescriptor& aDescriptor, gfx::BackendType aMoz2DBackend)
+  : mDescriptor(aDescriptor)
   , mMoz2DBackend(aMoz2DBackend)
   {}
 
   RefPtr<gfx::DrawTarget> mDrawTarget;
-  gfx::IntSize mSize;
-  gfx::SurfaceFormat mFormat;
+  BufferDescriptor mDescriptor;
   gfx::BackendType mMoz2DBackend;
 };
 
 } // namespace
 } // namespace
 
 #endif
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -63,16 +63,17 @@ public:
     , mViewport(0, 0, 0, 0)
     , mExtraResolution()
     , mBackgroundColor()
     , mLineScrollAmount(0, 0)
     , mPageScrollAmount(0, 0)
     , mAllowVerticalScrollWithWheel(false)
     , mIsLayersIdRoot(false)
     , mUsesContainerScrolling(false)
+    , mIsScrollInfoLayer(false)
   {
   }
 
   // Default copy ctor and operator= are fine
 
   bool operator==(const FrameMetrics& aOther) const
   {
     return mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) &&
@@ -99,17 +100,18 @@ public:
            mBackgroundColor == aOther.mBackgroundColor &&
            mDoSmoothScroll == aOther.mDoSmoothScroll &&
            mLineScrollAmount == aOther.mLineScrollAmount &&
            mPageScrollAmount == aOther.mPageScrollAmount &&
            mAllowVerticalScrollWithWheel == aOther.mAllowVerticalScrollWithWheel &&
            mClipRect == aOther.mClipRect &&
            mMaskLayerIndex == aOther.mMaskLayerIndex &&
            mIsLayersIdRoot == aOther.mIsLayersIdRoot &&
-		   mUsesContainerScrolling == aOther.mUsesContainerScrolling;
+           mUsesContainerScrolling == aOther.mUsesContainerScrolling &&
+           mIsScrollInfoLayer == aOther.mIsScrollInfoLayer;
   }
   bool operator!=(const FrameMetrics& aOther) const
   {
     return !operator==(aOther);
   }
 
   bool IsDefault() const
   {
@@ -540,16 +542,23 @@ public:
 
   // Implemented out of line because the implementation needs gfxPrefs.h
   // and we don't want to include that from FrameMetrics.h.
   void SetUsesContainerScrolling(bool aValue);
   bool UsesContainerScrolling() const {
     return mUsesContainerScrolling;
   }
 
+  void SetIsScrollInfoLayer(bool aIsScrollInfoLayer) {
+    mIsScrollInfoLayer = aIsScrollInfoLayer;
+  }
+  bool IsScrollInfoLayer() const {
+    return mIsScrollInfoLayer;
+  }
+
 private:
 
   // The pres-shell resolution that has been induced on the document containing
   // this scroll frame as a result of zooming this scroll frame (whether via
   // user action, or choosing an initial zoom level on page load). This can
   // only be different from 1.0 for frames that are zoomable, which currently
   // is just the root content document's root scroll frame (mIsRoot = true).
   // This is a plain float rather than a ScaleFactor because in and of itself
@@ -727,16 +736,19 @@ private:
   // Whether these framemetrics are for the root scroll frame (root element if
   // we don't have a root scroll frame) for its layers id.
   bool mIsLayersIdRoot;
 
   // True if scrolling using containers, false otherwise. This can be removed
   // when containerful scrolling is eliminated.
   bool mUsesContainerScrolling;
 
+  // Whether or not this frame has a "scroll info layer" to capture events.
+  bool mIsScrollInfoLayer;
+
   // WARNING!!!!
   //
   // When adding new fields to FrameMetrics, the following places should be
   // updated to include them (as needed):
   //    FrameMetrics::operator ==
   //    AsyncPanZoomController::NotifyLayersUpdated
   //    The ParamTraits specialization in GfxMessageUtils.h
   //
--- a/gfx/layers/ImageDataSerializer.cpp
+++ b/gfx/layers/ImageDataSerializer.cpp
@@ -1,177 +1,184 @@
 /* -*- Mode: C++; tab-width: 20; 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 "ImageDataSerializer.h"
+#include <string.h>                     // for memcpy
 #include "gfx2DGlue.h"                  // for SurfaceFormatToImageFormat
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
 #include "mozilla/gfx/Logging.h"        // for gfxDebug
 #include "mozilla/gfx/Tools.h"          // for GetAlignedStride, etc
+#include "mozilla/gfx/Types.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
+#include "yuv_convert.h"                // for ConvertYCbCrToRGB32, etc
 
 namespace mozilla {
 namespace layers {
+namespace ImageDataSerializer {
 
 using namespace gfx;
 
-// The Data is layed out as follows:
-//
-//  +-------------------+   -++ --+   <-- ImageDataSerializerBase::mData pointer
-//  | SurfaceBufferInfo |     |   |
-//  +-------------------+   --+   | offset
-//  |        ...        |         |
-//  +-------------------+   ------+
-//  |                   |
-//  |       data        |
-//  |                   |
-//  +-------------------+
-
-// Structure written at the beginning of the data blob containing the image
-// (as shown in the figure above). It contains the necessary informations to
-// read the image in the blob.
-namespace {
-struct SurfaceBufferInfo
-{
-  int32_t width;
-  int32_t height;
-  SurfaceFormat format;
+#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
 
-  static int32_t GetOffset()
-  {
-    return GetAlignedStride<16>(sizeof(SurfaceBufferInfo));
-  }
-};
-} // namespace
-
-static SurfaceBufferInfo*
-GetBufferInfo(uint8_t* aData, size_t aDataSize)
-{
-  return aDataSize >= sizeof(SurfaceBufferInfo)
-         ? reinterpret_cast<SurfaceBufferInfo*>(aData)
-         : nullptr;
-}
-
-void
-ImageDataSerializer::InitializeBufferInfo(IntSize aSize,
-                                          SurfaceFormat aFormat)
-{
-  SurfaceBufferInfo* info = GetBufferInfo(mData, mDataSize);
-  MOZ_ASSERT(info); // OK to assert here, this method is client-side-only
-  info->width = aSize.width;
-  info->height = aSize.height;
-  info->format = aFormat;
-  Validate();
-}
-
-static inline int32_t
-ComputeStride(SurfaceFormat aFormat, int32_t aWidth)
+int32_t
+ComputeRGBStride(SurfaceFormat aFormat, int32_t aWidth)
 {
   CheckedInt<int32_t> size = BytesPerPixel(aFormat);
   size *= aWidth;
   if (!size.isValid() || size.value() <= 0) {
     gfxDebug() << "ComputeStride overflow " << aWidth;
     return 0;
   }
 
   return GetAlignedStride<4>(size.value());
 }
 
+int32_t
+GetRGBStride(const RGBDescriptor& aDescriptor)
+{
+  return ComputeRGBStride(aDescriptor.format(), aDescriptor.size().width);
+}
+
 uint32_t
-ImageDataSerializerBase::ComputeMinBufferSize(IntSize aSize,
-                                              SurfaceFormat aFormat)
+ComputeRGBBufferSize(IntSize aSize, SurfaceFormat aFormat)
 {
   MOZ_ASSERT(aSize.height >= 0 && aSize.width >= 0);
 
   // This takes care of checking whether there could be overflow
   // with enough margin for the metadata.
   if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
     return 0;
   }
 
-  int32_t bufsize = GetAlignedStride<16>(ComputeStride(aFormat, aSize.width)
-                                         * aSize.height)
-                  + SurfaceBufferInfo::GetOffset();
+  int32_t bufsize = GetAlignedStride<16>(ComputeRGBStride(aFormat, aSize.width)
+                                         * aSize.height);
 
   if (bufsize < 0) {
     // This should not be possible thanks to Factory::AllowedSurfaceSize
     return 0;
   }
 
   return bufsize;
 }
 
-void
-ImageDataSerializerBase::Validate()
+
+
+// Minimum required shmem size in bytes
+uint32_t
+ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
+                       const gfx::IntSize& aCbCrSize, int32_t aCbCrStride)
 {
-  mIsValid = false;
-  if (!mData) {
-    return;
+  MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
+
+  if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 || aCbCrSize.width < 0 ||
+      aYSize.width > aYStride || aCbCrSize.width > aCbCrStride ||
+      aCbCrStride > aYStride || aCbCrSize.height > aYSize.height ||
+      !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height))) {
+    return 0;
   }
-  SurfaceBufferInfo* info = GetBufferInfo(mData, mDataSize);
-  if (!info) {
-    return;
-  }
-  size_t requiredSize =
-           ComputeMinBufferSize(IntSize(info->width, info->height), info->format);
-
-  mIsValid = !!requiredSize && requiredSize <= mDataSize;
+  // Overflow checks are performed in AllowedSurfaceSize
+  return MOZ_ALIGN_WORD(aYSize.height * aYStride)
+         + 2 * MOZ_ALIGN_WORD(aCbCrSize.height * aCbCrStride);
 }
 
-uint8_t*
-ImageDataSerializerBase::GetData()
+// Minimum required shmem size in bytes
+uint32_t
+ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, const gfx::IntSize& aCbCrSize)
 {
-  MOZ_ASSERT(IsValid());
-  return mData + SurfaceBufferInfo::GetOffset();
+  return ComputeYCbCrBufferSize(aYSize, aYSize.width, aCbCrSize, aCbCrSize.width);
 }
 
 uint32_t
-ImageDataSerializerBase::GetStride() const
+ComputeYCbCrBufferSize(uint32_t aBufferSize)
 {
-  MOZ_ASSERT(IsValid());
-  SurfaceBufferInfo* info = GetBufferInfo(mData, mDataSize);
-  return ComputeStride(GetFormat(), info->width);
+  return MOZ_ALIGN_WORD(aBufferSize);
+}
+
+void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight,
+                         int32_t cbCrStride, int32_t cbCrHeight,
+                         uint32_t& outYOffset, uint32_t& outCbOffset, uint32_t& outCrOffset)
+{
+  outYOffset = 0;
+  outCbOffset = outYOffset + MOZ_ALIGN_WORD(yStride * yHeight);
+  outCrOffset = outCbOffset + MOZ_ALIGN_WORD(cbCrStride * cbCrHeight);
 }
 
-IntSize
-ImageDataSerializerBase::GetSize() const
+gfx::SurfaceFormat FormatFromBufferDescriptor(const BufferDescriptor& aDescriptor)
 {
-  MOZ_ASSERT(IsValid());
-  SurfaceBufferInfo* info = GetBufferInfo(mData, mDataSize);
-  return IntSize(info->width, info->height);
+  switch (aDescriptor.type()) {
+    case BufferDescriptor::TRGBDescriptor:
+      return aDescriptor.get_RGBDescriptor().format();
+    case BufferDescriptor::TYCbCrDescriptor:
+      return gfx::SurfaceFormat::YUV;
+    default:
+      MOZ_CRASH();
+  }
 }
 
-SurfaceFormat
-ImageDataSerializerBase::GetFormat() const
+gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
 {
-  MOZ_ASSERT(IsValid());
-  return GetBufferInfo(mData, mDataSize)->format;
+  switch (aDescriptor.type()) {
+    case BufferDescriptor::TRGBDescriptor:
+      return aDescriptor.get_RGBDescriptor().size();
+    case BufferDescriptor::TYCbCrDescriptor:
+      return aDescriptor.get_YCbCrDescriptor().ySize();
+    default:
+      MOZ_CRASH();
+  }
+}
+
+uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
+{
+  return aBuffer + aDescriptor.yOffset();
 }
 
-already_AddRefed<DrawTarget>
-ImageDataSerializerBase::GetAsDrawTarget(gfx::BackendType aBackend)
+uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
 {
-  MOZ_ASSERT(IsValid());
-  RefPtr<DrawTarget> dt = gfx::Factory::CreateDrawTargetForData(aBackend,
-                                               GetData(), GetSize(),
-                                               GetStride(), GetFormat());
-  if (!dt) {
-    gfxCriticalNote << "Failed GetAsDrawTarget " << IsValid() << ", " << hexa(size_t(mData)) << " + " << SurfaceBufferInfo::GetOffset() << ", " << GetSize() << ", " << GetStride() << ", " << (int)GetFormat();
-  }
-  return dt.forget();
+  return aBuffer + aDescriptor.cbOffset();
+}
+
+uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
+{
+  return aBuffer + aDescriptor.crOffset();
 }
 
-already_AddRefed<gfx::DataSourceSurface>
-ImageDataSerializerBase::GetAsSurface()
+already_AddRefed<DataSourceSurface>
+DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
 {
-  MOZ_ASSERT(IsValid());
-  return Factory::CreateWrappingDataSourceSurface(GetData(),
-                                                  GetStride(),
-                                                  GetSize(),
-                                                  GetFormat());
+  gfx::IntSize ySize = aDescriptor.ySize();
+  gfx::IntSize cbCrSize = aDescriptor.cbCrSize();
+  int32_t yStride = ySize.width;
+  int32_t cbCrStride = cbCrSize.width;
+
+  RefPtr<DataSourceSurface> result =
+    Factory::CreateDataSourceSurface(ySize, gfx::SurfaceFormat::B8G8R8X8);
+  if (NS_WARN_IF(!result)) {
+    return nullptr;
+  }
+
+  DataSourceSurface::MappedSurface map;
+  if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
+    return nullptr;
+  }
+
+  gfx::YUVType type = TypeFromSize(ySize.width, ySize.height,
+                                   cbCrSize.width, cbCrSize.height);
+  gfx::ConvertYCbCrToRGB32(GetYChannel(aBuffer, aDescriptor),
+                           GetCbChannel(aBuffer, aDescriptor),
+                           GetCrChannel(aBuffer, aDescriptor),
+                           map.mData,
+                           0, 0, //pic x and y
+                           ySize.width, ySize.height,
+                           yStride, cbCrStride,
+                           map.mStride, type);
+  result->Unmap();
+  return result.forget();
 }
 
+
+} // namespace ImageDataSerializer
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ImageDataSerializer.h
+++ b/gfx/layers/ImageDataSerializer.h
@@ -19,79 +19,56 @@ namespace gfx {
 class DataSourceSurface;
 class DrawTarget;
 } // namespace gfx
 } // namespace mozilla
 
 namespace mozilla {
 namespace layers {
 
-class ImageDataSerializerBase
-{
-public:
-  bool IsValid() const { return mIsValid; }
+namespace ImageDataSerializer {
 
-  uint8_t* GetData();
-  uint32_t GetStride() const;
-  gfx::IntSize GetSize() const;
-  gfx::SurfaceFormat GetFormat() const;
-  already_AddRefed<gfx::DataSourceSurface> GetAsSurface();
-  already_AddRefed<gfx::DrawTarget> GetAsDrawTarget(gfx::BackendType aBackend);
+// RGB
 
-  static uint32_t ComputeMinBufferSize(gfx::IntSize aSize,
-                                       gfx::SurfaceFormat aFormat);
+int32_t ComputeRGBStride(gfx::SurfaceFormat aFormat, int32_t aWidth);
 
-  size_t GetBufferSize() const { return mDataSize; }
-
-protected:
+int32_t GetRGBStride(const RGBDescriptor& aDescriptor);
 
-  ImageDataSerializerBase(uint8_t* aData, size_t aDataSize)
-    : mData(aData)
-    , mDataSize(aDataSize)
-    , mIsValid(false)
-  {}
+uint32_t ComputeRGBBufferSize(gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
 
-  void Validate();
 
-  uint8_t* mData;
-  size_t mDataSize;
-  bool mIsValid;
-};
+// YCbCr
 
-/**
- * A facility to serialize an image into a buffer of memory.
- * This is intended for use with the IPC code, in order to copy image data
- * into shared memory.
- * Note that there is a separate serializer class for YCbCr images
- * (see YCbCrImageDataSerializer.h).
- */
-class MOZ_STACK_CLASS ImageDataSerializer : public ImageDataSerializerBase
-{
-public:
-  ImageDataSerializer(uint8_t* aData, size_t aDataSize)
-    : ImageDataSerializerBase(aData, aDataSize)
-  {
-    // a serializer needs to be usable before correct buffer info has been written to it
-    mIsValid = !!mData;
-  }
-  void InitializeBufferInfo(gfx::IntSize aSize,
-                            gfx::SurfaceFormat aFormat);
-};
+///This function is meant as a helper to know how much shared memory we need
+///to allocate in a shmem in order to place a shared YCbCr image blob of
+///given dimensions.
+uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize,
+                                int32_t aYStride,
+                                const gfx::IntSize& aCbCrSize,
+                                int32_t aCbCrStride);
+uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize,
+                                const gfx::IntSize& aCbCrSize);
+
+uint32_t ComputeYCbCrBufferSize(uint32_t aBufferSize);
 
-/**
- * A facility to deserialize image data that has been serialized by an
- * ImageDataSerializer.
- */
-class MOZ_STACK_CLASS ImageDataDeserializer : public ImageDataSerializerBase
-{
-public:
-  ImageDataDeserializer(uint8_t* aData, size_t aDataSize)
-    : ImageDataSerializerBase(aData, aDataSize)
-  {
-    Validate();
-  }
+void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight,
+                         int32_t cbCrStride, int32_t cbCrHeight,
+                         uint32_t& outYOffset, uint32_t& outCbOffset, uint32_t& outCrOffset);
+
+gfx::SurfaceFormat FormatFromBufferDescriptor(const BufferDescriptor& aDescriptor);
+
+gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor);
 
-};
+uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
+
+uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
+
+uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
+
+already_AddRefed<gfx::DataSourceSurface>
+DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
+
+} // ImageDataSerializer
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
deleted file mode 100644
--- a/gfx/layers/YCbCrImageDataSerializer.cpp
+++ /dev/null
@@ -1,317 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; 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/layers/YCbCrImageDataSerializer.h"
-#include <string.h>                     // for memcpy
-#include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
-#include "mozilla/gfx/BaseSize.h"       // for BaseSize
-#include "mozilla/gfx/Logging.h"        // for gfxDebug
-#include "mozilla/gfx/Types.h"
-#include "mozilla/mozalloc.h"           // for operator delete
-#include "nsDebug.h"                    // for NS_WARN_IF
-#include "yuv_convert.h"                // for ConvertYCbCrToRGB32, etc
-#include "nsDebug.h"
-
-#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
-
-namespace mozilla {
-
-using namespace gfx;
-
-namespace layers {
-
-// The Data is layed out as follows:
-//
-//  +-----------------+   -++ --+ --+ <-- Beginning of the buffer
-//  | YCbCrBufferInfo |     |   |   |
-//  +-----------------+   --+   |   |
-//  |      data       |         |   | YCbCrBufferInfo->[mY/mCb/mCr]Offset
-//  +-----------------+   ------+   |
-//  |      data       |             |
-//  +-----------------+   ----------+
-//  |      data       |
-//  +-----------------+
-//
-// There can be padding between the blocks above to keep word alignment.
-
-// Structure written at the beginning og the data blob containing the image
-// (as shown in the figure above). It contains the necessary informations to
-// read the image in the blob.
-struct YCbCrBufferInfo
-{
-  uint32_t mYOffset;
-  uint32_t mCbOffset;
-  uint32_t mCrOffset;
-  uint32_t mYStride;
-  uint32_t mYWidth;
-  uint32_t mYHeight;
-  uint32_t mCbCrStride;
-  uint32_t mCbCrWidth;
-  uint32_t mCbCrHeight;
-  StereoMode mStereoMode;
-};
-
-static YCbCrBufferInfo* GetYCbCrBufferInfo(uint8_t* aData, size_t aDataSize)
-{
-  return aDataSize >= sizeof(YCbCrBufferInfo)
-         ? reinterpret_cast<YCbCrBufferInfo*>(aData)
-         : nullptr;
-}
-
-void YCbCrImageDataDeserializerBase::Validate()
-{
-  mIsValid = false;
-  if (!mData) {
-    return;
-  }
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  if (!info) {
-    return;
-  }
-  size_t requiredSize = ComputeMinBufferSize(
-                          IntSize(info->mYWidth, info->mYHeight),
-                          info->mYStride,
-                          IntSize(info->mCbCrWidth, info->mCbCrHeight),
-                          info->mCbCrStride);
-  mIsValid = requiredSize <= mDataSize;
-
-}
-
-uint8_t* YCbCrImageDataDeserializerBase::GetYData()
-{
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  return reinterpret_cast<uint8_t*>(info) + info->mYOffset;
-}
-
-uint8_t* YCbCrImageDataDeserializerBase::GetCbData()
-{
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  return reinterpret_cast<uint8_t*>(info) + info->mCbOffset;
-}
-
-uint8_t* YCbCrImageDataDeserializerBase::GetCrData()
-{
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  return reinterpret_cast<uint8_t*>(info) + info->mCrOffset;
-}
-
-uint8_t* YCbCrImageDataDeserializerBase::GetData()
-{
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  return (reinterpret_cast<uint8_t*>(info)) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
-}
-
-uint32_t YCbCrImageDataDeserializerBase::GetYStride()
-{
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  return info->mYStride;
-}
-
-uint32_t YCbCrImageDataDeserializerBase::GetCbCrStride()
-{
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  return info->mCbCrStride;
-}
-
-gfx::IntSize YCbCrImageDataDeserializerBase::GetYSize()
-{
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  return gfx::IntSize(info->mYWidth, info->mYHeight);
-}
-
-gfx::IntSize YCbCrImageDataDeserializerBase::GetCbCrSize()
-{
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  return gfx::IntSize(info->mCbCrWidth, info->mCbCrHeight);
-}
-
-StereoMode YCbCrImageDataDeserializerBase::GetStereoMode()
-{
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  return info->mStereoMode;
-}
-
-// Offset in bytes
-static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride)
-{
-  return MOZ_ALIGN_WORD(aHeight * aStride);
-}
-
-// Minimum required shmem size in bytes
-size_t
-YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize,
-                                                     uint32_t aYStride,
-                                                     const gfx::IntSize& aCbCrSize,
-                                                     uint32_t aCbCrStride)
-{
-  MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
-  if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 || aCbCrSize.width < 0) {
-    gfxDebug() << "Non-positive YCbCr buffer size request " << aYSize.height << "x" << aYSize.width << ", " << aCbCrSize.height << "x" << aCbCrSize.width;
-    return 0;
-  }
-
-  if (aYSize != IntSize() &&
-      (!gfx::Factory::AllowedSurfaceSize(aYSize) ||
-       aCbCrSize.width > aYSize.width ||
-       aCbCrSize.height > aYSize.height)) {
-    return 0;
-  }
-
-  return ComputeOffset(aYSize.height, aYStride)
-         + 2 * ComputeOffset(aCbCrSize.height, aCbCrStride)
-         + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
-}
-
-// Minimum required shmem size in bytes
-size_t
-YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize,
-                                                   const gfx::IntSize& aCbCrSize)
-{
-  return ComputeMinBufferSize(aYSize, aYSize.width, aCbCrSize, aCbCrSize.width);
-}
-
-// Offset in bytes
-static size_t ComputeOffset(uint32_t aSize)
-{
-  return MOZ_ALIGN_WORD(aSize);
-}
-
-// Minimum required shmem size in bytes
-size_t
-YCbCrImageDataDeserializerBase::ComputeMinBufferSize(uint32_t aSize)
-{
-  return ComputeOffset(aSize) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
-}
-
-void
-YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYOffset,
-                                               uint32_t aCbOffset,
-                                               uint32_t aCrOffset,
-                                               uint32_t aYStride,
-                                               uint32_t aCbCrStride,
-                                               const gfx::IntSize& aYSize,
-                                               const gfx::IntSize& aCbCrSize,
-                                               StereoMode aStereoMode)
-{
-  YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
-  MOZ_ASSERT(info); // OK to assert here, this method is client-side-only
-  uint32_t info_size = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
-  info->mYOffset = info_size + aYOffset;
-  info->mCbOffset = info_size + aCbOffset;
-  info->mCrOffset = info_size + aCrOffset;
-  info->mYStride = aYStride;
-  info->mYWidth = aYSize.width;
-  info->mYHeight = aYSize.height;
-  info->mCbCrStride = aCbCrStride;
-  info->mCbCrWidth = aCbCrSize.width;
-  info->mCbCrHeight = aCbCrSize.height;
-  info->mStereoMode = aStereoMode;
-  Validate();
-}
-
-void
-YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYStride,
-                                               uint32_t aCbCrStride,
-                                               const gfx::IntSize& aYSize,
-                                               const gfx::IntSize& aCbCrSize,
-                                               StereoMode aStereoMode)
-{
-  uint32_t yOffset = 0;
-  uint32_t cbOffset = yOffset + MOZ_ALIGN_WORD(aYStride * aYSize.height);
-  uint32_t crOffset = cbOffset + MOZ_ALIGN_WORD(aCbCrStride * aCbCrSize.height);
-  return InitializeBufferInfo(yOffset, cbOffset, crOffset,
-      aYStride, aCbCrStride, aYSize, aCbCrSize, aStereoMode);
-}
-
-void
-YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize,
-                                               const gfx::IntSize& aCbCrSize,
-                                               StereoMode aStereoMode)
-{
-  return InitializeBufferInfo(aYSize.width, aCbCrSize.width, aYSize, aCbCrSize, aStereoMode);
-}
-
-static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uint32_t skip) {
-  for (uint32_t i = 0; i < len; ++i) {
-    *dst = *src;
-    src += 1 + skip;
-    ++dst;
-  }
-}
-
-bool
-YCbCrImageDataSerializer::CopyData(const uint8_t* aYData,
-                                   const uint8_t* aCbData, const uint8_t* aCrData,
-                                   gfx::IntSize aYSize, uint32_t aYStride,
-                                   gfx::IntSize aCbCrSize, uint32_t aCbCrStride,
-                                   uint32_t aYSkip, uint32_t aCbCrSkip)
-{
-  if (!IsValid() || GetYSize() != aYSize || GetCbCrSize() != aCbCrSize) {
-    return false;
-  }
-  for (int i = 0; i < aYSize.height; ++i) {
-    if (aYSkip == 0) {
-      // fast path
-      memcpy(GetYData() + i * GetYStride(),
-             aYData + i * aYStride,
-             aYSize.width);
-    } else {
-      // slower path
-      CopyLineWithSkip(aYData + i * aYStride,
-                       GetYData() + i * GetYStride(),
-                       aYSize.width, aYSkip);
-    }
-  }
-  for (int i = 0; i < aCbCrSize.height; ++i) {
-    if (aCbCrSkip == 0) {
-      // fast path
-      memcpy(GetCbData() + i * GetCbCrStride(),
-             aCbData + i * aCbCrStride,
-             aCbCrSize.width);
-      memcpy(GetCrData() + i * GetCbCrStride(),
-             aCrData + i * aCbCrStride,
-             aCbCrSize.width);
-    } else {
-      // slower path
-      CopyLineWithSkip(aCbData + i * aCbCrStride,
-                       GetCbData() + i * GetCbCrStride(),
-                       aCbCrSize.width, aCbCrSkip);
-      CopyLineWithSkip(aCrData + i * aCbCrStride,
-                       GetCrData() + i * GetCbCrStride(),
-                       aCbCrSize.width, aCbCrSkip);
-    }
-  }
-  return true;
-}
-
-already_AddRefed<DataSourceSurface>
-YCbCrImageDataDeserializer::ToDataSourceSurface()
-{
-  RefPtr<DataSourceSurface> result =
-    Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8);
-  if (NS_WARN_IF(!result)) {
-    return nullptr;
-  }
-
-  DataSourceSurface::MappedSurface map;
-  if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
-    return nullptr;
-  }
-
-  gfx::YUVType type = TypeFromSize(GetYSize().width, GetYSize().height,
-                                   GetCbCrSize().width, GetCbCrSize().height);
-  gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(),
-                           map.mData,
-                           0, 0, //pic x and y
-                           GetYSize().width, GetYSize().height,
-                           GetYStride(), GetCbCrStride(),
-                           map.mStride, type);
-  result->Unmap();
-  return result.forget();
-}
-
-
-} // namespace layers
-} // namespace mozilla
deleted file mode 100644
--- a/gfx/layers/YCbCrImageDataSerializer.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; 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_LAYERS_BLOBYCBCRSURFACE_H
-#define MOZILLA_LAYERS_BLOBYCBCRSURFACE_H
-
-#include <stddef.h>                     // for size_t
-#include <stdint.h>                     // for uint8_t, uint32_t
-#include "ImageTypes.h"                 // for StereoMode
-#include "mozilla/Attributes.h"         // for MOZ_STACK_CLASS
-#include "mozilla/RefPtr.h"             // for already_AddRefed
-#include "mozilla/gfx/Point.h"          // for IntSize
-
-namespace mozilla {
-namespace gfx {
-class DataSourceSurface;
-} // namespace gfx
-
-namespace layers {
-
-class Image;
-
-/**
- * Convenience class to share code between YCbCrImageDataSerializer
- * and YCbCrImageDataDeserializer.
- * Do not use it.
- */
-class YCbCrImageDataDeserializerBase
-{
-public:
-  bool IsValid() const { return mIsValid; }
-
-  /**
-   * Returns the Y channel data pointer.
-   */
-  uint8_t* GetYData();
-  /**
-   * Returns the Cb channel data pointer.
-   */
-  uint8_t* GetCbData();
-  /**
-   * Returns the Cr channel data pointer.
-   */
-  uint8_t* GetCrData();
-
-  /**
-   * Returns the Y channel stride.
-   */
-  uint32_t GetYStride();
-  /**
-   * Returns the stride of the Cb and Cr channels.
-   */
-  uint32_t GetCbCrStride();
-
-  /**
-   * Returns the dimensions of the Y Channel.
-   */
-  gfx::IntSize GetYSize();
-
-  /**
-   * Returns the dimensions of the Cb and Cr Channel.
-   */
-  gfx::IntSize GetCbCrSize();
-
-  /**
-   * Stereo mode for the image.
-   */
-  StereoMode GetStereoMode();
-
-  /**
-   * Return a pointer to the begining of the data buffer.
-   */
-  uint8_t* GetData();
-
-  /**
-   * This function is meant as a helper to know how much shared memory we need
-   * to allocate in a shmem in order to place a shared YCbCr image blob of
-   * given dimensions.
-   */
-  static size_t ComputeMinBufferSize(const gfx::IntSize& aYSize,
-                                     uint32_t aYStride,
-                                     const gfx::IntSize& aCbCrSize,
-                                     uint32_t aCbCrStride);
-  static size_t ComputeMinBufferSize(const gfx::IntSize& aYSize,
-                                     const gfx::IntSize& aCbCrSize);
-  static size_t ComputeMinBufferSize(uint32_t aSize);
-
-protected:
-  YCbCrImageDataDeserializerBase(uint8_t* aData, size_t aDataSize)
-    : mData (aData)
-    , mDataSize(aDataSize)
-    , mIsValid(false)
-  {}
-
-  void Validate();
-
-  uint8_t* mData;
-  size_t mDataSize;
-  bool mIsValid;
-};
-
-/**
- * A view on a YCbCr image stored with its metadata in a blob of memory.
- * It is only meant as a convenience to access the image data, and does not own
- * the data. The instance can live on the stack and used as follows:
- *
- * const YCbCrImage& yuv = sharedImage.get_YCbCrImage();
- * YCbCrImageDataDeserializer deserializer(yuv.data().get<uint8_t>());
- * if (!deserializer.IsValid()) {
- *   // handle error
- * }
- * size = deserializer.GetYSize(); // work with the data, etc...
- */
-class MOZ_STACK_CLASS YCbCrImageDataSerializer : public YCbCrImageDataDeserializerBase
-{
-public:
-  YCbCrImageDataSerializer(uint8_t* aData, size_t aDataSize)
-    : YCbCrImageDataDeserializerBase(aData, aDataSize)
-  {
-    // a serializer needs to be usable before correct buffer info has been written to it
-    mIsValid = !!mData;
-  }
-
-  /**
-   * Write the image informations in the buffer for given dimensions.
-   * The provided pointer should point to the beginning of the (chunk of)
-   * buffer on which we want to store the image.
-   */
-  void InitializeBufferInfo(uint32_t aYOffset,
-                            uint32_t aCbOffset,
-                            uint32_t aCrOffset,
-                            uint32_t aYStride,
-                            uint32_t aCbCrStride,
-                            const gfx::IntSize& aYSize,
-                            const gfx::IntSize& aCbCrSize,
-                            StereoMode aStereoMode);
-  void InitializeBufferInfo(uint32_t aYStride,
-                            uint32_t aCbCrStride,
-                            const gfx::IntSize& aYSize,
-                            const gfx::IntSize& aCbCrSize,
-                            StereoMode aStereoMode);
-  void InitializeBufferInfo(const gfx::IntSize& aYSize,
-                            const gfx::IntSize& aCbCrSize,
-                            StereoMode aStereoMode);
-  bool CopyData(const uint8_t* aYData,
-                const uint8_t* aCbData, const uint8_t* aCrData,
-                gfx::IntSize aYSize, uint32_t aYStride,
-                gfx::IntSize aCbCrSize, uint32_t aCbCrStride,
-                uint32_t aYSkip, uint32_t aCbCrSkip);
-};
-
-/**
- * A view on a YCbCr image stored with its metadata in a blob of memory.
- * It is only meant as a convenience to access the image data, and does not own
- * the data. The instance can live on the stack and used as follows:
- *
- * const YCbCrImage& yuv = sharedImage.get_YCbCrImage();
- * YCbCrImageDataDeserializer deserializer(yuv.data().get<uint8_t>());
- * if (!deserializer.IsValid()) {
- *   // handle error
- * }
- * size = deserializer.GetYSize(); // work with the data, etc...
- */
-class MOZ_STACK_CLASS YCbCrImageDataDeserializer : public YCbCrImageDataDeserializerBase
-{
-public:
-  YCbCrImageDataDeserializer(uint8_t* aData, size_t aDataSize)
-    : YCbCrImageDataDeserializerBase(aData, aDataSize)
-  {
-    Validate();
-  }
-
-  /**
-   * Convert the YCbCr data into RGB and return a DataSourceSurface.
-   * This is a costly operation, so use it only when YCbCr compositing is
-   * not supported.
-   */
-  already_AddRefed<gfx::DataSourceSurface> ToDataSourceSurface();
-};
-
-} // namespace layers
-} // namespace mozilla
-
-#endif
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -23,17 +23,16 @@
 #include "mozilla/mozalloc.h"           // for operator new
 #include "mozilla/TouchEvents.h"
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/EventStateManager.h"  // for WheelPrefs
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsThreadUtils.h"              // for NS_IsMainThread
 #include "OverscrollHandoffState.h"     // for OverscrollHandoffState
-#include "TaskThrottler.h"              // for TaskThrottler
 #include "TreeTraversal.h"              // for generic tree traveral algorithms
 #include "LayersLogging.h"              // for Stringify
 #include "Units.h"                      // for ParentlayerPixel
 #include "GestureEventListener.h"       // for GestureEventListener::setLongTapEnabled
 #include "UnitTransforms.h"             // for ViewAs
 
 #define ENABLE_APZCTM_LOGGING 0
 // #define ENABLE_APZCTM_LOGGING 1
@@ -81,21 +80,20 @@ struct APZCTreeManager::TreeBuildingStat
   // to facilitate re-using the same APZC for different layers that scroll
   // together (and thus have the same ScrollableLayerGuid).
   std::map<ScrollableLayerGuid, AsyncPanZoomController*> mApzcMap;
 };
 
 /*static*/ const ScreenMargin
 APZCTreeManager::CalculatePendingDisplayPort(
   const FrameMetrics& aFrameMetrics,
-  const ParentLayerPoint& aVelocity,
-  double aEstimatedPaintDuration)
+  const ParentLayerPoint& aVelocity)
 {
   return AsyncPanZoomController::CalculatePendingDisplayPort(
-    aFrameMetrics, aVelocity, aEstimatedPaintDuration);
+    aFrameMetrics, aVelocity);
 }
 
 APZCTreeManager::APZCTreeManager()
     : mInputQueue(new InputQueue()),
       mTreeLock("APZCTreeLock"),
       mHitResultForInputBlock(HitNothing),
       mRetainedTouchIdentifier(-1),
       mApzcTreeLog("apzctree")
@@ -106,21 +104,20 @@ APZCTreeManager::APZCTreeManager()
 }
 
 APZCTreeManager::~APZCTreeManager()
 {
 }
 
 AsyncPanZoomController*
 APZCTreeManager::NewAPZCInstance(uint64_t aLayersId,
-                                 GeckoContentController* aController,
-                                 TaskThrottler* aPaintThrottler)
+                                 GeckoContentController* aController)
 {
   return new AsyncPanZoomController(aLayersId, this, mInputQueue,
-    aController, aPaintThrottler, AsyncPanZoomController::USE_GESTURE_DETECTOR);
+    aController, AsyncPanZoomController::USE_GESTURE_DETECTOR);
 }
 
 TimeStamp
 APZCTreeManager::GetFrameTime()
 {
   return TimeStamp::Now();
 }
 
@@ -196,42 +193,16 @@ APZCTreeManager::UpdateHitTestingTree(Co
 
 #if ENABLE_APZCTM_LOGGING
   // Make the hit-test tree line up with the layer dump
   printf_stderr("APZCTreeManager (%p)\n", this);
   mRootNode->Dump("  ");
 #endif
 }
 
-void
-APZCTreeManager::InitializeForLayersId(uint64_t aLayersId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  auto throttlerInsertResult = mPaintThrottlerMap.insert(
-    std::make_pair(aLayersId, RefPtr<TaskThrottler>()));
-  if (throttlerInsertResult.second) {
-    throttlerInsertResult.first->second = new TaskThrottler(
-      GetFrameTime(), TimeDuration::FromMilliseconds(500));
-  }
-}
-
-void
-APZCTreeManager::AdoptLayersId(uint64_t aLayersId, APZCTreeManager* aOldManager)
-{
-  MOZ_ASSERT(aOldManager);
-  if (aOldManager == this) {
-    return;
-  }
-  auto iter = aOldManager->mPaintThrottlerMap.find(aLayersId);
-  if (iter != aOldManager->mPaintThrottlerMap.end()) {
-    mPaintThrottlerMap[aLayersId] = iter->second;
-    aOldManager->mPaintThrottlerMap.erase(iter);
-  }
-}
-
 // Compute the clip region to be used for a layer with an APZC. This function
 // is only called for layers which actually have scrollable metrics and an APZC.
 static ParentLayerIntRegion
 ComputeClipRegion(GeckoContentController* aController,
                   const LayerMetricsWrapper& aLayer)
 {
   ParentLayerIntRegion clipRegion;
   if (aLayer.GetClipRect()) {
@@ -457,22 +428,17 @@ APZCTreeManager::PrepareNodeForLayer(con
     }
 
     // The APZC we get off the layer may have been destroyed previously if the
     // layer was inactive or omitted from the layer tree for whatever reason
     // from a layers update. If it later comes back it will have a reference to
     // a destroyed APZC and so we need to throw that out and make a new one.
     bool newApzc = (apzc == nullptr || apzc->IsDestroyed());
     if (newApzc) {
-      // Look up the paint throttler for this layers id, or create it if
-      // this is the first APZC for this layers id.
-      RefPtr<TaskThrottler> throttler = mPaintThrottlerMap[aLayersId];
-      MOZ_ASSERT(throttler);
-
-      apzc = NewAPZCInstance(aLayersId, state->mController, throttler);
+      apzc = NewAPZCInstance(aLayersId, state->mController);
       apzc->SetCompositorParent(aState.mCompositor);
       if (state->mCrossProcessParent != nullptr) {
         apzc->ShareFrameMetricsAcrossProcesses();
       }
       MOZ_ASSERT(node == nullptr);
       node = new HitTestingTreeNode(apzc, true, aLayersId);
     } else {
       // If we are re-using a node for this layer clear the tree pointers
@@ -652,33 +618,20 @@ WillHandleInput(const PanGestureOrScroll
 
   WidgetWheelEvent wheelEvent = aPanInput.ToWidgetWheelEvent(nullptr);
   return WillHandleWheelEvent(&wheelEvent);
 }
 
 void
 APZCTreeManager::FlushApzRepaints(uint64_t aLayersId)
 {
+  // Previously, paints were throttled and therefore this method was used to
+  // ensure any pending paints were flushed. Now, paints are flushed
+  // immediately, so it is safe to simply send a notification now.
   APZCTM_LOG("Flushing repaints for layers id %" PRIu64, aLayersId);
-  { // scope lock
-    MonitorAutoLock lock(mTreeLock);
-    mTreeLock.AssertCurrentThreadOwns();
-
-    ForEachNode(mRootNode.get(),
-        [aLayersId](HitTestingTreeNode* aNode)
-        {
-          if (aNode->IsPrimaryHolder()) {
-            AsyncPanZoomController* apzc = aNode->GetApzc();
-            MOZ_ASSERT(apzc);
-            if (apzc->GetGuid().mLayersId == aLayersId) {
-              apzc->FlushRepaintIfPending();
-            }
-          }
-        });
-  }
   const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
   MOZ_ASSERT(state && state->mController);
   NS_DispatchToMainThread(NS_NewRunnableMethod(
     state->mController.get(), &GeckoContentController::NotifyFlushComplete));
 }
 
 nsEventStatus
 APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -47,17 +47,16 @@ class AsyncPanZoomController;
 class CompositorParent;
 class OverscrollHandoffChain;
 struct OverscrollHandoffState;
 struct FlingHandoffState;
 class LayerMetricsWrapper;
 class InputQueue;
 class GeckoContentController;
 class HitTestingTreeNode;
-class TaskThrottler;
 
 /**
  * ****************** NOTE ON LOCK ORDERING IN APZ **************************
  *
  * There are two kinds of locks used by APZ: APZCTreeManager::mTreeLock
  * ("the tree lock") and AsyncPanZoomController::mMonitor ("APZC locks").
  *
  * To avoid deadlock, we impose a lock ordering between these locks, which is:
@@ -133,27 +132,16 @@ public:
    */
   void UpdateHitTestingTree(CompositorParent* aCompositor,
                             Layer* aRoot,
                             bool aIsFirstPaint,
                             uint64_t aOriginatingLayersId,
                             uint32_t aPaintSequenceNumber);
 
   /**
-   * Do any per-layers-id setup needed. This will be called on the main thread,
-   * and may be called multiple times for the same layers id.
-   */
-  void InitializeForLayersId(uint64_t aLayersId);
-
-  /**
-   * Move any per-layers-id state from the old APZCTreeManager to this one.
-   */
-  void AdoptLayersId(uint64_t aLayersId, APZCTreeManager* aOldManager);
-
-  /**
    * Walk the tree of APZCs and flushes the repaint requests for all the APZCS
    * corresponding to the given layers id. Finally, sends a flush complete
    * notification to the GeckoContentController for the layers id.
    */
   void FlushApzRepaints(uint64_t aLayersId);
 
   /**
    * General handler for incoming input events. Manipulates the frame metrics
@@ -281,18 +269,17 @@ public:
 
   /**
    * See AsyncPanZoomController::CalculatePendingDisplayPort. This
    * function simply delegates to that one, so that non-layers code
    * never needs to include AsyncPanZoomController.h
    */
   static const ScreenMargin CalculatePendingDisplayPort(
     const FrameMetrics& aFrameMetrics,
-    const ParentLayerPoint& aVelocity,
-    double aEstimatedPaintDuration);
+    const ParentLayerPoint& aVelocity);
 
   /**
    * Set the dpi value used by all AsyncPanZoomControllers.
    * DPI defaults to 72 if not set using SetDPI() at any point.
    */
   static void SetDPI(float aDpiValue) { sDPI = aDpiValue; }
 
   /**
@@ -415,18 +402,17 @@ public:
   static void SetLongTapEnabled(bool aTapGestureEnabled);
 
 protected:
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~APZCTreeManager();
 
   // Protected hooks for gtests subclass
   virtual AsyncPanZoomController* NewAPZCInstance(uint64_t aLayersId,
-                                                  GeckoContentController* aController,
-                                                  TaskThrottler* aPaintThrottler);
+                                                  GeckoContentController* aController);
 public:
   // Public hooks for gtests subclass
   virtual TimeStamp GetFrameTime();
 
 public:
   /* Some helper functions to find an APZC given some identifying input. These functions
      lock the tree of APZCs while they find the right one, and then return an addref'd
      pointer to it. This allows caller code to just use the target APZC without worrying
@@ -531,20 +517,16 @@ private:
    * is considered part of the APZC tree management state.
    * Finally, the lock needs to be held when accessing mZoomConstraints.
    * IMPORTANT: See the note about lock ordering at the top of this file. */
   mutable mozilla::Monitor mTreeLock;
   RefPtr<HitTestingTreeNode> mRootNode;
   /* Holds the zoom constraints for scrollable layers, as determined by the
    * the main-thread gecko code. */
   std::map<ScrollableLayerGuid, ZoomConstraints> mZoomConstraints;
-  /* Stores a paint throttler for each layers id. There is one for each layers
-   * id to ensure that one child process painting slowly doesn't hold up
-   * another. */
-  std::map<uint64_t, RefPtr<TaskThrottler>> mPaintThrottlerMap;
   /* This tracks the APZC that should receive all inputs for the current input event block.
    * This allows touch points to move outside the thing they started on, but still have the
    * touch events delivered to the same initial APZC. This will only ever be touched on the
    * input delivery thread, and so does not require locking.
    */
   RefPtr<AsyncPanZoomController> mApzcForInputBlock;
   /* The hit result for the current input event block; this should always be in
    * sync with mApzcForInputBlock.
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -13,17 +13,16 @@
 #include "Compositor.h"                 // for Compositor
 #include "FrameMetrics.h"               // for FrameMetrics, etc
 #include "GestureEventListener.h"       // for GestureEventListener
 #include "HitTestingTreeNode.h"         // for HitTestingTreeNode
 #include "InputData.h"                  // for MultiTouchInput, etc
 #include "InputBlockState.h"            // for InputBlockState, TouchBlockState
 #include "InputQueue.h"                 // for InputQueue
 #include "OverscrollHandoffState.h"     // for OverscrollHandoffState
-#include "TaskThrottler.h"              // for TaskThrottler
 #include "Units.h"                      // for CSSRect, CSSPoint, etc
 #include "UnitTransforms.h"             // for TransformTo
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/task.h"                  // for NewRunnableMethod, etc
 #include "base/tracked.h"               // for FROM_HERE
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxTypes.h"                   // for gfxFloat
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
@@ -234,19 +233,16 @@ using mozilla::gfx::PointTyped;
  * On touch end we calculate the average velocity in order to compensate
  * touch/mouse drivers misbehaviour.
  *
  * \li\b apz.min_skate_speed
  * Minimum amount of speed along an axis before we switch to "skate" multipliers
  * rather than using the "stationary" multipliers.\n
  * Units: CSS pixels per millisecond
  *
- * \li\b apz.num_paint_duration_samples
- * Number of samples to store of how long it took to paint after the previous
- *
  * \li\b apz.overscroll.enabled
  * Pref that enables overscrolling. If this is disabled, excess scroll that
  * cannot be handed off is discarded.
  *
  * \li\b apz.overscroll.min_pan_distance_ratio
  * The minimum ratio of the pan distance along one axis to the pan distance
  * along the other axis needed to initiate overscroll along the first axis
  * during panning.
@@ -298,22 +294,16 @@ using mozilla::gfx::PointTyped;
  * \li\b apz.touch_start_tolerance
  * Constant describing the tolerance in distance we use, multiplied by the
  * device DPI, before we start panning the screen. This is to prevent us from
  * accidentally processing taps as touch moves, and from very short/accidental
  * touches moving the screen. touchmove events are also not delivered to content
  * within this distance on scrollable frames.\n
  * Units: (real-world, i.e. screen) inches
  *
- * \li\b apz.use_paint_duration
- * Whether or not to use the estimated paint duration as a factor when projecting
- * the displayport in the direction of scrolling. If this value is set to false,
- * a constant 50ms paint time is used; the projection can be scaled as desired
- * using the \b apz.velocity_bias pref below.
- *
  * \li\b apz.velocity_bias
  * How much to adjust the displayport in the direction of scrolling. This value
  * is multiplied by the velocity and added to the displayport offset.
  *
  * \li\b apz.velocity_relevance_time_ms
  * When computing a fling velocity from the most recently stored velocity
  * information, only velocities within the most X milliseconds are used.
  * This pref controls the value of X.\n
@@ -352,16 +342,22 @@ using mozilla::gfx::PointTyped;
 StaticAutoPtr<ComputedTimingFunction> gZoomAnimationFunction;
 
 /**
  * Computed time function used for curving up velocity when it gets high.
  */
 StaticAutoPtr<ComputedTimingFunction> gVelocityCurveFunction;
 
 /**
+ * The estimated duration of a paint for the purposes of calculating a new
+ * displayport, in milliseconds.
+ */
+static const double kDefaultEstimatedPaintDurationMs = 50;
+
+/**
  * Returns true if this is a high memory system and we can use
  * extra memory for a larger displayport to reduce checkerboarding.
  */
 static bool gIsHighMemSystem = false;
 static bool IsHighMemSystem()
 {
   return gIsHighMemSystem;
 }
@@ -846,20 +842,18 @@ AsyncPanZoomController::InitializeGlobal
   uint64_t threshold = 1LL << 32; // 4 GB in bytes
   gIsHighMemSystem = sysmem >= threshold;
 }
 
 AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
                                                APZCTreeManager* aTreeManager,
                                                const RefPtr<InputQueue>& aInputQueue,
                                                GeckoContentController* aGeckoContentController,
-                                               TaskThrottler* aPaintThrottler,
                                                GestureBehavior aGestures)
   :  mLayersId(aLayersId),
-     mPaintThrottler(aPaintThrottler),
      mGeckoContentController(aGeckoContentController),
      mRefPtrMonitor("RefPtrMonitor"),
      // mTreeManager must be initialized before GetFrameTime() is called
      mTreeManager(aTreeManager),
      mSharingFrameMetricsAcrossProcesses(false),
      mMonitor("AsyncPanZoomController"),
      mX(this),
      mY(this),
@@ -2690,35 +2684,39 @@ RedistributeDisplayPortExcess(CSSSize& a
     aDisplayPortSize.height *= (aDisplayPortSize.width / aScrollableRect.width);
     aDisplayPortSize.width = aScrollableRect.width;
   }
 }
 
 /* static */
 const ScreenMargin AsyncPanZoomController::CalculatePendingDisplayPort(
   const FrameMetrics& aFrameMetrics,
-  const ParentLayerPoint& aVelocity,
-  double aEstimatedPaintDuration)
+  const ParentLayerPoint& aVelocity)
 {
+  if (aFrameMetrics.IsScrollInfoLayer()) {
+    // Don't compute margins. Since we can't asynchronously scroll this frame,
+    // we don't want to paint anything more than the composition bounds.
+    return ScreenMargin();
+  }
+
   CSSSize compositionSize = aFrameMetrics.CalculateBoundedCompositedSizeInCssPixels();
   CSSPoint velocity = aVelocity / aFrameMetrics.GetZoom();
   CSSPoint scrollOffset = aFrameMetrics.GetScrollOffset();
   CSSRect scrollableRect = aFrameMetrics.GetExpandedScrollableRect();
 
   // Calculate the displayport size based on how fast we're moving along each axis.
   CSSSize displayPortSize = CalculateDisplayPortSize(compositionSize, velocity);
 
   if (gfxPrefs::APZEnlargeDisplayPortWhenClipped()) {
     RedistributeDisplayPortExcess(displayPortSize, scrollableRect);
   }
 
   // Offset the displayport, depending on how fast we're moving and the
   // estimated time it takes to paint, to try to minimise checkerboarding.
-  float estimatedPaintDurationMillis = (float)(aEstimatedPaintDuration * 1000.0);
-  float paintFactor = (gfxPrefs::APZUsePaintDuration() ? estimatedPaintDurationMillis : 50.0f);
+  float paintFactor = kDefaultEstimatedPaintDurationMs;
   CSSRect displayPort = CSSRect(scrollOffset + (velocity * paintFactor * gfxPrefs::APZVelocityBias()),
                                 displayPortSize);
 
   // Re-center the displayport based on its expansion over the composition size.
   displayPort.MoveBy((compositionSize.width - displayPort.width)/2.0f,
                      (compositionSize.height - displayPort.height)/2.0f);
 
   // Make sure the displayport remains within the scrollable rect.
@@ -2741,52 +2739,33 @@ const ScreenMargin AsyncPanZoomControlle
 void AsyncPanZoomController::ScheduleComposite() {
   if (mCompositorParent) {
     mCompositorParent->ScheduleRenderOnCompositorThread();
   }
 }
 
 void AsyncPanZoomController::ScheduleCompositeAndMaybeRepaint() {
   ScheduleComposite();
-
-  TimeDuration timePaintDelta = mPaintThrottler->TimeSinceLastRequest(GetFrameTime());
-  if (timePaintDelta.ToMilliseconds() > gfxPrefs::APZPanRepaintInterval()) {
-    RequestContentRepaint();
-  }
+  RequestContentRepaint();
 }
 
 void AsyncPanZoomController::FlushRepaintForOverscrollHandoff() {
   ReentrantMonitorAutoEnter lock(mMonitor);
   RequestContentRepaint();
   UpdateSharedCompositorFrameMetrics();
 }
 
 void AsyncPanZoomController::FlushRepaintForNewInputBlock() {
   APZC_LOG("%p flushing repaint for new input block\n", this);
 
   ReentrantMonitorAutoEnter lock(mMonitor);
-  // We need to send a new repaint request unthrottled, but that
-  // will obsolete any pending repaint request in the paint throttler.
-  // Therefore we should clear out the pending task and restore the
-  // state of mLastPaintRequestMetrics to what it was before the
-  // pending task was queued.
-  mPaintThrottler->CancelPendingTask();
-  mLastPaintRequestMetrics = mLastDispatchedPaintMetrics;
-
-  RequestContentRepaint(mFrameMetrics, false /* not throttled */);
+  RequestContentRepaint(mFrameMetrics);
   UpdateSharedCompositorFrameMetrics();
 }
 
-void AsyncPanZoomController::FlushRepaintIfPending() {
-  // Just tell the paint throttler to send the pending repaint request if
-  // there is one.
-  ReentrantMonitorAutoEnter lock(mMonitor);
-  mPaintThrottler->TaskComplete(GetFrameTime());
-}
-
 bool AsyncPanZoomController::SnapBackIfOverscrolled() {
   ReentrantMonitorAutoEnter lock(mMonitor);
   // It's possible that we're already in the middle of an overscroll
   // animation - if so, don't start a new one.
   if (IsOverscrolled() && mState != OVERSCROLL_ANIMATION) {
     APZC_LOG("%p is overscrolled, starting snap-back\n", this);
     StartOverscrollAnimation(ParentLayerPoint(0, 0));
     return true;
@@ -2819,21 +2798,18 @@ int32_t AsyncPanZoomController::GetLastT
   RefPtr<GestureEventListener> listener = GetGestureEventListener();
   return listener ? listener->GetLastTouchIdentifier() : -1;
 }
 
 void AsyncPanZoomController::RequestContentRepaint() {
   RequestContentRepaint(mFrameMetrics);
 }
 
-void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics, bool aThrottled) {
-  aFrameMetrics.SetDisplayPortMargins(
-    CalculatePendingDisplayPort(aFrameMetrics,
-                                GetVelocityVector(),
-                                mPaintThrottler->AverageDuration().ToSeconds()));
+void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics) {
+  aFrameMetrics.SetDisplayPortMargins(CalculatePendingDisplayPort(aFrameMetrics, GetVelocityVector()));
   aFrameMetrics.SetUseDisplayPortMargins();
 
   // If we're trying to paint what we already think is painted, discard this
   // request since it's a pointless paint.
   ScreenMargin marginDelta = (mLastPaintRequestMetrics.GetDisplayPortMargins()
                            - aFrameMetrics.GetDisplayPortMargins());
   if (fabsf(marginDelta.left) < EPSILON &&
       fabsf(marginDelta.top) < EPSILON &&
@@ -2847,57 +2823,49 @@ void AsyncPanZoomController::RequestCont
       fabsf(aFrameMetrics.GetViewport().width -
             mLastPaintRequestMetrics.GetViewport().width) < EPSILON &&
       fabsf(aFrameMetrics.GetViewport().height -
             mLastPaintRequestMetrics.GetViewport().height) < EPSILON &&
       aFrameMetrics.GetScrollGeneration() == mLastPaintRequestMetrics.GetScrollGeneration()) {
     return;
   }
 
-  if (aThrottled) {
-    mPaintThrottler->PostTask(
-      FROM_HERE,
-      UniquePtr<CancelableTask>(NewRunnableMethod(this,
-                        &AsyncPanZoomController::DispatchRepaintRequest,
-                        aFrameMetrics)),
-      GetFrameTime());
-  } else {
-    DispatchRepaintRequest(aFrameMetrics);
-  }
-
+  DispatchRepaintRequest(aFrameMetrics);
   aFrameMetrics.SetPresShellId(mLastContentPaintMetrics.GetPresShellId());
-  mLastPaintRequestMetrics = aFrameMetrics;
 }
 
 /*static*/ CSSRect
 GetDisplayPortRect(const FrameMetrics& aFrameMetrics)
 {
   // This computation is based on what happens in CalculatePendingDisplayPort. If that
   // changes then this might need to change too
   CSSRect baseRect(aFrameMetrics.GetScrollOffset(),
                    aFrameMetrics.CalculateBoundedCompositedSizeInCssPixels());
   baseRect.Inflate(aFrameMetrics.GetDisplayPortMargins() / aFrameMetrics.DisplayportPixelsPerCSSPixel());
   return baseRect;
 }
 
 void
 AsyncPanZoomController::DispatchRepaintRequest(const FrameMetrics& aFrameMetrics) {
   RefPtr<GeckoContentController> controller = GetGeckoContentController();
-  if (controller) {
-    APZC_LOG_FM(aFrameMetrics, "%p requesting content repaint", this);
-    LogRendertraceRect(GetGuid(), "requested displayport", "yellow", GetDisplayPortRect(aFrameMetrics));
-
-    if (NS_IsMainThread()) {
-      controller->RequestContentRepaint(aFrameMetrics);
-    } else {
-      NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<FrameMetrics>(
-        controller, &GeckoContentController::RequestContentRepaint, aFrameMetrics));
-    }
-    mLastDispatchedPaintMetrics = aFrameMetrics;
+  if (!controller) {
+    return;
   }
+
+  APZC_LOG_FM(aFrameMetrics, "%p requesting content repaint", this);
+  LogRendertraceRect(GetGuid(), "requested displayport", "yellow", GetDisplayPortRect(aFrameMetrics));
+
+  if (NS_IsMainThread()) {
+    controller->RequestContentRepaint(aFrameMetrics);
+  } else {
+    NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<FrameMetrics>(
+      controller, &GeckoContentController::RequestContentRepaint, aFrameMetrics));
+  }
+  mExpectedGeckoMetrics = aFrameMetrics;
+  mLastPaintRequestMetrics = aFrameMetrics;
 }
 
 bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
                                              Vector<Task*>* aOutDeferredTasks)
 {
   APZThreadUtils::AssertOnCompositorThread();
 
   // This function may get called multiple with the same sample time, because
@@ -2908,26 +2876,21 @@ bool AsyncPanZoomController::UpdateAnima
     return false;
   }
   TimeDuration sampleTimeDelta = aSampleTime - mLastSampleTime;
   mLastSampleTime = aSampleTime;
 
   if (mAnimation) {
     bool continueAnimation = mAnimation->Sample(mFrameMetrics, sampleTimeDelta);
     *aOutDeferredTasks = mAnimation->TakeDeferredTasks();
-    if (continueAnimation) {
-      if (mPaintThrottler->TimeSinceLastRequest(aSampleTime) >
-          mAnimation->mRepaintInterval) {
-        RequestContentRepaint();
-      }
-    } else {
+    if (!continueAnimation) {
       mAnimation = nullptr;
       SetState(NOTHING);
-      RequestContentRepaint();
     }
+    RequestContentRepaint();
     UpdateSharedCompositorFrameMetrics();
     return true;
   }
   return false;
 }
 
 Matrix4x4 AsyncPanZoomController::GetOverscrollTransform() const {
   ReentrantMonitorAutoEnter lock(mMonitor);
@@ -3066,27 +3029,27 @@ ViewTransform AsyncPanZoomController::Ge
 Matrix4x4 AsyncPanZoomController::GetCurrentAsyncTransformWithOverscroll() const {
   return Matrix4x4(GetCurrentAsyncTransform()) * GetOverscrollTransform();
 }
 
 Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() const {
   ReentrantMonitorAutoEnter lock(mMonitor);
 
   LayerPoint scrollChange =
-    (mLastContentPaintMetrics.GetScrollOffset() - mLastDispatchedPaintMetrics.GetScrollOffset())
+    (mLastContentPaintMetrics.GetScrollOffset() - mExpectedGeckoMetrics.GetScrollOffset())
     * mLastContentPaintMetrics.GetDevPixelsPerCSSPixel()
     * mLastContentPaintMetrics.GetCumulativeResolution();
 
   // We're interested in the async zoom change. Factor out the content scale
   // that may change when dragging the window to a monitor with a different
   // content scale.
   LayoutDeviceToParentLayerScale2D lastContentZoom =
     mLastContentPaintMetrics.GetZoom() / mLastContentPaintMetrics.GetDevPixelsPerCSSPixel();
   LayoutDeviceToParentLayerScale2D lastDispatchedZoom =
-    mLastDispatchedPaintMetrics.GetZoom() / mLastDispatchedPaintMetrics.GetDevPixelsPerCSSPixel();
+    mExpectedGeckoMetrics.GetZoom() / mExpectedGeckoMetrics.GetDevPixelsPerCSSPixel();
   gfxSize zoomChange = lastContentZoom / lastDispatchedZoom;
 
   return Matrix4x4::Translation(scrollChange.x, scrollChange.y, 0).
            PostScale(zoomChange.width, zoomChange.height, 1);
 }
 
 uint32_t
 AsyncPanZoomController::GetCheckerboardMagnitude() const
@@ -3154,17 +3117,16 @@ void AsyncPanZoomController::NotifyLayer
   LogRendertraceRect(GetGuid(), "page", "brown", aLayerMetrics.GetScrollableRect());
   LogRendertraceRect(GetGuid(), "painted displayport", "lightgreen",
     aLayerMetrics.GetDisplayPort() + aLayerMetrics.GetScrollOffset());
   if (!aLayerMetrics.GetCriticalDisplayPort().IsEmpty()) {
     LogRendertraceRect(GetGuid(), "painted critical displayport", "darkgreen",
       aLayerMetrics.GetCriticalDisplayPort() + aLayerMetrics.GetScrollOffset());
   }
 
-  mPaintThrottler->TaskComplete(GetFrameTime());
   bool needContentRepaint = false;
   bool viewportUpdated = false;
   if (FuzzyEqualsAdditive(aLayerMetrics.GetCompositionBounds().width, mFrameMetrics.GetCompositionBounds().width) &&
       FuzzyEqualsAdditive(aLayerMetrics.GetCompositionBounds().height, mFrameMetrics.GetCompositionBounds().height)) {
     // Remote content has sync'd up to the composition geometry
     // change, so we can accept the viewport it's calculated.
     if (mFrameMetrics.GetViewport().width != aLayerMetrics.GetViewport().width ||
         mFrameMetrics.GetViewport().height != aLayerMetrics.GetViewport().height) {
@@ -3185,26 +3147,23 @@ void AsyncPanZoomController::NotifyLayer
        && (aLayerMetrics.GetScrollGeneration() != mFrameMetrics.GetScrollGeneration());
 
   // TODO if we're in a drag and scrollOffsetUpdated is set then we want to
   // ignore it
 
   if (aIsFirstPaint || isDefault) {
     // Initialize our internal state to something sane when the content
     // that was just painted is something we knew nothing about previously
-    mPaintThrottler->ClearHistory();
-    mPaintThrottler->SetMaxDurations(gfxPrefs::APZNumPaintDurationSamples());
-
     CancelAnimation();
 
     mFrameMetrics = aLayerMetrics;
     if (scrollOffsetUpdated) {
       AcknowledgeScrollUpdate();
     }
-    mLastDispatchedPaintMetrics = aLayerMetrics;
+    mExpectedGeckoMetrics = aLayerMetrics;
     ShareCompositorFrameMetrics();
 
     if (mFrameMetrics.GetDisplayPortMargins() != ScreenMargin()) {
       // A non-zero display port margin here indicates a displayport has
       // been set by a previous APZC for the content at this guid. The
       // scrollable rect may have changed since then, making the margins
       // wrong, so we need to calculate a new display port.
       APZC_LOG("%p detected non-empty margins which probably need updating\n", this);
@@ -3247,32 +3206,33 @@ void AsyncPanZoomController::NotifyLayer
     mFrameMetrics.SetCumulativeResolution(aLayerMetrics.GetCumulativeResolution());
     mFrameMetrics.SetHasScrollgrab(aLayerMetrics.GetHasScrollgrab());
     mFrameMetrics.SetLineScrollAmount(aLayerMetrics.GetLineScrollAmount());
     mFrameMetrics.SetPageScrollAmount(aLayerMetrics.GetPageScrollAmount());
     mFrameMetrics.SetClipRect(aLayerMetrics.GetClipRect());
     mFrameMetrics.SetMaskLayerIndex(aLayerMetrics.GetMaskLayerIndex());
     mFrameMetrics.SetIsLayersIdRoot(aLayerMetrics.IsLayersIdRoot());
     mFrameMetrics.SetUsesContainerScrolling(aLayerMetrics.UsesContainerScrolling());
+    mFrameMetrics.SetIsScrollInfoLayer(aLayerMetrics.IsScrollInfoLayer());
 
     if (scrollOffsetUpdated) {
       APZC_LOG("%p updating scroll offset from %s to %s\n", this,
         ToString(mFrameMetrics.GetScrollOffset()).c_str(),
         ToString(aLayerMetrics.GetScrollOffset()).c_str());
 
       // Send an acknowledgement with the new scroll generation so that any
       // repaint requests later in this function go through.
       // Because of the scroll generation update, any inflight paint requests are
-      // going to be ignored by layout, and so mLastDispatchedPaintMetrics
+      // going to be ignored by layout, and so mExpectedGeckoMetrics
       // becomes incorrect for the purposes of calculating the LD transform. To
-      // correct this we need to update mLastDispatchedPaintMetrics to be the
+      // correct this we need to update mExpectedGeckoMetrics to be the
       // last thing we know was painted by Gecko.
       mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics);
       AcknowledgeScrollUpdate();
-      mLastDispatchedPaintMetrics = aLayerMetrics;
+      mExpectedGeckoMetrics = aLayerMetrics;
 
       // Cancel the animation (which might also trigger a repaint request)
       // after we update the scroll offset above. Otherwise we can be left
       // in a state where things are out of sync.
       CancelAnimation();
 
       // Since the scroll offset has changed, we need to recompute the
       // displayport margins and send them to layout. Otherwise there might be
@@ -3294,17 +3254,17 @@ void AsyncPanZoomController::NotifyLayer
       Stringify(mFrameMetrics.GetScrollOffset()).c_str(),
       Stringify(aLayerMetrics.GetSmoothScrollOffset()).c_str(),
       mState);
 
     // See comment on the similar code in the |if (scrollOffsetUpdated)| block
     // above.
     mFrameMetrics.CopySmoothScrollInfoFrom(aLayerMetrics);
     AcknowledgeScrollUpdate();
-    mLastDispatchedPaintMetrics = aLayerMetrics;
+    mExpectedGeckoMetrics = aLayerMetrics;
 
     if (mState == SMOOTH_SCROLL && mAnimation) {
       APZC_LOG("%p updating destination on existing animation\n", this);
       RefPtr<SmoothScrollAnimation> animation(
         static_cast<SmoothScrollAnimation*>(mAnimation.get()));
       animation->SetDestination(
         CSSPoint::ToAppUnits(aLayerMetrics.GetSmoothScrollOffset()));
     } else {
@@ -3433,19 +3393,17 @@ void AsyncPanZoomController::ZoomToRect(
       aRect.y -= (sizeAfterZoom.height - aRect.height) * 0.5f;
       if (aRect.y < 0.0f) {
         aRect.y = 0.0f;
       }
     }
 
     endZoomToMetrics.SetScrollOffset(aRect.TopLeft());
     endZoomToMetrics.SetDisplayPortMargins(
-      CalculatePendingDisplayPort(endZoomToMetrics,
-                                  ParentLayerPoint(0,0),
-                                  0));
+      CalculatePendingDisplayPort(endZoomToMetrics, ParentLayerPoint(0,0)));
     endZoomToMetrics.SetUseDisplayPortMargins();
 
     StartAnimation(new ZoomAnimation(
         mFrameMetrics.GetScrollOffset(),
         mFrameMetrics.GetZoom(),
         endZoomToMetrics.GetScrollOffset(),
         endZoomToMetrics.GetZoom()));
 
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -19,17 +19,16 @@
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Atomics.h"
 #include "InputData.h"
 #include "Axis.h"
 #include "InputQueue.h"
 #include "APZUtils.h"
 #include "Layers.h"                     // for Layer::ScrollDirection
 #include "LayersTypes.h"
-#include "TaskThrottler.h"
 #include "mozilla/gfx/Matrix.h"
 #include "nsRegion.h"
 
 #include "base/message_loop.h"
 
 namespace mozilla {
 
 namespace ipc {
@@ -99,17 +98,16 @@ public:
    *       distance, but it's the closest thing we currently have.
    */
   static ScreenCoord GetTouchStartTolerance();
 
   AsyncPanZoomController(uint64_t aLayersId,
                          APZCTreeManager* aTreeManager,
                          const RefPtr<InputQueue>& aInputQueue,
                          GeckoContentController* aController,
-                         TaskThrottler* aPaintThrottler,
                          GestureBehavior aGestures = DEFAULT_GESTURES);
 
   // --------------------------------------------------------------------------
   // These methods must only be called on the gecko thread.
   //
 
   /**
    * Read the various prefs and do any global initialization for all APZC instances.
@@ -182,21 +180,16 @@ public:
    * 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.
    */
   void NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint);
 
   /**
-   * Flush any pending repaint request.
-   */
-  void FlushRepaintIfPending();
-
-  /**
    * The platform implementation must set the compositor parent so that we can
    * request composites.
    */
   void SetCompositorParent(CompositorParent* aCompositorParent);
 
   /**
    * Inform this APZC that it will be sharing its FrameMetrics with a cross-process
    * compositor so that the associated content process can access it. This is only
@@ -264,18 +257,17 @@ public:
   /**
    * Recalculates the displayport. Ideally, this should paint an area bigger
    * than the composite-to dimensions so that when you scroll down, you don't
    * checkerboard immediately. This includes a bunch of logic, including
    * algorithms to bias painting in the direction of the velocity.
    */
   static const ScreenMargin CalculatePendingDisplayPort(
     const FrameMetrics& aFrameMetrics,
-    const ParentLayerPoint& aVelocity,
-    double aEstimatedPaintDuration);
+    const ParentLayerPoint& aVelocity);
 
   nsEventStatus HandleDragEvent(const MouseInput& aEvent,
                                 const AsyncDragMetrics& aDragMetrics);
 
   /**
    * Handler for events which should not be intercepted by the touch listener.
    */
   nsEventStatus HandleInputEvent(const InputData& aEvent,
@@ -592,17 +584,17 @@ protected:
 
   /**
    * Tell the paint throttler to request a content repaint with the given
    * metrics.  (Helper function used by RequestContentRepaint.) If aThrottled
    * is set to false, the repaint request is sent directly without going through
    * the paint throttler. In particular, the GeckoContentController::RequestContentRepaint
    * function will be invoked before this function returns.
    */
-  void RequestContentRepaint(FrameMetrics& aFrameMetrics, bool aThrottled = true);
+  void RequestContentRepaint(FrameMetrics& aFrameMetrics);
 
   /**
    * Actually send the next pending paint request to gecko.
    */
   void DispatchRepaintRequest(const FrameMetrics& aFrameMetrics);
 
   /**
    * Gets the current frame metrics. This is *not* the Gecko copy stored in the
@@ -646,17 +638,16 @@ protected:
 
   // This is called to request that the main thread snap the scroll position
   // to a nearby snap position if appropriate. The current scroll position is
   // used as the final destination.
   void RequestSnap();
 
   uint64_t mLayersId;
   RefPtr<CompositorParent> mCompositorParent;
-  RefPtr<TaskThrottler> mPaintThrottler;
 
   /* Access to the following two fields is protected by the mRefPtrMonitor,
      since they are accessed on the UI thread but can be cleared on the
      compositor thread. */
   RefPtr<GeckoContentController> mGeckoContentController;
   RefPtr<GestureEventListener> mGestureEventListener;
   mutable Monitor mRefPtrMonitor;
 
@@ -694,25 +685,22 @@ protected:
 private:
   // Metrics of the container layer corresponding to this APZC. This is
   // stored here so that it is accessible from the UI/controller thread.
   // These are the metrics at last content paint, the most recent
   // values we were notified of in NotifyLayersUpdate(). Since it represents
   // the Gecko state, it should be used as a basis for untransformation when
   // sending messages back to Gecko.
   FrameMetrics mLastContentPaintMetrics;
-  // The last metrics that we requested a paint for. These are used to make sure
-  // that we're not requesting a paint of the same thing that's already drawn.
-  // If we don't do this check, we don't get a ShadowLayersUpdated back.
+  // The last metrics used for a content repaint request.
   FrameMetrics mLastPaintRequestMetrics;
-  // The last metrics that we actually sent to Gecko. This allows us to transform
-  // inputs into a coordinate space that Gecko knows about. This assumes the pipe
-  // through which input events and repaint requests are sent to Gecko operates
-  // in a FIFO manner.
-  FrameMetrics mLastDispatchedPaintMetrics;
+  // The metrics that we expect content to have. This is updated when we
+  // request a content repaint, and when we receive a shadow layers update.
+  // This allows us to transform events into Gecko's coordinate space.
+  FrameMetrics mExpectedGeckoMetrics;
 
   AxisX mX;
   AxisY mY;
 
   // This flag is set to true when we are in a axis-locked pan as a result of
   // the touch-action CSS property.
   bool mPanDirRestricted;
 
deleted file mode 100644
--- a/gfx/layers/apz/src/TaskThrottler.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
-/* vim: set sw=2 sts=2 ts=8 et 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 "TaskThrottler.h"
-
-#include "mozilla/layers/APZThreadUtils.h"
-
-#define TASK_LOG(...)
-// #define TASK_LOG(...) printf_stderr("TASK: " __VA_ARGS__)
-
-namespace mozilla {
-namespace layers {
-
-TaskThrottler::TaskThrottler(const TimeStamp& aTimeStamp, const TimeDuration& aMaxWait)
-  : mMonitor("TaskThrottler")
-  , mOutstanding(false)
-  , mQueuedTask(nullptr)
-  , mStartTime(aTimeStamp)
-  , mMaxWait(aMaxWait)
-  , mMean(1)
-  , mTimeoutTask(nullptr)
-{
-}
-
-TaskThrottler::~TaskThrottler()
-{
-  // The timeout task holds a strong reference to the TaskThrottler, so if the
-  // TaskThrottler is being destroyed, there's no need to cancel the task.
-}
-
-void
-TaskThrottler::PostTask(const tracked_objects::Location& aLocation,
-                        UniquePtr<CancelableTask> aTask, const TimeStamp& aTimeStamp)
-{
-  MonitorAutoLock lock(mMonitor);
-
-  TASK_LOG("%p got a task posted; mOutstanding=%d\n", this, mOutstanding);
-  aTask->SetBirthPlace(aLocation);
-
-  if (mOutstanding) {
-    CancelPendingTask(lock);
-    if (TimeSinceLastRequest(aTimeStamp, lock) < mMaxWait) {
-      mQueuedTask = Move(aTask);
-      TASK_LOG("%p queued task %p\n", this, mQueuedTask.get());
-      // Make sure the queued task is sent after mMaxWait time elapses,
-      // even if we don't get a TaskComplete() until then.
-      TimeDuration timeout = mMaxWait - TimeSinceLastRequest(aTimeStamp, lock);
-      mTimeoutTask = NewRunnableMethod(this, &TaskThrottler::OnTimeout);
-      APZThreadUtils::RunDelayedTaskOnCurrentThread(mTimeoutTask, timeout);
-      return;
-    }
-    // we've been waiting for more than the max-wait limit, so just fall through
-    // and send the new task already.
-  }
-
-  mStartTime = aTimeStamp;
-  aTask->Run();
-  mOutstanding = true;
-}
-
-void
-TaskThrottler::OnTimeout()
-{
-  MonitorAutoLock lock(mMonitor);
-  if (mQueuedTask) {
-    RunQueuedTask(TimeStamp::Now(), lock);
-  }
-  // The message loop will delete the posted timeout task. Make sure we don't
-  // keep a dangling pointer to it.
-  mTimeoutTask = nullptr;
-}
-
-void
-TaskThrottler::TaskComplete(const TimeStamp& aTimeStamp)
-{
-  MonitorAutoLock lock(mMonitor);
-
-  if (!mOutstanding) {
-    return;
-  }
-
-  mMean.insert(aTimeStamp - mStartTime);
-
-  if (mQueuedTask) {
-    RunQueuedTask(aTimeStamp, lock);
-    CancelTimeoutTask(lock);
-  } else {
-    mOutstanding = false;
-  }
-}
-
-TimeDuration
-TaskThrottler::AverageDuration()
-{
-  MonitorAutoLock lock(mMonitor);
-
-  return mMean.empty() ? TimeDuration() : mMean.mean();
-}
-
-void
-TaskThrottler::RunQueuedTask(const TimeStamp& aTimeStamp,
-                             const MonitorAutoLock& aProofOfLock)
-{
-  TASK_LOG("%p running task %p\n", this, mQueuedTask.get());
-  mStartTime = aTimeStamp;
-  mQueuedTask->Run();
-  mQueuedTask = nullptr;
-}
-
-void
-TaskThrottler::CancelPendingTask()
-{
-  MonitorAutoLock lock(mMonitor);
-  CancelPendingTask(lock);
-}
-
-void
-TaskThrottler::CancelPendingTask(const MonitorAutoLock& aProofOfLock)
-{
-  if (mQueuedTask) {
-    TASK_LOG("%p cancelling task %p\n", this, mQueuedTask.get());
-    mQueuedTask->Cancel();
-    mQueuedTask = nullptr;
-    CancelTimeoutTask(aProofOfLock);
-  }
-}
-
-void
-TaskThrottler::CancelTimeoutTask(const MonitorAutoLock& aProofOfLock)
-{
-  if (mTimeoutTask) {
-    mTimeoutTask->Cancel();
-    mTimeoutTask = nullptr;  // the MessageLoop will destroy it
-  }
-}
-
-TimeDuration
-TaskThrottler::TimeSinceLastRequest(const TimeStamp& aTimeStamp)
-{
-  MonitorAutoLock lock(mMonitor);
-  return TimeSinceLastRequest(aTimeStamp, lock);
-}
-
-TimeDuration
-TaskThrottler::TimeSinceLastRequest(const TimeStamp& aTimeStamp,
-                                    const MonitorAutoLock& aProofOfLock)
-{
-  return aTimeStamp - mStartTime;
-}
-
-void
-TaskThrottler::ClearHistory()
-{
-  MonitorAutoLock lock(mMonitor);
-
-  mMean.clear();
-}
-
-void
-TaskThrottler::SetMaxDurations(uint32_t aMaxDurations)
-{
-  MonitorAutoLock lock(mMonitor);
-
-  if (aMaxDurations != mMean.maxValues()) {
-    mMean = RollingMean<TimeDuration, TimeDuration>(aMaxDurations);
-  }
-}
-
-} // namespace layers
-} // namespace mozilla
deleted file mode 100644
--- a/gfx/layers/apz/src/TaskThrottler.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
-/* vim: set sw=4 ts=8 et 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/. */
-
-#ifndef mozilla_dom_TaskThrottler_h
-#define mozilla_dom_TaskThrottler_h
-
-#include <stdint.h>                     // for uint32_t
-#include "base/task.h"                  // for CancelableTask
-#include "mozilla/Monitor.h"            // for Monitor
-#include "mozilla/mozalloc.h"           // for operator delete
-#include "mozilla/RollingMean.h"        // for RollingMean
-#include "mozilla/TimeStamp.h"          // for TimeDuration, TimeStamp
-#include "mozilla/UniquePtr.h"          // for UniquePtr
-#include "nsCOMPtr.h"                   // for nsCOMPtr
-#include "nsISupportsImpl.h"            // for NS_INLINE_DECL_THREADSAFE_REFCOUNTING
-#include "nsTArray.h"                   // for nsTArray
-
-namespace tracked_objects {
-class Location;
-} // namespace tracked_objects
-
-namespace mozilla {
-namespace layers {
-
-/** The TaskThrottler prevents update event overruns. It is used in cases where
- * you're sending an async message and waiting for a reply. You need to call
- * PostTask to queue a task and TaskComplete when you get a response.
- *
- * The call to TaskComplete will run the most recent task posted since the last
- * request was sent, if any. This means that at any time there can be at most 1
- * outstanding request being processed and at most 1 queued behind it.
- *
- * However, to guard against task runs that error out and fail to call TaskComplete,
- * the TaskThrottler also has a max-wait timeout. If the caller requests a new
- * task be posted, and it has been greater than the max-wait timeout since the
- * last one was sent, then we send the new one regardless of whether or not the
- * last one was marked as completed.
- *
- * This is used in the context of repainting a scrollable region. While another
- * process is painting you might get several updates from the UI thread but when
- * the paint is complete you want to send the most recent.
- */
-
-class TaskThrottler {
-public:
-  TaskThrottler(const TimeStamp& aTimeStamp, const TimeDuration& aMaxWait);
-
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TaskThrottler)
-
-  /** Post a task to be run as soon as there are no outstanding tasks, or
-   * post it immediately if it has been more than the max-wait time since
-   * the last task was posted.
-   *
-   * @param aLocation Use the macro FROM_HERE
-   * @param aTask     Ownership of this object is transferred to TaskThrottler
-   *                  which will delete it when it is either run or becomes
-   *                  obsolete or the TaskThrottler is destructed.
-   */
-  void PostTask(const tracked_objects::Location& aLocation,
-                UniquePtr<CancelableTask> aTask, const TimeStamp& aTimeStamp);
-  /**
-   * Mark the task as complete and process the next queued task.
-   */
-  void TaskComplete(const TimeStamp& aTimeStamp);
-
-  /**
-   * Calculate the average time between processing the posted task and getting
-   * the TaskComplete() call back.
-   */
-  TimeDuration AverageDuration();
-
-  /**
-   * Cancel the queued task if there is one.
-   */
-  void CancelPendingTask();
-
-  /**
-   * Return the time elapsed since the last request was processed
-   */
-  TimeDuration TimeSinceLastRequest(const TimeStamp& aTimeStamp);
-
-  /**
-   * Clear average history.
-   */
-  void ClearHistory();
-
-  /**
-   * @param aMaxDurations The maximum number of durations to measure.
-   */
-
-  void SetMaxDurations(uint32_t aMaxDurations);
-
-private:
-  mutable Monitor mMonitor;
-  bool mOutstanding;
-  UniquePtr<CancelableTask> mQueuedTask;
-  TimeStamp mStartTime;
-  TimeDuration mMaxWait;
-  RollingMean<TimeDuration, TimeDuration> mMean;
-  CancelableTask* mTimeoutTask;  // not owned because it's posted to a MessageLoop
-                                 // which deletes it
-
-  ~TaskThrottler();
-  void RunQueuedTask(const TimeStamp& aTimeStamp,
-                     const MonitorAutoLock& aProofOfLock);
-  void CancelPendingTask(const MonitorAutoLock& aProofOfLock);
-  TimeDuration TimeSinceLastRequest(const TimeStamp& aTimeStamp,
-                                    const MonitorAutoLock& aProofOfLock);
-  void OnTimeout();
-  void CancelTimeoutTask(const MonitorAutoLock& aProofOfLock);
-};
-
-} // namespace layers
-} // namespace mozilla
-
-#endif // mozilla_dom_TaskThrottler_h
--- a/gfx/layers/apz/test/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/layers/apz/test/gtest/TestAsyncPanZoomController.cpp
@@ -149,35 +149,33 @@ public:
   explicit TestAPZCTreeManager(MockContentControllerDelayed* aMcc) : mcc(aMcc) {}
 
   RefPtr<InputQueue> GetInputQueue() const {
     return mInputQueue;
   }
 
 protected:
   AsyncPanZoomController* NewAPZCInstance(uint64_t aLayersId,
-                                          GeckoContentController* aController,
-                                          TaskThrottler* aPaintThrottler) override;
+                                          GeckoContentController* aController) override;
 
   TimeStamp GetFrameTime() override {
     return mcc->Time();
   }
 
 private:
   RefPtr<MockContentControllerDelayed> mcc;
 };
 
 class TestAsyncPanZoomController : public AsyncPanZoomController {
 public:
   TestAsyncPanZoomController(uint64_t aLayersId, MockContentControllerDelayed* aMcc,
                              TestAPZCTreeManager* aTreeManager,
-                             TaskThrottler* aPaintThrottler,
                              GestureBehavior aBehavior = DEFAULT_GESTURES)
     : AsyncPanZoomController(aLayersId, aTreeManager, aTreeManager->GetInputQueue(),
-        aMcc, aPaintThrottler, aBehavior)
+        aMcc, aBehavior)
     , mWaitForMainThread(false)
     , mcc(aMcc)
   {}
 
   nsEventStatus ReceiveInputEvent(const InputData& aEvent, ScrollableLayerGuid* aDummy, uint64_t* aOutInputBlockId) {
     // This is a function whose signature matches exactly the ReceiveInputEvent
     // on APZCTreeManager. This allows us to templates for functions like
     // TouchDown, TouchUp, etc so that we can reuse the code for dispatching
@@ -256,21 +254,20 @@ public:
 
 private:
   bool mWaitForMainThread;
   MockContentControllerDelayed* mcc;
 };
 
 AsyncPanZoomController*
 TestAPZCTreeManager::NewAPZCInstance(uint64_t aLayersId,
-                                     GeckoContentController* aController,
-                                     TaskThrottler* aPaintThrottler)
+                                     GeckoContentController* aController)
 {
   MockContentControllerDelayed* mcc = static_cast<MockContentControllerDelayed*>(aController);
-  return new TestAsyncPanZoomController(aLayersId, mcc, this, aPaintThrottler,
+  return new TestAsyncPanZoomController(aLayersId, mcc, this,
       AsyncPanZoomController::USE_GESTURE_DETECTOR);
 }
 
 static FrameMetrics
 TestFrameMetrics()
 {
   FrameMetrics fm;
 
@@ -292,19 +289,18 @@ public:
 protected:
   virtual void SetUp()
   {
     gfxPrefs::GetSingleton();
     APZThreadUtils::SetThreadAssertionsEnabled(false);
     APZThreadUtils::SetControllerThread(MessageLoop::current());
 
     mcc = new NiceMock<MockContentControllerDelayed>();
-    mPaintThrottler = new TaskThrottler(mcc->Time(), TimeDuration::FromMilliseconds(500));
     tm = new TestAPZCTreeManager(mcc);
-    apzc = new TestAsyncPanZoomController(0, mcc, tm, mPaintThrottler, mGestureBehavior);
+    apzc = new TestAsyncPanZoomController(0, mcc, tm, mGestureBehavior);
     apzc->SetFrameMetrics(TestFrameMetrics());
   }
 
   /**
    * Get the APZC's scroll range in CSS pixels.
    */
   CSSRect GetScrollRange() const
   {
@@ -377,17 +373,16 @@ protected:
     EXPECT_TRUE(recoveredFromOverscroll);
     apzc->AssertStateIsReset();
   }
 
   void TestOverscroll();
 
   AsyncPanZoomController::GestureBehavior mGestureBehavior;
   RefPtr<MockContentControllerDelayed> mcc;
-  RefPtr<TaskThrottler> mPaintThrottler;
   RefPtr<TestAPZCTreeManager> tm;
   RefPtr<TestAsyncPanZoomController> apzc;
 };
 
 class APZCGestureDetectorTester : public APZCBasicTester {
 public:
   APZCGestureDetectorTester()
     : APZCBasicTester(AsyncPanZoomController::USE_GESTURE_DETECTOR)
@@ -814,17 +809,18 @@ protected:
 
   void DoPinchTest(bool aShouldTriggerPinch,
                    nsTArray<uint32_t> *aAllowedTouchBehaviors = nullptr)
   {
     apzc->SetFrameMetrics(GetPinchableFrameMetrics());
     MakeApzcZoomable();
 
     if (aShouldTriggerPinch) {
-      EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
+      // One repaint request for each gesture.
+      EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(2);
     } else {
       EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
     }
 
     int touchInputId = 0;
     if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) {
       PinchWithTouchInputAndCheckStatus(apzc, 250, 300, 1.25, touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors);
     } else {
@@ -1136,17 +1132,17 @@ TEST_F(APZCBasicTester, ComplexTransform
   // CSS transforms, the two layers are the same size in screen
   // pixels.
   //
   // The screen itself is 24x24 in screen pixels (therefore 4x4 in
   // CSS pixels). The displayport is 1 extra CSS pixel on all
   // sides.
 
   RefPtr<TestAsyncPanZoomController> childApzc =
-      new TestAsyncPanZoomController(0, mcc, tm, mPaintThrottler);
+      new TestAsyncPanZoomController(0, mcc, tm);
 
   const char* layerTreeSyntax = "c(c)";
   // LayerID                     0 1
   nsIntRegion layerVisibleRegion[] = {
     nsIntRegion(IntRect(0, 0, 300, 300)),
     nsIntRegion(IntRect(0, 0, 150, 300)),
   };
   Matrix4x4 transforms[] = {
@@ -1243,17 +1239,18 @@ TEST_F(APZCPinchTester, Panning_TwoFinge
   EXPECT_EQ(2.0, fm.GetZoom().ToScaleFactor().scale);
 }
 
 class APZCPanningTester : public APZCBasicTester {
 protected:
   void DoPanTest(bool aShouldTriggerScroll, bool aShouldBeConsumed, uint32_t aBehavior)
   {
     if (aShouldTriggerScroll) {
-      EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
+      // One repaint request for each pan.
+      EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(2);
     } else {
       EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
     }
 
     int touchStart = 50;
     int touchEnd = 10;
     ParentLayerPoint pointOut;
     ViewTransform viewTransformOut;
@@ -1352,18 +1349,16 @@ TEST_F(APZCPanningTester, PanWithPrevent
 }
 
 TEST_F(APZCPanningTester, PanWithPreventDefault) {
   SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
   DoPanWithPreventDefaultTest();
 }
 
 TEST_F(APZCBasicTester, Fling) {
-  EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
-
   int touchStart = 50;
   int touchEnd = 10;
   ParentLayerPoint pointOut;
   ViewTransform viewTransformOut;
 
   // Fling down. Each step scroll further down
   Pan(apzc, mcc, touchStart, touchEnd);
   ParentLayerPoint lastPoint;
@@ -2417,39 +2412,35 @@ TEST_F(APZHitTestingTester, HitTesting2)
   EXPECT_EQ(apzc3, hit.get());
   // transformToApzc unapplies both layers[2]'s css transform and the root's
   // async transform
   EXPECT_EQ(ParentLayerPoint(12.5, 75), transformToApzc * ScreenPoint(25, 25));
   // transformToGecko reapplies both the css transform and the async transform
   // because we have already issued a paint request with it.
   EXPECT_EQ(ScreenPoint(25, 25), transformToGecko * ParentLayerPoint(12.5, 75));
 
-  // This second pan will move the APZC by another 50 pixels but since the paint
-  // request dispatched above has not "completed", we will not dispatch another
-  // one yet. Now we have an async transform on top of the pending paint request
-  // transform.
+  // This second pan will move the APZC by another 50 pixels.
+  EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
   ApzcPanNoFling(apzcroot, mcc, 100, 50);
 
   // Hit where layers[3] used to be. It should now hit the root.
   hit = GetTargetAPZC(ScreenPoint(75, 75));
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
   EXPECT_EQ(ParentLayerPoint(75, 75), transformToApzc * ScreenPoint(75, 75));
-  // transformToGecko unapplies the full async transform of -100 pixels, and then
-  // reapplies the "D" transform of -50 leading to an overall adjustment of +50
-  EXPECT_EQ(ScreenPoint(75, 125), transformToGecko * ParentLayerPoint(75, 75));
+  // transformToGecko unapplies the full async transform of -100 pixels
+  EXPECT_EQ(ScreenPoint(75, 75), transformToGecko * ParentLayerPoint(75, 75));
 
   // Hit where layers[1] used to be. It should now hit the root.
   hit = GetTargetAPZC(ScreenPoint(25, 25));
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
   EXPECT_EQ(ParentLayerPoint(25, 25), transformToApzc * ScreenPoint(25, 25));
-  // transformToGecko unapplies the full async transform of -100 pixels, and then
-  // reapplies the "D" transform of -50 leading to an overall adjustment of +50
-  EXPECT_EQ(ScreenPoint(25, 75), transformToGecko * ParentLayerPoint(25, 25));
+  // transformToGecko unapplies the full async transform of -100 pixels
+  EXPECT_EQ(ScreenPoint(25, 25), transformToGecko * ParentLayerPoint(25, 25));
 }
 
 TEST_F(APZCTreeManagerTester, ScrollablePaintedLayers) {
   CreateSimpleMultiLayerTree();
   ScopedLayerTreeRegistration registration(manager, 0, root, mcc);
 
   // both layers have the same scrollId
   SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID);
@@ -3492,94 +3483,8 @@ public:
 
   virtual void Cancel() {
     mMetrics.IncrementCancelCount();
   }
 
 private:
   TaskRunMetrics& mMetrics;
 };
-
-class APZTaskThrottlerTester : public ::testing::Test {
-public:
-  APZTaskThrottlerTester()
-  {
-    now = TimeStamp::Now();
-    throttler = new TaskThrottler(now, TimeDuration::FromMilliseconds(100));
-  }
-
-protected:
-  TimeStamp Advance(int aMillis = 5)
-  {
-    now = now + TimeDuration::FromMilliseconds(aMillis);
-    return now;
-  }
-
-  UniquePtr<CancelableTask> NewTask()
-  {
-    return MakeUnique<MockTask>(metrics);
-  }
-
-  TimeStamp now;
-  RefPtr<TaskThrottler> throttler;
-  TaskRunMetrics metrics;
-};
-
-TEST_F(APZTaskThrottlerTester, BasicTest) {
-  // Check that posting the first task runs right away
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 1
-  EXPECT_EQ(1, metrics.GetAndClearRunCount());
-
-  // Check that posting the second task doesn't run until the first one is done
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 2
-  EXPECT_EQ(0, metrics.GetAndClearRunCount());
-  throttler->TaskComplete(Advance());                           // for task 1
-  EXPECT_EQ(1, metrics.GetAndClearRunCount());
-  EXPECT_EQ(0, metrics.GetAndClearCancelCount());
-
-  // Check that tasks are coalesced: dispatch 5 tasks
-  // while there is still one outstanding, and ensure
-  // that only one of the 5 runs
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 3
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 4
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 5
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 6
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 7
-  EXPECT_EQ(0, metrics.GetAndClearRunCount());
-  EXPECT_EQ(4, metrics.GetAndClearCancelCount());
-
-  throttler->TaskComplete(Advance());                           // for task 2
-  EXPECT_EQ(1, metrics.GetAndClearRunCount());
-  throttler->TaskComplete(Advance());                           // for task 7 (tasks 3..6 were cancelled)
-  EXPECT_EQ(0, metrics.GetAndClearRunCount());
-  EXPECT_EQ(0, metrics.GetAndClearCancelCount());
-}
-
-TEST_F(APZTaskThrottlerTester, TimeoutTest) {
-  // Check that posting the first task runs right away
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 1
-  EXPECT_EQ(1, metrics.GetAndClearRunCount());
-
-  // Because we let 100ms pass, the second task should
-  // run immediately even though the first one isn't
-  // done yet
-  throttler->PostTask(FROM_HERE, NewTask(), Advance(100));      // task 2; task 1 is assumed lost
-  EXPECT_EQ(1, metrics.GetAndClearRunCount());
-  throttler->TaskComplete(Advance());                           // for task 1, but TaskThrottler thinks it's for task 2
-  throttler->TaskComplete(Advance());                           // for task 2, TaskThrottler ignores it
-  EXPECT_EQ(0, metrics.GetAndClearRunCount());
-  EXPECT_EQ(0, metrics.GetAndClearCancelCount());
-
-  // This time queue up a few tasks before the timeout expires
-  // and ensure cancellation still works as expected
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 3
-  EXPECT_EQ(1, metrics.GetAndClearRunCount());
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 4
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 5
-  throttler->PostTask(FROM_HERE, NewTask(), Advance());         // task 6
-  EXPECT_EQ(0, metrics.GetAndClearRunCount());
-  throttler->PostTask(FROM_HERE, NewTask(), Advance(100));      // task 7; task 3 is assumed lost
-  EXPECT_EQ(1, metrics.GetAndClearRunCount());
-  EXPECT_EQ(3, metrics.GetAndClearCancelCount());               // tasks 4..6 should have been cancelled
-  throttler->TaskComplete(Advance());                           // for task 7
-  EXPECT_EQ(0, metrics.GetAndClearRunCount());
-  EXPECT_EQ(0, metrics.GetAndClearCancelCount());
-}
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -36,36 +36,36 @@ namespace layers {
 using dom::TabParent;
 
 uint64_t APZCCallbackHelper::sLastTargetAPZCNotificationInputBlock = uint64_t(-1);
 
 static void
 AdjustDisplayPortForScrollDelta(mozilla::layers::FrameMetrics& aFrameMetrics,
                                 const CSSPoint& aActualScrollOffset)
 {
-    // Correct the display-port by the difference between the requested scroll
-    // offset and the resulting scroll offset after setting the requested value.
-    ScreenPoint shift =
-        (aFrameMetrics.GetScrollOffset() - aActualScrollOffset) *
-        aFrameMetrics.DisplayportPixelsPerCSSPixel();
-    ScreenMargin margins = aFrameMetrics.GetDisplayPortMargins();
-    margins.left -= shift.x;
-    margins.right += shift.x;
-    margins.top -= shift.y;
-    margins.bottom += shift.y;
-    aFrameMetrics.SetDisplayPortMargins(margins);
+  // Correct the display-port by the difference between the requested scroll
+  // offset and the resulting scroll offset after setting the requested value.
+  ScreenPoint shift =
+      (aFrameMetrics.GetScrollOffset() - aActualScrollOffset) *
+      aFrameMetrics.DisplayportPixelsPerCSSPixel();
+  ScreenMargin margins = aFrameMetrics.GetDisplayPortMargins();
+  margins.left -= shift.x;
+  margins.right += shift.x;
+  margins.top -= shift.y;
+  margins.bottom += shift.y;
+  aFrameMetrics.SetDisplayPortMargins(margins);
 }
 
 static void
 RecenterDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics)
 {
-    ScreenMargin margins = aFrameMetrics.GetDisplayPortMargins();
-    margins.right = margins.left = margins.LeftRight() / 2;
-    margins.top = margins.bottom = margins.TopBottom() / 2;
-    aFrameMetrics.SetDisplayPortMargins(margins);
+  ScreenMargin margins = aFrameMetrics.GetDisplayPortMargins();
+  margins.right = margins.left = margins.LeftRight() / 2;
+  margins.top = margins.bottom = margins.TopBottom() / 2;
+  aFrameMetrics.SetDisplayPortMargins(margins);
 }
 
 static CSSPoint
 ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint, bool& aSuccessOut)
 {
   aSuccessOut = false;
 
   if (!aFrame) {
@@ -123,19 +123,30 @@ ScrollFrame(nsIContent* aContent,
 {
   // Scroll the window to the desired spot
   nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId());
   bool scrollUpdated = false;
   CSSPoint apzScrollOffset = aMetrics.GetScrollOffset();
   CSSPoint actualScrollOffset = ScrollFrameTo(sf, apzScrollOffset, scrollUpdated);
 
   if (scrollUpdated) {
-    // Correct the display port due to the difference between mScrollOffset and the
-    // actual scroll offset.
-    AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset);
+    if (aMetrics.IsScrollInfoLayer()) {
+      // In cases where the APZ scroll offset is different from the content scroll
+      // offset, we want to interpret the margins as relative to the APZ scroll
+      // offset except when the frame is not scrollable by APZ. Therefore, if the
+      // layer is a scroll info layer, we leave the margins as-is and they will
+      // be interpreted as relative to the content scroll offset.
+      if (nsIFrame* frame = aContent->GetPrimaryFrame()) {
+        frame->SchedulePaint();
+      }
+    } else {
+      // Correct the display port due to the difference between mScrollOffset and the
+      // actual scroll offset.
+      AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset);
+    }
   } else {
     // For whatever reason we couldn't update the scroll offset on the scroll frame,
     // which means the data APZ used for its displayport calculation is stale. Fall
     // back to a sane default behaviour. Note that we don't tile-align the recentered
     // displayport because tile-alignment depends on the scroll position, and the
     // scroll position here is out of our control. See bug 966507 comment 21 for a
     // more detailed explanation.
     RecenterDisplayPort(aMetrics);
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -2,17 +2,16 @@
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BasicCompositor.h"
 #include "BasicLayersImpl.h"            // for FillRectWithMask
 #include "TextureHostBasic.h"
 #include "mozilla/layers/Effects.h"
-#include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsIWidget.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Helpers.h"
 #include "gfxUtils.h"
 #include "YCbCrUtils.h"
 #include <algorithm>
 #include "ImageContainer.h"
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -10,17 +10,16 @@
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "mozilla/Atomics.h"
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
 #include "mozilla/layers/AsyncTransactionTracker.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/TextureClientRecycleAllocator.h"
-#include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "ImageContainer.h"             // for PlanarYCbCrData, etc
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Logging.h"        // for gfxDebug
 #include "mozilla/layers/TextureClientOGL.h"
 #include "mozilla/layers/PTextureChild.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h" // for CreateDataSourceSurfaceByCloning
@@ -833,29 +832,30 @@ TextureClient::CreateForYCbCr(ISurfaceAl
     return nullptr;
   }
 
   return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
 }
 
 // static
 already_AddRefed<TextureClient>
-TextureClient::CreateWithBufferSize(ISurfaceAllocator* aAllocator,
-                                    gfx::SurfaceFormat aFormat,
-                                    size_t aSize,
-                                    TextureFlags aTextureFlags)
+TextureClient::CreateForYCbCrWithBufferSize(ISurfaceAllocator* aAllocator,
+                                            gfx::SurfaceFormat aFormat,
+                                            size_t aSize,
+                                            TextureFlags aTextureFlags)
 {
   // also test the validity of aAllocator
   MOZ_ASSERT(aAllocator && aAllocator->IPCOpen());
   if (!aAllocator || !aAllocator->IPCOpen()) {
     return nullptr;
   }
 
-  TextureData* data = BufferTextureData::CreateWithBufferSize(aAllocator, aFormat, aSize,
-                                                              aTextureFlags);
+  TextureData* data =
+    BufferTextureData::CreateForYCbCrWithBufferSize(aAllocator, aFormat, aSize,
+                                                    aTextureFlags);
   if (!data) {
     return nullptr;
   }
 
   return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
 }
 
 TextureClient::TextureClient(TextureData* aData, TextureFlags aFlags, ISurfaceAllocator* aAllocator)
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -292,20 +292,20 @@ public:
                            gfx::BackendType aMoz2dBackend,
                            TextureFlags aTextureFlags,
                            TextureAllocationFlags flags = ALLOC_DEFAULT);
 
   // Creates and allocates a TextureClient (can beaccessed through raw
   // pointers) with a certain buffer size. It's unfortunate that we need this.
   // providing format and sizes could let us do more optimization.
   static already_AddRefed<TextureClient>
-  CreateWithBufferSize(ISurfaceAllocator* aAllocator,
-                       gfx::SurfaceFormat aFormat,
-                       size_t aSize,
-                       TextureFlags aTextureFlags);
+  CreateForYCbCrWithBufferSize(ISurfaceAllocator* aAllocator,
+                               gfx::SurfaceFormat aFormat,
+                               size_t aSize,
+                               TextureFlags aTextureFlags);
 
   // Creates and allocates a TextureClient of the same type.
   already_AddRefed<TextureClient>
   CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
                 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const;
 
   /**
    * Locks the shared data, allowing the caller to get access to it.
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -8,20 +8,19 @@
 #include "CompositableHost.h"           // for CompositableHost
 #include "LayerScope.h"
 #include "LayersLogging.h"              // for AppendToString
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
-#include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
-#include "mozilla/layers/YCbCrImageDataSerializer.h"
+#include "mozilla/layers/ImageDataSerializer.h"
 #include "nsAString.h"
 #include "mozilla/RefPtr.h"                   // for nsRefPtr
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "mozilla/layers/PTextureParent.h"
 #include "mozilla/unused.h"
 #include <limits>
 #include "../opengl/CompositorOGL.h"
 #include "gfxPrefs.h"
@@ -90,17 +89,18 @@ public:
 
 ////////////////////////////////////////////////////////////////////////////////
 PTextureParent*
 TextureHost::CreateIPDLActor(CompositableParentManager* aManager,
                              const SurfaceDescriptor& aSharedData,
                              LayersBackend aLayersBackend,
                              TextureFlags aFlags)
 {
-  if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorMemory &&
+  if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer &&
+      aSharedData.get_SurfaceDescriptorBuffer().data().type() == MemoryOrShmem::Tuintptr_t &&
       !aManager->IsSameProcess())
   {
     NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!");
     return nullptr;
   }
   TextureParent* actor = new TextureParent(aManager);
   if (!actor->Init(aSharedData, aLayersBackend, aFlags)) {
     delete actor;
@@ -197,18 +197,17 @@ already_AddRefed<TextureHost> CreateText
 
 already_AddRefed<TextureHost>
 TextureHost::Create(const SurfaceDescriptor& aDesc,
                     ISurfaceAllocator* aDeallocator,
                     LayersBackend aBackend,
                     TextureFlags aFlags)
 {
   switch (aDesc.type()) {
-    case SurfaceDescriptor::TSurfaceDescriptorShmem:
-    case SurfaceDescriptor::TSurfaceDescriptorMemory:
+    case SurfaceDescriptor::TSurfaceDescriptorBuffer:
     case SurfaceDescriptor::TSurfaceDescriptorDIB:
     case SurfaceDescriptor::TSurfaceDescriptorFileMapping:
       return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
 
     case SurfaceDescriptor::TEGLImageDescriptor:
     case SurfaceDescriptor::TSurfaceTextureDescriptor:
     case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture:
       return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
@@ -247,29 +246,36 @@ TextureHost::Create(const SurfaceDescrip
 
 already_AddRefed<TextureHost>
 CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc,
                                     ISurfaceAllocator* aDeallocator,
                                     TextureFlags aFlags)
 {
   RefPtr<TextureHost> result;
   switch (aDesc.type()) {
-    case SurfaceDescriptor::TSurfaceDescriptorShmem: {
-      const SurfaceDescriptorShmem& descriptor = aDesc.get_SurfaceDescriptorShmem();
-      result = new ShmemTextureHost(descriptor.data(),
-                                    descriptor.format(),
-                                    aDeallocator,
-                                    aFlags);
-      break;
-    }
-    case SurfaceDescriptor::TSurfaceDescriptorMemory: {
-      const SurfaceDescriptorMemory& descriptor = aDesc.get_SurfaceDescriptorMemory();
-      result = new MemoryTextureHost(reinterpret_cast<uint8_t*>(descriptor.data()),
-                                     descriptor.format(),
-                                     aFlags);
+    case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
+      const SurfaceDescriptorBuffer& bufferDesc = aDesc.get_SurfaceDescriptorBuffer();
+      const MemoryOrShmem& data = bufferDesc.data();
+      switch (data.type()) {
+        case MemoryOrShmem::TShmem: {
+          result = new ShmemTextureHost(data.get_Shmem(),
+                                        bufferDesc.desc(),
+                                        aDeallocator,
+                                        aFlags);
+          break;
+        }
+        case MemoryOrShmem::Tuintptr_t: {
+          result = new MemoryTextureHost(reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
+                                         bufferDesc.desc(),
+                                         aFlags);
+          break;
+        }
+        default:
+          MOZ_CRASH();
+      }
       break;
     }
 #ifdef XP_WIN
     case SurfaceDescriptor::TSurfaceDescriptorDIB: {
       result = new DIBTextureHost(aFlags, aDesc);
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorFileMapping: {
@@ -363,49 +369,48 @@ TextureSource::TextureSource()
     MOZ_COUNT_CTOR(TextureSource);
 }
 
 TextureSource::~TextureSource()
 {
     MOZ_COUNT_DTOR(TextureSource);
 }
 
-BufferTextureHost::BufferTextureHost(gfx::SurfaceFormat aFormat,
+BufferTextureHost::BufferTextureHost(const BufferDescriptor& aDesc,
                                      TextureFlags aFlags)
 : TextureHost(aFlags)
 , mCompositor(nullptr)
-, mFormat(aFormat)
 , mUpdateSerial(1)
 , mLocked(false)
 , mNeedsFullUpdate(false)
 {
+  mDescriptor = aDesc;
+  switch (mDescriptor.type()) {
+    case BufferDescriptor::TYCbCrDescriptor: {
+      const YCbCrDescriptor& ycbcr = mDescriptor.get_YCbCrDescriptor();
+      mSize = ycbcr.ySize();
+      mFormat = gfx::SurfaceFormat::YUV;
+      break;
+    }
+    case BufferDescriptor::TRGBDescriptor: {
+      const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
+      mSize = rgb.size();
+      mFormat = rgb.format();
+      break;
+    }
+    default: MOZ_CRASH();
+  }
   if (aFlags & TextureFlags::COMPONENT_ALPHA) {
     // One texture of a component alpha texture pair will start out all white.
     // This hack allows us to easily make sure that white will be uploaded.
     // See bug 1138934
     mNeedsFullUpdate = true;
   }
 }
 
-void
-BufferTextureHost::InitSize()
-{
-  if (mFormat == gfx::SurfaceFormat::YUV) {
-    YCbCrImageDataDeserializer yuvDeserializer(GetBuffer(), GetBufferSize());
-    if (yuvDeserializer.IsValid()) {
-      mSize = yuvDeserializer.GetYSize();
-    }
-  } else if (mFormat != gfx::SurfaceFormat::UNKNOWN) {
-    ImageDataDeserializer deserializer(GetBuffer(), GetBufferSize());
-    if (deserializer.IsValid()) {
-      mSize = deserializer.GetSize();
-    }
-  }
-}
-
 BufferTextureHost::~BufferTextureHost()
 {}
 
 void
 BufferTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
 {
   ++mUpdateSerial;
   // If the last frame wasn't uploaded yet, and we -don't- have a partial update,
@@ -507,36 +512,37 @@ BufferTextureHost::MaybeUpload(nsIntRegi
   // If upload returns true we know mFirstSource is not null
   mFirstSource->SetUpdateSerial(mUpdateSerial);
   return true;
 }
 
 bool
 BufferTextureHost::Upload(nsIntRegion *aRegion)
 {
-  if (!GetBuffer()) {
+  uint8_t* buf = GetBuffer();
+  if (!buf) {
     // We don't have a buffer; a possible cause is that the IPDL actor
     // is already dead. This inevitably happens as IPDL actors can die
     // at any time, so we want to silently return in this case.
     return false;
   }
   if (!mCompositor) {
     // This can happen if we send textures to a compositable that isn't yet
     // attached to a layer.
     return false;
   }
   if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
     NS_WARNING("BufferTextureHost: unsupported format!");
     return false;
   } else if (mFormat == gfx::SurfaceFormat::YUV) {
-    YCbCrImageDataDeserializer yuvDeserializer(GetBuffer(), GetBufferSize());
-    MOZ_ASSERT(yuvDeserializer.IsValid());
+    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
 
     if (!mCompositor->SupportsEffect(EffectTypes::YCBCR)) {
-      RefPtr<gfx::DataSourceSurface> surf = yuvDeserializer.ToDataSourceSurface();
+      RefPtr<gfx::DataSourceSurface> surf =
+        ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(buf, mDescriptor.get_YCbCrDescriptor());
       if (NS_WARN_IF(!surf)) {
         return false;
       }
       if (!mFirstSource) {
         mFirstSource = mCompositor->CreateDataTextureSource(mFlags);
       }
       mFirstSource->Update(surf, aRegion);
       return true;
@@ -560,31 +566,30 @@ BufferTextureHost::Upload(nsIntRegion *a
       // all 3 sources are DataTextureSource.
       MOZ_ASSERT(mFirstSource->GetNextSibling());
       MOZ_ASSERT(mFirstSource->GetNextSibling()->GetNextSibling());
       srcY = mFirstSource;
       srcU = mFirstSource->GetNextSibling()->AsDataTextureSource();
       srcV = mFirstSource->GetNextSibling()->GetNextSibling()->AsDataTextureSource();
     }
 
-
     RefPtr<gfx::DataSourceSurface> tempY =
-      gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetYData(),
-                                                    yuvDeserializer.GetYStride(),
-                                                    yuvDeserializer.GetYSize(),
+      gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetYChannel(buf, desc),
+                                                    desc.ySize().width,
+                                                    desc.ySize(),
                                                     gfx::SurfaceFormat::A8);
     RefPtr<gfx::DataSourceSurface> tempCb =
-      gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetCbData(),
-                                                    yuvDeserializer.GetCbCrStride(),
-                                                    yuvDeserializer.GetCbCrSize(),
+      gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCbChannel(buf, desc),
+                                                    desc.cbCrSize().width,
+                                                    desc.cbCrSize(),
                                                     gfx::SurfaceFormat::A8);
     RefPtr<gfx::DataSourceSurface> tempCr =
-      gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetCrData(),
-                                                    yuvDeserializer.GetCbCrStride(),
-                                                    yuvDeserializer.GetCbCrSize(),
+      gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCrChannel(buf, desc),
+                                                    desc.cbCrSize().width,
+                                                    desc.cbCrSize(),
                                                     gfx::SurfaceFormat::A8);
     // We don't support partial updates for Y U V textures
     NS_ASSERTION(!aRegion, "Unsupported partial updates for YCbCr textures");
     if (!tempY ||
         !tempCb ||
         !tempCr ||
         !srcY->Update(tempY) ||
         !srcU->Update(tempCb) ||
@@ -597,23 +602,20 @@ BufferTextureHost::Upload(nsIntRegion *a
     nsIntRegion* regionToUpdate = aRegion;
     if (!mFirstSource) {
       mFirstSource = mCompositor->CreateDataTextureSource(mFlags);
       if (mFlags & TextureFlags::COMPONENT_ALPHA) {
         // Update the full region the first time for component alpha textures.
         regionToUpdate = nullptr;
       }
     }
-    ImageDataDeserializer deserializer(GetBuffer(), GetBufferSize());
-    if (!deserializer.IsValid()) {
-      NS_ERROR("Failed to deserialize image!");
-      return false;
-    }
 
-    RefPtr<gfx::DataSourceSurface> surf = deserializer.GetAsSurface();
+    RefPtr<gfx::DataSourceSurface> surf =
+      gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),
+        ImageDataSerializer::ComputeRGBStride(mFormat, mSize.width), mSize, mFormat);
     if (!surf) {
       return false;
     }
 
     if (!mFirstSource->Update(surf.get(), regionToUpdate)) {
       NS_WARNING("failed to update the DataTextureSource");
       return false;
     }
@@ -625,45 +627,39 @@ BufferTextureHost::Upload(nsIntRegion *a
 already_AddRefed<gfx::DataSourceSurface>
 BufferTextureHost::GetAsSurface()
 {
   RefPtr<gfx::DataSourceSurface> result;
   if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
     NS_WARNING("BufferTextureHost: unsupported format!");
     return nullptr;
   } else if (mFormat == gfx::SurfaceFormat::YUV) {
-    YCbCrImageDataDeserializer yuvDeserializer(GetBuffer(), GetBufferSize());
-    if (!yuvDeserializer.IsValid()) {
-      return nullptr;
-    }
-    result = yuvDeserializer.ToDataSourceSurface();
+    result = ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
+      GetBuffer(), mDescriptor.get_YCbCrDescriptor());
     if (NS_WARN_IF(!result)) {
       return nullptr;
     }
   } else {
-    ImageDataDeserializer deserializer(GetBuffer(), GetBufferSize());
-    if (!deserializer.IsValid()) {
-      NS_ERROR("Failed to deserialize image!");
-      return nullptr;
-    }
-    result = deserializer.GetAsSurface();
+    RefPtr<gfx::DataSourceSurface> surf =
+      gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),
+        ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()),
+        mSize, mFormat);
   }
   return result.forget();
 }
 
 ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem,
-                                   gfx::SurfaceFormat aFormat,
+                                   const BufferDescriptor& aDesc,
                                    ISurfaceAllocator* aDeallocator,
                                    TextureFlags aFlags)
-: BufferTextureHost(aFormat, aFlags)
+: BufferTextureHost(aDesc, aFlags)
 , mShmem(MakeUnique<ipc::Shmem>(aShmem))
 , mDeallocator(aDeallocator)
 {
   MOZ_COUNT_CTOR(ShmemTextureHost);
-  InitSize();
 }
 
 ShmemTextureHost::~ShmemTextureHost()
 {
   MOZ_ASSERT(!mShmem || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
              "Leaking our buffer");
   DeallocateDeviceData();
   MOZ_COUNT_DTOR(ShmemTextureHost);
@@ -700,23 +696,22 @@ uint8_t* ShmemTextureHost::GetBuffer()
 }
 
 size_t ShmemTextureHost::GetBufferSize()
 {
   return mShmem ? mShmem->Size<uint8_t>() : 0;
 }
 
 MemoryTextureHost::MemoryTextureHost(uint8_t* aBuffer,
-                                     gfx::SurfaceFormat aFormat,
+                                     const BufferDescriptor& aDesc,
                                      TextureFlags aFlags)
-: BufferTextureHost(aFormat, aFlags)
+: BufferTextureHost(aDesc, aFlags)
 , mBuffer(aBuffer)
 {
   MOZ_COUNT_CTOR(MemoryTextureHost);
-  InitSize();
 }
 
 MemoryTextureHost::~MemoryTextureHost()
 {
   MOZ_ASSERT(!mBuffer || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
              "Leaking our buffer");
   DeallocateDeviceData();
   MOZ_COUNT_DTOR(MemoryTextureHost);
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -14,16 +14,17 @@
 #include "mozilla/RefPtr.h"             // for RefPtr, already_AddRefed, etc
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface
 #include "mozilla/gfx/Point.h"          // for IntSize, IntPoint
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat, etc
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorTypes.h"  // for TextureFlags, etc
 #include "mozilla/layers/FenceUtils.h"  // for FenceHandle
 #include "mozilla/layers/LayersTypes.h"  // for LayerRenderState, etc
+#include "mozilla/layers/LayersSurfaces.h"
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "mozilla/UniquePtr.h"          // for UniquePtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nscore.h"                     // for nsACString
@@ -32,16 +33,17 @@
 
 namespace mozilla {
 namespace ipc {
 class Shmem;
 } // namespace ipc
 
 namespace layers {
 
+class BufferDescriptor;
 class Compositor;
 class CompositableParentManager;
 class SurfaceDescriptor;
 class ISurfaceAllocator;
 class TextureHostOGL;
 class TextureSourceOGL;
 class TextureSourceD3D9;
 class TextureSourceD3D11;
@@ -562,18 +564,17 @@ protected:
  *
  * Uploads happen when Lock is called.
  *
  * BufferTextureHost supports YCbCr and flavours of RGBA images (RGBX, A, etc.).
  */
 class BufferTextureHost : public TextureHost
 {
 public:
-  BufferTextureHost(gfx::SurfaceFormat aFormat,
-                    TextureFlags aFlags);
+  BufferTextureHost(const BufferDescriptor& aDescriptor, TextureFlags aFlags);
 
   ~BufferTextureHost();
 
   virtual uint8_t* GetBuffer() = 0;
 
   virtual size_t GetBufferSize() = 0;
 
   virtual bool Lock() override;
@@ -600,41 +601,39 @@ public:
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
 
   virtual bool HasInternalBuffer() const override { return true; }
 
 protected:
   bool Upload(nsIntRegion *aRegion = nullptr);
   bool MaybeUpload(nsIntRegion *aRegion = nullptr);
 
-  void InitSize();
-
   virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
 
+  BufferDescriptor mDescriptor;
   RefPtr<Compositor> mCompositor;
   RefPtr<DataTextureSource> mFirstSource;
   nsIntRegion mMaybeUpdatedRegion;
   gfx::IntSize mSize;
-  // format of the data that is shared with the content process.
   gfx::SurfaceFormat mFormat;
   uint32_t mUpdateSerial;
   bool mLocked;
   bool mNeedsFullUpdate;
 };
 
 /**
  * TextureHost that wraps shared memory.
  * the corresponding texture on the client side is ShmemTextureClient.
  * This TextureHost is backend-independent.
  */
 class ShmemTextureHost : public BufferTextureHost
 {
 public:
   ShmemTextureHost(const mozilla::ipc::Shmem& aShmem,
-                   gfx::SurfaceFormat aFormat,
+                   const BufferDescriptor& aDesc,
                    ISurfaceAllocator* aDeallocator,
                    TextureFlags aFlags);
 
 protected:
   ~ShmemTextureHost();
 
 public:
   virtual void DeallocateSharedData() override;
@@ -659,17 +658,17 @@ protected:
  * The corresponding texture on the client side is MemoryTextureClient.
  * Can obviously not be used in a cross process setup.
  * This TextureHost is backend-independent.
  */
 class MemoryTextureHost : public BufferTextureHost
 {
 public:
   MemoryTextureHost(uint8_t* aBuffer,
-                    gfx::SurfaceFormat aFormat,
+                    const BufferDescriptor& aDesc,
                     TextureFlags aFlags);
 
 protected:
   ~MemoryTextureHost();
 
 public:
   virtual void DeallocateSharedData() override;
 
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -2,17 +2,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TextureD3D11.h"
 #include "CompositorD3D11.h"
 #include "gfxContext.h"
 #include "Effects.h"
-#include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "gfxWindowsPlatform.h"
 #include "gfx2DGlue.h"
 #include "gfxPrefs.h"
 #include "ReadbackManagerD3D11.h"
 #include "mozilla/gfx/Logging.h"
 
 namespace mozilla {
 
@@ -660,18 +659,17 @@ DXGIYCbCrTextureData::Deallocate(ISurfac
 
 already_AddRefed<TextureHost>
 CreateTextureHostD3D11(const SurfaceDescriptor& aDesc,
                        ISurfaceAllocator* aDeallocator,
                        TextureFlags aFlags)
 {
   RefPtr<TextureHost> result;
   switch (aDesc.type()) {
-    case SurfaceDescriptor::TSurfaceDescriptorShmem:
-    case SurfaceDescriptor::TSurfaceDescriptorMemory: {
+    case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
       result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
       result = new DXGITextureHostD3D11(aFlags,
                                         aDesc.get_SurfaceDescriptorD3D10());
       break;
     }
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -3,17 +3,16 @@
  * 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 "TextureD3D9.h"
 #include "CompositorD3D9.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "Effects.h"
-#include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "gfxWindowsPlatform.h"
 #include "gfx2DGlue.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
@@ -48,18 +47,17 @@ TextureSourceD3D9::~TextureSourceD3D9()
 
 already_AddRefed<TextureHost>
 CreateTextureHostD3D9(const SurfaceDescriptor& aDesc,
                       ISurfaceAllocator* aDeallocator,
                       TextureFlags aFlags)
 {
   RefPtr<TextureHost> result;
   switch (aDesc.type()) {
-    case SurfaceDescriptor::TSurfaceDescriptorShmem:
-    case SurfaceDescriptor::TSurfaceDescriptorMemory: {
+    case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
       result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorD3D9: {
       result = new TextureHostD3D9(aFlags, aDesc);
       break;
     }
     case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
@@ -187,17 +185,17 @@ TextureSourceD3D9::InitTextures(DeviceMa
 
   RefPtr<IDirect3DTexture9> tmpTexture =
     aDeviceManager->CreateTexture(aSize, aFormat, D3DPOOL_SYSTEMMEM, this);
   if (!tmpTexture) {
     return nullptr;
   }
 
   tmpTexture->GetSurfaceLevel(0, getter_AddRefs(aSurface));
-  
+
   HRESULT hr = aSurface->LockRect(&aLockedRect, nullptr, 0);
   if (FAILED(hr) || !aLockedRect.pBits) {
     gfxCriticalError() << "Failed to lock rect initialize texture in D3D9 " << hexa(hr);
     return nullptr;
   }
 
   return result.forget();
 }
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -1541,32 +1541,25 @@ CompositorParent::RecvNotifyChildCreated
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   NotifyChildCreated(child);
   return true;
 }
 
 void
 CompositorParent::NotifyChildCreated(const uint64_t& aChild)
 {
-  if (mApzcTreeManager) {
-    NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<uint64_t>(
-        mApzcTreeManager, &APZCTreeManager::InitializeForLayersId, aChild));
-  }
   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
   sIndirectLayerTrees[aChild].mParent = this;
   sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
 }
 
 bool
 CompositorParent::RecvAdoptChild(const uint64_t& child)
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
-  if (mApzcTreeManager) {
-    mApzcTreeManager->AdoptLayersId(child, sIndirectLayerTrees[child].mParent->mApzcTreeManager.get());
-  }
   NotifyChildCreated(child);
   if (sIndirectLayerTrees[child].mLayerTree) {
     sIndirectLayerTrees[child].mLayerTree->mLayerManager = mLayerManager;
   }
   if (sIndirectLayerTrees[child].mRoot) {
     sIndirectLayerTrees[child].mRoot->AsLayerComposite()->SetLayerManager(mLayerManager);
   }
   return true;
@@ -1628,35 +1621,31 @@ UpdateControllerForLayersId(uint64_t aLa
 
 ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(APZCTreeManager* aApzctm,
                                                          uint64_t aLayersId,
                                                          Layer* aRoot,
                                                          GeckoContentController* aController)
     : mLayersId(aLayersId)
 {
   EnsureLayerTreeMapReady();
-  aApzctm->InitializeForLayersId(aLayersId);
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   sIndirectLayerTrees[aLayersId].mRoot = aRoot;
   sIndirectLayerTrees[aLayersId].mController = aController;
 }
 
 ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration()
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   sIndirectLayerTrees.erase(mLayersId);
 }
 
 /*static*/ void
 CompositorParent::SetControllerForLayerTree(uint64_t aLayersId,
                                             GeckoContentController* aController)
 {
-  if (APZCTreeManager* apzctm = GetAPZCTreeManager(aLayersId)) {
-    apzctm->InitializeForLayersId(aLayersId);
-  }
   // This ref is adopted by UpdateControllerForLayersId().
   aController->AddRef();
   CompositorLoop()->PostTask(FROM_HERE,
                              NewRunnableFunction(&UpdateControllerForLayersId,
                                                  aLayersId,
                                                  aController));
 }
 
--- a/gfx/layers/ipc/ISurfaceAllocator.cpp
+++ b/gfx/layers/ipc/ISurfaceAllocator.cpp
@@ -55,48 +55,48 @@ ISurfaceAllocator::~ISurfaceAllocator()
 
 void
 ISurfaceAllocator::Finalize()
 {
   ShrinkShmemSectionHeap();
 }
 
 static inline uint8_t*
-GetAddressFromDescriptor(const SurfaceDescriptor& aDescriptor, size_t& aSize)
+GetAddressFromDescriptor(const SurfaceDescriptor& aDescriptor)
 {
   MOZ_ASSERT(IsSurfaceDescriptorValid(aDescriptor));
-  MOZ_ASSERT(aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorShmem ||
-             aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorMemory);
-  if (aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorShmem) {
-    Shmem shmem(aDescriptor.get_SurfaceDescriptorShmem().data());
-    aSize = shmem.Size<uint8_t>();
-    return shmem.get<uint8_t>();
+  MOZ_RELEASE_ASSERT(aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer);
+
+  auto memOrShmem = aDescriptor.get_SurfaceDescriptorBuffer().data();
+  if (memOrShmem.type() == MemoryOrShmem::TShmem) {
+    return memOrShmem.get_Shmem().get<uint8_t>();
   } else {
-    const SurfaceDescriptorMemory& image = aDescriptor.get_SurfaceDescriptorMemory();
-    aSize = std::numeric_limits<size_t>::max();
-    return reinterpret_cast<uint8_t*>(image.data());
+    return reinterpret_cast<uint8_t*>(memOrShmem.get_uintptr_t());
   }
 }
 
 already_AddRefed<gfx::DrawTarget>
 GetDrawTargetForDescriptor(const SurfaceDescriptor& aDescriptor, gfx::BackendType aBackend)
 {
-  size_t size;
-  uint8_t* data = GetAddressFromDescriptor(aDescriptor, size);
-  ImageDataDeserializer image(data, size);
-  return image.GetAsDrawTarget(aBackend);
+  uint8_t* data = GetAddressFromDescriptor(aDescriptor);
+  auto rgb = aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor();
+  uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
+  return gfx::Factory::CreateDrawTargetForData(gfx::BackendType::CAIRO,
+                                               data, rgb.size(),
+                                               stride, rgb.format());
 }
 
 already_AddRefed<gfx::DataSourceSurface>
 GetSurfaceForDescriptor(const SurfaceDescriptor& aDescriptor)
 {
-  size_t size;
-  uint8_t* data = GetAddressFromDescriptor(aDescriptor, size);
-  ImageDataDeserializer image(data, size);
-  return image.GetAsSurface();
+  uint8_t* data = GetAddressFromDescriptor(aDescriptor);
+  auto rgb = aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor();
+  uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
+  return gfx::Factory::CreateWrappingDataSourceSurface(data, stride, rgb.size(),
+                                                       rgb.format());
 }
 
 bool
 ISurfaceAllocator::AllocSurfaceDescriptor(const gfx::IntSize& aSize,
                                           gfxContentType aContent,
                                           SurfaceDescriptor* aBuffer)
 {
   if (!IPCOpen()) {
@@ -111,55 +111,57 @@ ISurfaceAllocator::AllocSurfaceDescripto
                                                   uint32_t aCaps,
                                                   SurfaceDescriptor* aBuffer)
 {
   if (!IPCOpen()) {
     return false;
   }
   gfx::SurfaceFormat format =
     gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aContent);
-  size_t size = ImageDataSerializer::ComputeMinBufferSize(aSize, format);
+  size_t size = ImageDataSerializer::ComputeRGBBufferSize(aSize, format);
   if (!size) {
     return false;
   }
+
+  MemoryOrShmem bufferDesc;
   if (IsSameProcess()) {
-    uint8_t *data = new (std::nothrow) uint8_t[size];
+    uint8_t* data = new (std::nothrow) uint8_t[size];
     if (!data) {
       return false;
     }
     GfxMemoryImageReporter::DidAlloc(data);
 #ifdef XP_MACOSX
     // Workaround a bug in Quartz where drawing an a8 surface to another a8
     // surface with OP_SOURCE still requires the destination to be clear.
     if (format == gfx::SurfaceFormat::A8) {
       memset(data, 0, size);
     }
 #endif
-    *aBuffer = SurfaceDescriptorMemory((uintptr_t)data, format);
+    bufferDesc = reinterpret_cast<uintptr_t>(data);
   } else {
 
     mozilla::ipc::SharedMemory::SharedMemoryType shmemType = OptimalShmemType();
     mozilla::ipc::Shmem shmem;
     if (!AllocUnsafeShmem(size, shmemType, &shmem)) {
       return false;
     }
 
-    *aBuffer = SurfaceDescriptorShmem(shmem, format);
+    bufferDesc = shmem;
   }
-  
-  uint8_t* data = GetAddressFromDescriptor(*aBuffer, size);
-  ImageDataSerializer serializer(data, size);
-  serializer.InitializeBufferInfo(aSize, format);
+
+  *aBuffer = SurfaceDescriptorBuffer(RGBDescriptor(aSize, format), bufferDesc);
+
   return true;
 }
 
 /* static */ bool
 ISurfaceAllocator::IsShmem(SurfaceDescriptor* aSurface)
 {
-  return aSurface && (aSurface->type() == SurfaceDescriptor::TSurfaceDescriptorShmem);
+  return aSurface && (aSurface->type() == SurfaceDescriptor::TSurfaceDescriptorBuffer)
+      && (aSurface->get_SurfaceDescriptorBuffer().data().type() == MemoryOrShmem::TShmem);
 }
 
 void
 ISurfaceAllocator::DestroySharedSurface(SurfaceDescriptor* aSurface)
 {
   MOZ_ASSERT(IPCOpen());
   if (!IPCOpen()) {
     return;
@@ -167,27 +169,28 @@ ISurfaceAllocator::DestroySharedSurface(
 
   MOZ_ASSERT(aSurface);
   if (!aSurface) {
     return;
   }
   if (!IPCOpen()) {
     return;
   }
-  switch (aSurface->type()) {
-    case SurfaceDescriptor::TSurfaceDescriptorShmem:
-      DeallocShmem(aSurface->get_SurfaceDescriptorShmem().data());
+  SurfaceDescriptorBuffer& desc = aSurface->get_SurfaceDescriptorBuffer();
+  switch (desc.data().type()) {
+    case MemoryOrShmem::TShmem: {
+      DeallocShmem(desc.data().get_Shmem());
       break;
-    case SurfaceDescriptor::TSurfaceDescriptorMemory:
-      GfxMemoryImageReporter::WillFree((uint8_t*)aSurface->get_SurfaceDescriptorMemory().data());
-      delete [] (uint8_t*)aSurface->get_SurfaceDescriptorMemory().data();
+    }
+    case MemoryOrShmem::Tuintptr_t: {
+      uint8_t* ptr = (uint8_t*)desc.data().get_uintptr_t();
+      GfxMemoryImageReporter::WillFree(ptr);
+      delete [] ptr;
       break;
-    case SurfaceDescriptor::Tnull_t:
-    case SurfaceDescriptor::T__None:
-      break;
+    }
     default:
       NS_RUNTIMEABORT("surface type not implemented!");
   }
   *aSurface = SurfaceDescriptor();
 }
 
 // XXX - We should actually figure out the minimum shmem allocation size on
 // a certain platform and use that.
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 using struct gfxPoint from "gfxPoint.h";
 using nsIntRegion from "nsRegion.h";
 using struct mozilla::layers::MagicGrallocBufferHandle from "gfxipc/ShadowLayerUtils.h";
 using struct mozilla::layers::GrallocBufferRef from "gfxipc/ShadowLayerUtils.h";
 using struct mozilla::layers::SurfaceDescriptorX11 from "gfxipc/ShadowLayerUtils.h";
+using mozilla::StereoMode from "ImageTypes.h";
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
 using mozilla::gfx::IntRect from "mozilla/gfx/Rect.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
 using gfxImageFormat from "gfxTypes.h";
 
 namespace mozilla {
@@ -90,35 +91,47 @@ struct SurfaceDescriptorSharedGLTexture 
   bool hasAlpha;
 };
 
 struct SurfaceDescriptorGralloc {
   MaybeMagicGrallocBufferHandle buffer;
   bool isOpaque;
 };
 
-/**
- * Used for shmem-backed YCbCr and (flavors of) RGBA textures
- */
-struct SurfaceDescriptorShmem {
-  Shmem data;
+struct RGBDescriptor {
+  IntSize size;
   SurfaceFormat format;
 };
 
-/**
- * Used for "raw memory"-backed YCbCr and (flavors of) RGBA textures
- */
-struct SurfaceDescriptorMemory {
-  uintptr_t data;
-  SurfaceFormat format;
+struct YCbCrDescriptor {
+  IntSize ySize;
+  IntSize cbCrSize;
+  uint32_t yOffset;
+  uint32_t cbOffset;
+  uint32_t crOffset;
+  StereoMode stereoMode;
+};
+
+union BufferDescriptor {
+  RGBDescriptor;
+  YCbCrDescriptor;
+};
+
+union MemoryOrShmem {
+  uintptr_t;
+  Shmem;
+};
+
+struct SurfaceDescriptorBuffer {
+  BufferDescriptor desc;
+  MemoryOrShmem data;
 };
 
 union SurfaceDescriptor {
-  SurfaceDescriptorShmem;
-  SurfaceDescriptorMemory;
+  SurfaceDescriptorBuffer;
   SurfaceDescriptorD3D9;
   SurfaceDescriptorDIB;
   SurfaceDescriptorD3D10;
   SurfaceDescriptorFileMapping;
   SurfaceDescriptorDXGIYCbCr;
   SurfaceDescriptorX11;
   SurfaceTextureDescriptor;
   EGLImageDescriptor;
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -314,21 +314,22 @@ ShadowLayerForwarder::RepositionChild(Sh
 #ifdef DEBUG
 void
 ShadowLayerForwarder::CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const
 {
   if (!aDescriptor) {
     return;
   }
 
-  if (aDescriptor->type() == SurfaceDescriptor::TSurfaceDescriptorShmem) {
-    const SurfaceDescriptorShmem& shmem = aDescriptor->get_SurfaceDescriptorShmem();
-    shmem.data().AssertInvariants();
+  if (aDescriptor->type() == SurfaceDescriptor::TSurfaceDescriptorBuffer &&
+      aDescriptor->get_SurfaceDescriptorBuffer().data().type() == MemoryOrShmem::TShmem) {
+    const Shmem& shmem = aDescriptor->get_SurfaceDescriptorBuffer().data().get_Shmem();
+    shmem.AssertInvariants();
     MOZ_ASSERT(mShadowManager &&
-               mShadowManager->IsTrackingSharedMemory(shmem.data().mSegment));
+               mShadowManager->IsTrackingSharedMemory(shmem.mSegment));
   }
 }
 #endif
 
 void
 ShadowLayerForwarder::UseTiledLayerBuffer(CompositableClient* aCompositable,
                                           const SurfaceDescriptorTiles& aTileLayerDescriptor)
 {
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -10,17 +10,17 @@
 #include "ISurfaceAllocator.h"          // for ISurfaceAllocator, etc
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat::SurfaceFormat::YUV
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
 #include "mozilla/layers/ImageClient.h"  // for ImageClient
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/BufferTexture.h"
-#include "mozilla/layers/YCbCrImageDataSerializer.h"
+#include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/ImageBridgeChild.h"  // for ImageBridgeChild
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsISupportsImpl.h"            // for Image::AddRef
 #include "mozilla/ipc/Shmem.h"
 
 namespace mozilla {
 namespace layers {
 
@@ -107,79 +107,66 @@ SharedPlanarYCbCrImage::SetData(const Pl
 }
 
 // needs to be overriden because the parent class sets mBuffer which we
 // do not want to happen.
 uint8_t*
 SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
 {
   MOZ_ASSERT(!mTextureClient, "This image already has allocated data");
-  size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aSize);
+  size_t size = ImageDataSerializer::ComputeYCbCrBufferSize(aSize);
   if (!size) {
     return nullptr;
   }
 
-  mTextureClient = TextureClient::CreateWithBufferSize(mCompositable->GetForwarder(),
-                                                       gfx::SurfaceFormat::YUV, size,
-                                                       mCompositable->GetTextureFlags());
+  mTextureClient = TextureClient::CreateForYCbCrWithBufferSize(mCompositable->GetForwarder(),
+                                                               gfx::SurfaceFormat::YUV, size,
+                                                               mCompositable->GetTextureFlags());
 
   // get new buffer _without_ setting mBuffer.
   if (!mTextureClient) {
     return nullptr;
   }
 
   // update buffer size
   mBufferSize = size;
 
   MappedYCbCrTextureData mapped;
   if (mTextureClient->BorrowMappedYCbCrData(mapped)) {
     // The caller expects a pointer to the beginning of the writable part of the
-    // buffer (after the metadata) which is where the y channel starts by default.
-    // The caller might choose to write the y channel at a different offset and
-    // if it does so, it will also update the metadata.
-    // Anyway, we return the y channel here but the intent is to obtain the start of
-    // the writable part of the buffer.
+    // buffer which is where the y channel starts by default.
     return mapped.y.data;
   } else {
     MOZ_CRASH();
   }
 }
 
 bool
 SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
 {
+  // SetDataNoCopy is used to update YUV plane offsets without (re)allocating
+  // memory previously allocated with AllocateAndGetNewBuffer().
+
   MOZ_ASSERT(mTextureClient, "This Image should have already allocated data");
   if (!mTextureClient) {
     return false;
   }
   mData = aData;
   mSize = aData.mPicSize;
-  /* SetDataNoCopy is used to update YUV plane offsets without (re)allocating
-   * memory previously allocated with AllocateAndGetNewBuffer().
-   * serializer.GetData() returns the address of the memory previously allocated
-   * with AllocateAndGetNewBuffer(), that we subtract from the Y, Cb, Cr
-   * channels to compute 0-based offsets to pass to InitializeBufferInfo.
-   */
-  MappedYCbCrTextureData mapped;
-  if(!mTextureClient->BorrowMappedYCbCrData(mapped)) {
-    MOZ_CRASH();
-  }
-  YCbCrImageDataSerializer serializer(mapped.metadata, mBufferSize);
-  uint8_t *base = serializer.GetData();
+
+  uint8_t *base = GetBuffer();
   uint32_t yOffset = aData.mYChannel - base;
   uint32_t cbOffset = aData.mCbChannel - base;
   uint32_t crOffset = aData.mCrChannel - base;
-  serializer.InitializeBufferInfo(yOffset,
-                                  cbOffset,
-                                  crOffset,
-                                  aData.mYStride,
-                                  aData.mCbCrStride,
-                                  aData.mYSize,
-                                  aData.mCbCrSize,
-                                  aData.mStereoMode);
+
+  static_cast<BufferTextureData*>(mTextureClient->GetInternalData())->SetDesciptor(
+    YCbCrDescriptor(aData.mYSize, aData.mCbCrSize, yOffset, cbOffset, crOffset,
+                    aData.mStereoMode)
+  );
+
   return true;
 }
 
 bool
 SharedPlanarYCbCrImage::IsValid() {
   return !!mTextureClient;
 }
 
@@ -227,18 +214,17 @@ SharedPlanarYCbCrImage::Allocate(PlanarY
   mData.mCbSkip = 0;
   mData.mCrSkip = 0;
   mData.mYStride = mData.mYSize.width;
   mData.mCbCrStride = mData.mCbCrSize.width;
 
   // do not set mBuffer like in PlanarYCbCrImage because the later
   // will try to manage this memory without knowing it belongs to a
   // shmem.
-  mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize,
-                                                               mData.mCbCrSize);
+  mBufferSize = ImageDataSerializer::ComputeYCbCrBufferSize(mData.mYSize, mData.mCbCrSize);
   mSize = mData.mPicSize;
 
   mTextureClient->Unlock();
 
   return mBufferSize > 0;
 }
 
 } // namespace layers
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -175,17 +175,16 @@ EXPORTS.mozilla.layers += [
     'opengl/MacIOSurfaceTextureClientOGL.h',
     'opengl/MacIOSurfaceTextureHostOGL.h',
     'opengl/TextureClientOGL.h',
     'opengl/TextureHostOGL.h',
     'PersistentBufferProvider.h',
     'RenderTrace.h',
     'TextureWrapperImage.h',
     'TransactionIdAllocator.h',
-    'YCbCrImageDataSerializer.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS.mozilla.layers += [
         'basic/TextureClientX11.h',
         'basic/X11TextureSourceBasic.h',
         'composite/X11TextureHost.h',
         'ipc/ShadowLayerUtilsX11.h',
@@ -245,17 +244,16 @@ UNIFIED_SOURCES += [
     'apz/src/APZCTreeManager.cpp',
     'apz/src/AsyncPanZoomController.cpp',
     'apz/src/Axis.cpp',
     'apz/src/GestureEventListener.cpp',
     'apz/src/HitTestingTreeNode.cpp',
     'apz/src/InputBlockState.cpp',
     'apz/src/InputQueue.cpp',
     'apz/src/OverscrollHandoffState.cpp',
-    'apz/src/TaskThrottler.cpp',
     'apz/src/TouchCounter.cpp',
     'apz/src/WheelScrollAnimation.cpp',
     'apz/testutil/APZTestData.cpp',
     'apz/util/ActiveElementManager.cpp',
     'apz/util/APZCCallbackHelper.cpp',
     'apz/util/APZEventState.cpp',
     'apz/util/APZThreadUtils.cpp',
     'apz/util/ChromeProcessController.cpp',
@@ -347,17 +345,16 @@ UNIFIED_SOURCES += [
     'opengl/TextureClientOGL.cpp',
     'opengl/TextureHostOGL.cpp',
     'opengl/TexturePoolOGL.cpp',
     'protobuf/LayerScopePacket.pb.cc',
     'ReadbackProcessor.cpp',
     'RenderTrace.cpp',
     'RotatedBuffer.cpp',
     'TextureWrapperImage.cpp',
-    'YCbCrImageDataSerializer.cpp',
 ]
 
 SOURCES += [
     'basic/BasicImageLayer.cpp',
     'ImageContainer.cpp',
     'Layers.cpp',
     'LayerTreeInvalidation.cpp',
     'PersistentBufferProvider.cpp',
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -11,17 +11,16 @@
 #include "GLUploadHelpers.h"
 #include "GLReadTexImageHelper.h"
 #include "gfx2DGlue.h"                  // for ContentForFormat, etc
 #include "gfxReusableSurfaceWrapper.h"  // for gfxReusableSurfaceWrapper
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Logging.h"        // for gfxCriticalError
 #include "mozilla/layers/ISurfaceAllocator.h"
-#include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "mozilla/layers/GrallocTextureHost.h"
 #include "nsRegion.h"                   // for nsIntRegion
 #include "AndroidSurfaceTexture.h"
 #include "GfxTexturesReporter.h"        // for GfxTexturesReporter
 #include "GLBlitTextureImageHelper.h"
 #include "GeckoProfiler.h"
 
 #ifdef MOZ_WIDGET_GONK
@@ -47,18 +46,17 @@ class Compositor;
 
 already_AddRefed<TextureHost>
 CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
                      ISurfaceAllocator* aDeallocator,
                      TextureFlags aFlags)
 {
   RefPtr<TextureHost> result;
   switch (aDesc.type()) {
-    case SurfaceDescriptor::TSurfaceDescriptorShmem:
-    case SurfaceDescriptor::TSurfaceDescriptorMemory: {
+    case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
       result = CreateBackendIndependentTextureHost(aDesc,
                                                    aDeallocator, aFlags);
       break;
     }
 
 #ifdef MOZ_WIDGET_ANDROID
     case SurfaceDescriptor::TSurfaceTextureDescriptor: {
       const SurfaceTextureDescriptor& desc = aDesc.get_SurfaceTextureDescriptor();
--- a/gfx/tests/gtest/TestTextures.cpp
+++ b/gfx/tests/gtest/TestTextures.cpp
@@ -11,17 +11,17 @@
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/layers/BufferTexture.h"
 #include "mozilla/RefPtr.h"
 #include "gfx2DGlue.h"
 #include "gfxImageSurface.h"
 #include "gfxTypes.h"
 #include "ImageContainer.h"
-#include "mozilla/layers/YCbCrImageDataSerializer.h"
+#include "mozilla/layers/ImageDataSerializer.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 /*
  * This test performs the following actions:
  * - creates a surface
@@ -114,41 +114,16 @@ void AssertSurfacesEqual(SourceSurface* 
       }
     }
   }
 
   dataSurface1->Unmap();
   dataSurface2->Unmap();
 }
 
-// Same as above, for YCbCr surfaces
-void AssertYCbCrSurfacesEqual(PlanarYCbCrData* surface1,
-                              PlanarYCbCrData* surface2)
-{
-  ASSERT_EQ(surface1->mYSize, surface2->mYSize);
-  ASSERT_EQ(surface1->mCbCrSize, surface2->mCbCrSize);
-  ASSERT_EQ(surface1->mStereoMode, surface2->mStereoMode);
-  ASSERT_EQ(surface1->mPicSize, surface2->mPicSize);
-
-  for (int y = 0; y < surface1->mYSize.height; ++y) {
-    for (int x = 0; x < surface1->mYSize.width; ++x) {
-      ASSERT_EQ(surface1->mYChannel[y*surface1->mYStride + x*(1+surface1->mYSkip)],
-                surface2->mYChannel[y*surface2->mYStride + x*(1+surface2->mYSkip)]);
-    }
-  }
-  for (int y = 0; y < surface1->mCbCrSize.height; ++y) {
-    for (int x = 0; x < surface1->mCbCrSize.width; ++x) {
-      ASSERT_EQ(surface1->mCbChannel[y*surface1->mCbCrStride + x*(1+surface1->mCbSkip)],
-                surface2->mCbChannel[y*surface2->mCbCrStride + x*(1+surface2->mCbSkip)]);
-      ASSERT_EQ(surface1->mCrChannel[y*surface1->mCbCrStride + x*(1+surface1->mCrSkip)],
-                surface2->mCrChannel[y*surface2->mCbCrStride + x*(1+surface2->mCrSkip)]);
-    }
-  }
-}
-
 // Run the test for a texture client and a surface
 void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {
 
   // client allocation
   ASSERT_TRUE(texture->CanExposeDrawTarget());
 
   ASSERT_TRUE(texture->Lock(OpenMode::OPEN_READ_WRITE));
   // client painting
@@ -201,52 +176,38 @@ void TestTextureClientYCbCr(TextureClien
   client->Lock(OpenMode::OPEN_READ_WRITE);
   UpdateYCbCrTextureClient(client, ycbcrData);
   client->Unlock();
 
   // client serialization
   SurfaceDescriptor descriptor;
   ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor));
 
-  ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);
+  ASSERT_EQ(descriptor.type(), SurfaceDescriptor::TSurfaceDescriptorBuffer);
+  auto bufferDesc = descriptor.get_SurfaceDescriptorBuffer();
+  ASSERT_EQ(bufferDesc.desc().type(), BufferDescriptor::TYCbCrDescriptor);
+  auto ycbcrDesc = bufferDesc.desc().get_YCbCrDescriptor();
+  ASSERT_EQ(ycbcrDesc.ySize(), ycbcrData.mYSize);
+  ASSERT_EQ(ycbcrDesc.cbCrSize(), ycbcrData.mCbCrSize);
+  ASSERT_EQ(ycbcrDesc.stereoMode(), ycbcrData.mStereoMode);
 
   // host deserialization
   RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, nullptr,
                                                                         client->GetFlags());
 
   RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get());
 
   ASSERT_TRUE(host.get() != nullptr);
   ASSERT_EQ(host->GetFlags(), client->GetFlags());
 
   // host read
 
   if (host->Lock()) {
     // This will work iff the compositor is not BasicCompositor
     ASSERT_EQ(host->GetFormat(), mozilla::gfx::SurfaceFormat::YUV);
-
-    YCbCrImageDataDeserializer yuvDeserializer(host->GetBuffer(), host->GetBufferSize());
-    ASSERT_TRUE(yuvDeserializer.IsValid());
-    PlanarYCbCrData data;
-    data.mYChannel = yuvDeserializer.GetYData();
-    data.mCbChannel = yuvDeserializer.GetCbData();
-    data.mCrChannel = yuvDeserializer.GetCrData();
-    data.mYStride = yuvDeserializer.GetYStride();
-    data.mCbCrStride = yuvDeserializer.GetCbCrStride();
-    data.mStereoMode = yuvDeserializer.GetStereoMode();
-    data.mYSize = yuvDeserializer.GetYSize();
-    data.mCbCrSize = yuvDeserializer.GetCbCrSize();
-    data.mYSkip = 0;
-    data.mCbSkip = 0;
-    data.mCrSkip = 0;
-    data.mPicSize = data.mYSize;
-    data.mPicX = 0;
-    data.mPicY = 0;
-
-    AssertYCbCrSurfacesEqual(&ycbcrData, &data);
     host->Unlock();
   }
 }
 
 } // namespace layers
 } // namespace mozilla
 
 TEST(Layers, TextureSerialization) {
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -162,31 +162,29 @@ private:
   DECL_GFX_PREF(Live, "apz.fling_repaint_interval",            APZFlingRepaintInterval, int32_t, 75);
   DECL_GFX_PREF(Live, "apz.fling_stop_on_tap_threshold",       APZFlingStopOnTapThreshold, float, 0.05f);
   DECL_GFX_PREF(Live, "apz.fling_stopped_threshold",           APZFlingStoppedThreshold, float, 0.01f);
   DECL_GFX_PREF(Live, "apz.highlight_checkerboarded_areas",    APZHighlightCheckerboardedAreas, bool, false);
   DECL_GFX_PREF(Live, "apz.max_velocity_inches_per_ms",        APZMaxVelocity, float, -1.0f);
   DECL_GFX_PREF(Once, "apz.max_velocity_queue_size",           APZMaxVelocityQueueSize, uint32_t, 5);
   DECL_GFX_PREF(Live, "apz.min_skate_speed",                   APZMinSkateSpeed, float, 1.0f);
   DECL_GFX_PREF(Live, "apz.minimap.enabled",                   APZMinimap, bool, false);
-  DECL_GFX_PREF(Live, "apz.num_paint_duration_samples",        APZNumPaintDurationSamples, int32_t, 3);
   DECL_GFX_PREF(Live, "apz.overscroll.enabled",                APZOverscrollEnabled, bool, false);
   DECL_GFX_PREF(Live, "apz.overscroll.min_pan_distance_ratio", APZMinPanDistanceRatio, float, 1.0f);
   DECL_GFX_PREF(Live, "apz.overscroll.spring_friction",        APZOverscrollSpringFriction, float, 0.015f);
   DECL_GFX_PREF(Live, "apz.overscroll.spring_stiffness",       APZOverscrollSpringStiffness, float, 0.001f);
   DECL_GFX_PREF(Live, "apz.overscroll.stop_distance_threshold", APZOverscrollStopDistanceThreshold, float, 5.0f);
   DECL_GFX_PREF(Live, "apz.overscroll.stop_velocity_threshold", APZOverscrollStopVelocityThreshold, float, 0.01f);
   DECL_GFX_PREF(Live, "apz.overscroll.stretch_factor",         APZOverscrollStretchFactor, float, 0.5f);
   DECL_GFX_PREF(Live, "apz.pan_repaint_interval",              APZPanRepaintInterval, int32_t, 250);
   DECL_GFX_PREF(Live, "apz.printtree",                         APZPrintTree, bool, false);
   DECL_GFX_PREF(Live, "apz.smooth_scroll_repaint_interval",    APZSmoothScrollRepaintInterval, int32_t, 75);
   DECL_GFX_PREF(Live, "apz.test.logging_enabled",              APZTestLoggingEnabled, bool, false);
   DECL_GFX_PREF(Live, "apz.touch_move_tolerance",              APZTouchMoveTolerance, float, 0.0);
   DECL_GFX_PREF(Live, "apz.touch_start_tolerance",             APZTouchStartTolerance, float, 1.0f/4.5f);
-  DECL_GFX_PREF(Live, "apz.use_paint_duration",                APZUsePaintDuration, bool, true);
   DECL_GFX_PREF(Live, "apz.velocity_bias",                     APZVelocityBias, float, 1.0f);
   DECL_GFX_PREF(Live, "apz.velocity_relevance_time_ms",        APZVelocityRelevanceTime, uint32_t, 150);
   DECL_GFX_PREF(Live, "apz.x_skate_highmem_adjust",            APZXSkateHighMemAdjust, float, 0.0f);
   DECL_GFX_PREF(Live, "apz.x_skate_size_multiplier",           APZXSkateSizeMultiplier, float, 1.5f);
   DECL_GFX_PREF(Live, "apz.x_stationary_size_multiplier",      APZXStationarySizeMultiplier, float, 3.0f);
   DECL_GFX_PREF(Live, "apz.y_skate_highmem_adjust",            APZYSkateHighMemAdjust, float, 0.0f);
   DECL_GFX_PREF(Live, "apz.y_skate_size_multiplier",           APZYSkateSizeMultiplier, float, 2.5f);
   DECL_GFX_PREF(Live, "apz.y_stationary_size_multiplier",      APZYStationarySizeMultiplier, float, 3.5f);
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -6865,17 +6865,17 @@ Warn(AsmJSParser& parser, int errorNumbe
                                  : ParseWarning;
     parser.reportNoOffset(reportKind, /* strict = */ false, errorNumber, str ? str : "");
     return false;
 }
 
 static bool
 EstablishPreconditions(ExclusiveContext* cx, AsmJSParser& parser)
 {
-#ifdef JS_CODEGEN_NONE
+#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
     return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by lack of a JIT compiler");
 #endif
 
     if (!cx->jitSupportsFloatingPoint())
         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by lack of floating point support");
 
     if (cx->gcSystemPageSize() != AsmJSPageSize)
         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by non 4KiB system page size");
@@ -6975,17 +6975,17 @@ js::ValidateAsmJS(ExclusiveContext* cx, 
 }
 
 bool
 js::IsAsmJSCompilationAvailable(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // See EstablishPreconditions.
-#ifdef JS_CODEGEN_NONE
+#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
     bool available = false;
 #else
     bool available = cx->jitSupportsFloatingPoint() &&
                      cx->gcSystemPageSize() == AsmJSPageSize &&
                      cx->runtime()->options().asmJS();
 #endif
 
     args.rval().set(BooleanValue(available));
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -2941,17 +2941,17 @@ wasm::CompileFunction(CompileTask* task)
     FunctionCompileResults& results = task->results();
 
     JitContext jitContext(CompileRuntime::get(args.runtime), &results.alloc());
 
     const JitCompileOptions options;
     MIRGraph graph(&results.alloc());
     CompileInfo compileInfo(func.numLocals());
     MIRGenerator mir(nullptr, options, &results.alloc(), &graph, &compileInfo,
-                     IonOptimizations.get(Optimization_AsmJS),
+                     IonOptimizations.get(OptimizationLevel::AsmJS),
                      args.usesSignalHandlersForOOB);
 
     // Build MIR graph
     {
         FunctionCompiler f(args, func, mir, results);
         if (!f.init())
             return false;
 
--- a/js/src/builtin/Reflect.cpp
+++ b/js/src/builtin/Reflect.cpp
@@ -194,21 +194,17 @@ Reflect_enumerate(JSContext* cx, unsigne
     RootedObject iterator(cx);
     if (!Enumerate(cx, obj, &iterator))
         return false;
     args.rval().setObject(*iterator);
     return true;
 }
 #endif
 
-/*
- * ES6 26.1.6 Reflect.get(target, propertyKey [, receiver])
- *
- * Primitive receivers are not supported yet (see bug 603201).
- */
+/* ES6 26.1.6 Reflect.get(target, propertyKey [, receiver]) */
 static bool
 Reflect_get(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     RootedObject obj(cx, NonNullObject(cx, args.get(0)));
     if (!obj)
@@ -216,26 +212,20 @@ Reflect_get(JSContext* cx, unsigned argc
 
     // Steps 2-3.
     RootedValue propertyKey(cx, args.get(1));
     RootedId key(cx);
     if (!ToPropertyKey(cx, propertyKey, &key))
         return false;
 
     // Step 4.
-    RootedValue receiver(cx, argc > 2 ? args[2] : args.get(0));
-
-    // Non-standard hack: Throw a TypeError if the receiver isn't an object.
-    // See bug 603201.
-    RootedObject receiverObj(cx, NonNullObject(cx, receiver));
-    if (!receiverObj)
-        return false;
+    RootedValue receiver(cx, args.length() > 2 ? args[2] : args.get(0));
 
     // Step 5.
-    return GetProperty(cx, obj, receiverObj, key, args.rval());
+    return GetProperty(cx, obj, receiver, key, args.rval());
 }
 
 /* ES6 26.1.7 Reflect.getOwnPropertyDescriptor(target, propertyKey) */
 static bool
 Reflect_getOwnPropertyDescriptor(JSContext* cx, unsigned argc, Value* vp)
 {
     // Step 1.
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -331,17 +321,17 @@ Reflect_set(JSContext* cx, unsigned argc
 
     // Steps 2-3.
     RootedValue propertyKey(cx, args.get(1));
     RootedId key(cx);
     if (!ToPropertyKey(cx, propertyKey, &key))
         return false;
 
     // Step 4.
-    RootedValue receiver(cx, argc > 3 ? args[3] : args.get(0));
+    RootedValue receiver(cx, args.length() > 3 ? args[3] : args.get(0));
 
     // Step 5.
     ObjectOpResult result;
     RootedValue value(cx, args.get(2));
     if (!SetProperty(cx, target, key, value, receiver, result))
         return false;
     args.rval().setBoolean(bool(result));
     return true;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -301,18 +301,18 @@ GC(JSContext* cx, unsigned argc, Value* 
     else
         JS::PrepareForFullGC(cx->runtime());
 
     JSGCInvocationKind gckind = shrinking ? GC_SHRINK : GC_NORMAL;
     JS::GCForReason(cx->runtime(), gckind, JS::gcreason::API);
 
     char buf[256] = { '\0' };
 #ifndef JS_MORE_DETERMINISTIC
-    JS_snprintf(buf, sizeof(buf), "before %lu, after %lu\n",
-                (unsigned long)preBytes, (unsigned long)cx->runtime()->gc.usage.gcBytes());
+    JS_snprintf(buf, sizeof(buf), "before %" PRIuSIZE ", after %" PRIuSIZE "\n",
+                preBytes, cx->runtime()->gc.usage.gcBytes());
 #endif
     JSString* str = JS_NewStringCopyZ(cx, buf);
     if (!str)
         return false;
     args.rval().setString(str);
     return true;
 }
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -68,18 +68,18 @@ AC_PROG_AWK
 dnl Initialize the Pthread test variables early so they can be
 dnl  overridden by each platform.
 dnl ========================================================
 USE_PTHREADS=
 _PTHREAD_LDFLAGS=""
 
 dnl Do not allow objdir == srcdir builds
 dnl ==============================================================
-_topsrcdir=`cd $srcdir; pwd -W 2>/dev/null || pwd`
-_objdir=`pwd`
+_topsrcdir=`cd $srcdir; pwd -W 2>/dev/null || pwd -P`
+_objdir=`pwd -P`
 
 if test "$_topsrcdir" = "$_objdir"
 then
   echo "  ***"
   echo "  * Building directly in the main source directory is not allowed."
   echo "  *"
   echo "  * To build, you must run configure from a separate directory"
   echo "  * (referred to as an object directory)."
@@ -107,17 +107,17 @@ if test "$_conflict_files"; then
 	*   To clean up the source tree:
 	*     1. cd $_topsrcdir
 	*     2. gmake distclean
 	***
 	EOF
   exit 1
   break
 fi
-MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd`
+MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd -P`
 
 MOZ_BUILD_BACKEND
 
 MOZ_DEFAULT_COMPILER
 
 COMPILE_ENVIRONMENT=1
 MOZ_ARG_DISABLE_BOOL(compile-environment,
 [  --disable-compile-environment
new file mode 100644
--- /dev/null
+++ b/js/src/devtools/automation/arm64-jstests-slow.txt
@@ -0,0 +1,52 @@
+ecma/Date/15.9.5.10-2.js
+ecma/Date/15.9.5.11-2.js
+ecma/Date/15.9.5.12-2.js
+ecma/Date/15.9.5.8.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-01-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-02-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-03-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-04-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-05-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-06-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-07-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-08-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-09-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-10-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-11-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-12-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-13-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-14-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-15-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-16-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-17-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-18-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-19-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-20-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-21-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-22-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-23-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-24-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-25-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-26-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-27-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-30-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-31-of-32.js
+ecma_5/Object/15.2.3.6-dictionary-redefinition-32-of-32.js
+ecma_5/Object/15.2.3.6-middle-redefinition-1-of-8.js
+ecma_5/Object/15.2.3.6-middle-redefinition-2-of-8.js
+ecma_5/Object/15.2.3.6-middle-redefinition-3-of-8.js
+ecma_5/Object/15.2.3.6-middle-redefinition-4-of-8.js
+ecma_5/Object/15.2.3.6-middle-redefinition-5-of-8.js
+ecma_5/Object/15.2.3.6-middle-redefinition-6-of-8.js
+ecma_5/Object/15.2.3.6-middle-redefinition-7-of-8.js
+ecma_5/Object/15.2.3.6-middle-redefinition-8-of-8.js
+ecma_5/Object/15.2.3.6-redefinition-1-of-4.js
+ecma_5/Object/15.2.3.6-redefinition-2-of-4.js
+ecma_5/Object/15.2.3.6-redefinition-3-of-4.js
+ecma_5/Object/15.2.3.6-redefinition-4-of-4.js
+ecma_6/Comprehensions/sudoku.js
+js1_8/extensions/regress-476427.js
+js1_8_5/extensions/clone-complex-object.js
+js1_8_5/reflect-parse/classes.js
+js1_8_5/reflect-parse/destructuring-variable-declarations.js
+js1_8_5/regress/no-array-comprehension-length-limit.js
--- a/js/src/devtools/automation/autospider.sh
+++ b/js/src/devtools/automation/autospider.sh
@@ -212,20 +212,20 @@ elif [[ "$VARIANT" = "warnaserr" ||
         "$VARIANT" = "warnaserrdebug" ||
         "$VARIANT" = "plain" ]]; then
     export JSTESTS_EXTRA_ARGS=--jitflags=all
 elif [[ "$VARIANT" = "arm-sim" ||
         "$VARIANT" = "arm-sim-osx" ||
         "$VARIANT" = "plaindebug" ]]; then
     export JSTESTS_EXTRA_ARGS=--jitflags=debug
 elif [[ "$VARIANT" = arm64* ]]; then
-    # The ARM64 JIT is not yet fully functional, and asm.js does not work.
-    # Just run "make check" and jsapi-tests.
-    RUN_JITTEST=false
-    RUN_JSTESTS=false
+    # The ARM64 simulator is slow, so some tests are timing out.
+    # Run a reduced set of test cases so this doesn't take hours.
+    export JSTESTS_EXTRA_ARGS="--exclude-file=$ABSDIR/arm64-jstests-slow.txt"
+    export JITTEST_EXTRA_ARGS="--jitflags=none --args=--baseline-eager -x ion/ -x asm.js/"
 fi
 
 $COMMAND_PREFIX $MAKE check || exit 1
 
 RESULT=0
 
 if $RUN_JITTEST; then
     $COMMAND_PREFIX $MAKE check-jit-test || RESULT=$?
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6775,16 +6775,23 @@ Parser<FullParseHandler>::classDefinitio
 
         if (tt == TOK_SEMI)
             continue;
 
         bool isStatic = false;
         if (tt == TOK_NAME && tokenStream.currentName() == context->names().static_) {
             if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName))
                 return null();
+            if (tt == TOK_RC) {
+                tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName);
+                report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
+                       "property name", TokenKindToDesc(tt));
+                return null();
+            }
+
             if (tt != TOK_LP) {
                 if (!checkUnescapedName())
                     return null();
 
                 isStatic = true;
             } else {
                 tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName);
                 tokenStream.ungetToken();
@@ -9244,18 +9251,17 @@ template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
                                    PropertyType* propType, MutableHandleAtom propAtom)
 {
     TokenKind ltok;
     if (!tokenStream.getToken(&ltok, TokenStream::KeywordIsName))
         return null();
 
-    // TOK_RC should be handled in caller.
-    MOZ_ASSERT(ltok != TOK_RC);
+    MOZ_ASSERT(ltok != TOK_RC, "caller should have handled TOK_RC");
 
     bool isGenerator = false;
     if (ltok == TOK_MUL) {
         isGenerator = true;
         if (!tokenStream.getToken(&ltok, TokenStream::KeywordIsName))
             return null();
     }
 
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -496,25 +496,25 @@ JS_GetTraceThingInfo(char* buf, size_t b
             *buf++ = ' ';
             bufsize--;
             JSString* str = (JSString*)thing;
 
             if (str->isLinear()) {
                 bool willFit = str->length() + strlen("<length > ") +
                                CountDecimalDigits(str->length()) < bufsize;
 
-                n = JS_snprintf(buf, bufsize, "<length %d%s> ",
-                                (int)str->length(),
+                n = JS_snprintf(buf, bufsize, "<length %" PRIuSIZE "%s> ",
+                                str->length(),
                                 willFit ? "" : " (truncated)");
                 buf += n;
                 bufsize -= n;
 
                 PutEscapedString(buf, bufsize, &str->asLinear(), 0);
             } else {
-                JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
+                JS_snprintf(buf, bufsize, "<rope: length %" PRIuSIZE ">", str->length());
             }
             break;
           }
 
           case JS::TraceKind::Symbol:
           {
             JS::Symbol* sym = static_cast<JS::Symbol*>(thing);
             if (JSString* desc = sym->description()) {
--- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
@@ -117,18 +117,17 @@ NativeRegExpMacroAssembler::GenerateCode
     Label return_temp0;
 
     // Finalize code - write the entry point code now we know how many
     // registers we need.
     masm.bind(&entry_label_);
 
 #ifdef JS_CODEGEN_ARM64
     // ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing.
-    MOZ_ASSERT(!masm.GetStackPointer64().Is(sp));
-    masm.Mov(masm.GetStackPointer64(), sp);
+    masm.initStackPtr();
 #endif
 
     // Push non-volatile registers which might be modified by jitcode.
     size_t pushedNonVolatileRegisters = 0;
     for (GeneralRegisterForwardIterator iter(savedNonVolatileRegisters); iter.more(); ++iter) {
         masm.Push(*iter);
         pushedNonVolatileRegisters++;
     }
--- a/js/src/jit-test/lib/jitopts.js
+++ b/js/src/jit-test/lib/jitopts.js
@@ -4,16 +4,22 @@
 // different set of JIT toggles are set, since TBPL runs each jit-test
 // multiple times with a variety of flags.
 function jitTogglesMatch(opts) {
   var currentOpts = getJitCompilerOptions();
   for (var k in opts) {
     if (k.indexOf(".enable") > 0 && opts[k] != currentOpts[k])
       return false;
   }
+
+  // ARM64 does not yet have an Ion code generator, so return false if
+  // ion.enable is requested.
+  if (getBuildConfiguration()['arm64-simulator'] && opts['ion.enable'])
+    return false;
+
   return true;
 }
 
 // Run fn under a particular set of JIT options.
 function withJitOptions(opts, fn) {
   var oldOpts = getJitCompilerOptions();
   for (var k in opts)
     setJitCompilerOption(k, opts[k]);
--- a/js/src/jit-test/tests/debug/Debugger-allowUnobservedAsmJS-02.js
+++ b/js/src/jit-test/tests/debug/Debugger-allowUnobservedAsmJS-02.js
@@ -14,10 +14,12 @@ assertEq(g.dbg.allowUnobservedAsmJS, fal
 enableLastWarning();
 
 var asmFunStr = USE_ASM + 'function f() {} return f';
 offThreadCompileScript("(function() {" + asmFunStr + "})");
 runOffThreadScript();
 
 var msg = getLastWarning().message;
 assertEq(msg === "asm.js type error: Disabled by debugger" ||
+         msg === "asm.js type error: Disabled by lack of a JIT compiler" ||
+         msg === "asm.js type error: Disabled by javascript.options.asmjs in about:config" ||
          msg === "asm.js type error: Disabled by lack of floating point support",
          true);
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2103,18 +2103,16 @@ IonCompile(JSContext* cx, JSScript* scri
            BaselineFrame* baselineFrame, jsbytecode* osrPc, bool constructing,
            bool recompile, OptimizationLevel optimizationLevel)
 {
     TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
     TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, script);
     AutoTraceLog logScript(logger, event);
     AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
 
-    MOZ_ASSERT(optimizationLevel > Optimization_DontCompile);
-
     // Make sure the script's canonical function isn't lazy. We can't de-lazify
     // it in a helper thread.
     script->ensureNonLazyCanonicalFunction(cx);
 
     TrackPropertiesForSingletonScopes(cx, script, baselineFrame);
 
     LifoAlloc* alloc = cx->new_<LifoAlloc>(TempAllocator::PreferredLifoChunkSize);
     if (!alloc)
@@ -2391,17 +2389,17 @@ Compile(JSContext* cx, HandleScript scri
     MethodStatus status = CheckScriptSize(cx, script);
     if (status != Method_Compiled) {
         JitSpew(JitSpew_IonAbort, "Aborted compilation of %s:%" PRIuSIZE, script->filename(), script->lineno());
         return status;
     }
 
     bool recompile = false;
     OptimizationLevel optimizationLevel = GetOptimizationLevel(script, osrPc);
-    if (optimizationLevel == Optimization_DontCompile)
+    if (optimizationLevel == OptimizationLevel::DontCompile)
         return Method_Skipped;
 
     if (script->hasIonScript()) {
         IonScript* scriptIon = script->ionScript();
         if (!scriptIon->method())
             return Method_CantCompile;
 
         // Don't recompile/overwrite higher optimized code,
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -3678,17 +3678,17 @@ jit::AnalyzeNewScriptDefiniteProperties(
         return false;
 
     CompileInfo info(script, fun,
                      /* osrPc = */ nullptr, /* constructing = */ false,
                      Analysis_DefiniteProperties,
                      script->needsArgsObj(),
                      inlineScriptTree);
 
-    const OptimizationInfo* optimizationInfo = IonOptimizations.get(Optimization_Normal);
+    const OptimizationInfo* optimizationInfo = IonOptimizations.get(OptimizationLevel::Normal);
 
     CompilerConstraintList* constraints = NewCompilerConstraintList(temp);
     if (!constraints) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     BaselineInspector inspector(script);
@@ -3899,17 +3899,17 @@ jit::AnalyzeArgumentsUsage(JSContext* cx
     }
 
     CompileInfo info(script, script->functionNonDelazifying(),
                      /* osrPc = */ nullptr, /* constructing = */ false,
                      Analysis_ArgumentsUsage,
                      /* needsArgsObj = */ true,
                      inlineScriptTree);
 
-    const OptimizationInfo* optimizationInfo = IonOptimizations.get(Optimization_Normal);
+    const OptimizationInfo* optimizationInfo = IonOptimizations.get(OptimizationLevel::Normal);
 
     CompilerConstraintList* constraints = NewCompilerConstraintList(temp);
     if (!constraints) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     BaselineInspector inspector(script);
--- a/js/src/jit/IonOptimizationLevels.cpp
+++ b/js/src/jit/IonOptimizationLevels.cpp
@@ -11,37 +11,38 @@
 #include "jit/Ion.h"
 
 using namespace js;
 using namespace js::jit;
 
 namespace js {
 namespace jit {
 
-OptimizationInfos IonOptimizations;
+OptimizationLevelInfo IonOptimizations;
 
 void
 OptimizationInfo::initNormalOptimizationInfo()
 {
-    level_ = Optimization_Normal;
+    level_ = OptimizationLevel::Normal;
 
+    autoTruncate_ = true;
     eaa_ = true;
+    eagerSimdUnbox_ = true;
     edgeCaseAnalysis_ = true;
     eliminateRedundantChecks_ = true;
     inlineInterpreted_ = true;
     inlineNative_ = true;
-    eagerSimdUnbox_ = true;
+    licm_ = true;
+    loopUnrolling_ = true;
     gvn_ = true;
-    licm_ = true;
     rangeAnalysis_ = true;
-    loopUnrolling_ = true;
     reordering_ = true;
-    autoTruncate_ = true;
     sincos_ = true;
     sink_ = true;
+
     registerAllocator_ = RegisterAllocator_Backtracking;
 
     inlineMaxBytecodePerCallSiteMainThread_ = 500;
     inlineMaxBytecodePerCallSiteOffThread_ = 1000;
     inlineMaxCalleeInlinedBytecodeLength_ = 3350;
     inlineMaxTotalBytecodeLength_ = 80000;
     inliningMaxCallerBytecodeLength_ = 1500;
     maxInlineDepth_ = 3;
@@ -56,26 +57,26 @@ void
 OptimizationInfo::initAsmjsOptimizationInfo()
 {
     // The AsmJS optimization level
     // Disables some passes that don't work well with asmjs.
 
     // Take normal option values for not specified values.
     initNormalOptimizationInfo();
 
+    level_ = OptimizationLevel::AsmJS;
+
     ama_ = true;
-    level_ = Optimization_AsmJS;
+    autoTruncate_ = false;
     eagerSimdUnbox_ = false;           // AsmJS has no boxing / unboxing.
     edgeCaseAnalysis_ = false;
     eliminateRedundantChecks_ = false;
-    autoTruncate_ = false;
+    scalarReplacement_ = false;        // AsmJS has no objects.
     sincos_ = false;
     sink_ = false;
-    registerAllocator_ = RegisterAllocator_Backtracking;
-    scalarReplacement_ = false;        // AsmJS has no objects.
 }
 
 uint32_t
 OptimizationInfo::compilerWarmUpThreshold(JSScript* script, jsbytecode* pc) const
 {
     MOZ_ASSERT(pc == nullptr || pc == script->code() || JSOp(*pc) == JSOP_LOOPENTRY);
 
     if (pc == script->code())
@@ -103,59 +104,61 @@ OptimizationInfo::compilerWarmUpThreshol
     // It's more efficient to enter outer loops, rather than inner loops, via OSR.
     // To accomplish this, we use a slightly higher threshold for inner loops.
     // Note that the loop depth is always > 0 so we will prefer non-OSR over OSR.
     uint32_t loopDepth = LoopEntryDepthHint(pc);
     MOZ_ASSERT(loopDepth > 0);
     return warmUpThreshold + loopDepth * 100;
 }
 
-OptimizationInfos::OptimizationInfos()
+OptimizationLevelInfo::OptimizationLevelInfo()
 {
-    infos_[Optimization_Normal - 1].initNormalOptimizationInfo();
-    infos_[Optimization_AsmJS - 1].initAsmjsOptimizationInfo();
+    infos_[OptimizationLevel::Normal].initNormalOptimizationInfo();
+    infos_[OptimizationLevel::AsmJS].initAsmjsOptimizationInfo();
 
 #ifdef DEBUG
     OptimizationLevel level = firstLevel();
     while (!isLastLevel(level)) {
         OptimizationLevel next = nextLevel(level);
-        MOZ_ASSERT(level < next);
+        MOZ_ASSERT_IF(level != OptimizationLevel::DontCompile, level < next);
         level = next;
     }
 #endif
 }
 
 OptimizationLevel
-OptimizationInfos::nextLevel(OptimizationLevel level) const
+OptimizationLevelInfo::nextLevel(OptimizationLevel level) const
 {
     MOZ_ASSERT(!isLastLevel(level));
     switch (level) {
-      case Optimization_DontCompile:
-        return Optimization_Normal;
-      default:
-        MOZ_CRASH("Unknown optimization level.");
+      case OptimizationLevel::DontCompile:
+        return OptimizationLevel::Normal;
+      case OptimizationLevel::Normal:
+      case OptimizationLevel::AsmJS:
+      case OptimizationLevel::Count:;
     }
+    MOZ_CRASH("Unknown optimization level.");
 }
 
 OptimizationLevel
-OptimizationInfos::firstLevel() const
+OptimizationLevelInfo::firstLevel() const
 {
-    return nextLevel(Optimization_DontCompile);
+    return nextLevel(OptimizationLevel::DontCompile);
 }
 
 bool
-OptimizationInfos::isLastLevel(OptimizationLevel level) const
+OptimizationLevelInfo::isLastLevel(OptimizationLevel level) const
 {
-    return level == Optimization_Normal;
+    return level == OptimizationLevel::Normal;
 }
 
 OptimizationLevel
-OptimizationInfos::levelForScript(JSScript* script, jsbytecode* pc) const
+OptimizationLevelInfo::levelForScript(JSScript* script, jsbytecode* pc) const
 {
-    OptimizationLevel prev = Optimization_DontCompile;
+    OptimizationLevel prev = OptimizationLevel::DontCompile;
 
     while (!isLastLevel(prev)) {
         OptimizationLevel level = nextLevel(prev);
         const OptimizationInfo* info = get(level);
         if (script->getWarmUpCount() < info->compilerWarmUpThreshold(script, pc))
             return prev;
 
         prev = level;
--- a/js/src/jit/IonOptimizationLevels.h
+++ b/js/src/jit/IonOptimizationLevels.h
@@ -2,47 +2,49 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jit_IonOptimizationLevels_h
 #define jit_IonOptimizationLevels_h
 
+#include "mozilla/EnumeratedArray.h"
+
 #include "jsbytecode.h"
 #include "jstypes.h"
 
 #include "jit/JitOptions.h"
 #include "js/TypeDecls.h"
 
 namespace js {
 namespace jit {
 
-enum OptimizationLevel
+enum class OptimizationLevel : uint8_t
 {
-    Optimization_DontCompile,
-    Optimization_Normal,
-    Optimization_AsmJS,
-    Optimization_Count
+    Normal,
+    AsmJS,
+    Count,
+    DontCompile
 };
 
 #ifdef JS_JITSPEW
 inline const char*
 OptimizationLevelString(OptimizationLevel level)
 {
     switch (level) {
-      case Optimization_DontCompile:
+      case OptimizationLevel::DontCompile:
         return "Optimization_DontCompile";
-      case Optimization_Normal:
+      case OptimizationLevel::Normal:
         return "Optimization_Normal";
-      case Optimization_AsmJS:
+      case OptimizationLevel::AsmJS:
         return "Optimization_AsmJS";
-      default:
-        MOZ_CRASH("Invalid OptimizationLevel");
+      case OptimizationLevel::Count:;
     }
+    MOZ_CRASH("Invalid OptimizationLevel");
 }
 #endif
 
 class OptimizationInfo
 {
   public:
     OptimizationLevel level_;
 
@@ -258,35 +260,32 @@ class OptimizationInfo
         return compilerWarmUpThreshold * inliningWarmUpThresholdFactor_;
     }
 
     uint32_t inliningRecompileThreshold() const {
         return inliningWarmUpThreshold() * inliningRecompileThresholdFactor_;
     }
 };
 
-class OptimizationInfos
+class OptimizationLevelInfo
 {
   private:
-    OptimizationInfo infos_[Optimization_Count - 1];
+    mozilla::EnumeratedArray<OptimizationLevel, OptimizationLevel::Count, OptimizationInfo> infos_;
 
   public:
-    OptimizationInfos();
+    OptimizationLevelInfo();
 
     const OptimizationInfo* get(OptimizationLevel level) const {
-        MOZ_ASSERT(level < Optimization_Count);
-        MOZ_ASSERT(level != Optimization_DontCompile);
-
-        return &infos_[level - 1];
+        return &infos_[level];
     }
 
     OptimizationLevel nextLevel(OptimizationLevel level) const;
     OptimizationLevel firstLevel() const;
     bool isLastLevel(OptimizationLevel level) const;
     OptimizationLevel levelForScript(JSScript* script, jsbytecode* pc = nullptr) const;
 };
 
-extern OptimizationInfos IonOptimizations;
+extern OptimizationLevelInfo IonOptimizations;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_IonOptimizationLevels_h */
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -402,19 +402,12 @@ MacroAssemblerARMCompat::branchAdd32(Con
 }
 
 void
 MacroAssemblerARMCompat::incrementInt32Value(const Address& addr)
 {
     asMasm().add32(Imm32(1), ToPayload(addr));
 }
 
-void
-MacroAssemblerARMCompat::decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label)
-{
-    asMasm().subPtr(imm, lhs);
-    branch32(cond, lhs, Imm32(0), label);
-}
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_arm_MacroAssembler_arm_inl_h */
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -966,17 +966,20 @@ class MacroAssemblerARMCompat : public M
     void branchPtr(Condition cond, Register lhs, wasm::SymbolicAddress imm, Label* label) {
         ScratchRegisterScope scratch(asMasm());
         movePtr(imm, scratch);
         branchPtr(cond, lhs, scratch, label);
     }
     void branchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
         branch32(cond, lhs, imm, label);
     }
-    inline void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label);
+    void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
+        ma_sub(imm, lhs, SetCC);
+        as_b(label, cond);
+    }
     void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label);
     void moveValue(const Value& val, Register type, Register data);
 
     CodeOffsetJump jumpWithPatch(RepatchLabel* label, Condition cond = Always,
                                  Label* documentation = nullptr);
     CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation) {
         return jumpWithPatch(label, Always, documentation);
     }
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -1341,18 +1341,18 @@ class MacroAssemblerCompat : public vixl
         B(dest, cond);
     }
 
     void branch(Condition cond, Label* label) {
         B(label, cond);
     }
     void branch(JitCode* target) {
         syncStackPtr();
-        addPendingJump(nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
-        b(-1); // The jump target will be patched by executableCopy().
+        BufferOffset loc = b(-1); // The jump target will be patched by executableCopy().
+        addPendingJump(loc, ImmPtr(target->raw()), Relocation::JITCODE);
     }
 
     void branch32(Condition cond, const Operand& lhs, Register rhs, Label* label) {
         // since rhs is an operand, do the compare backwards
         Cmp(ARMRegister(rhs, 32), lhs);
         B(label, Assembler::InvertCmpCondition(cond));
     }
     void branch32(Condition cond, const Operand& lhs, Imm32 rhs, Label* label) {
--- a/js/src/jit/arm64/vixl/MacroAssembler-vixl.cpp
+++ b/js/src/jit/arm64/vixl/MacroAssembler-vixl.cpp
@@ -1559,21 +1559,24 @@ void MacroAssembler::Claim(const Operand
 
   if (size.IsImmediate()) {
     VIXL_ASSERT(size.immediate() > 0);
     if (sp.Is(GetStackPointer64())) {
       VIXL_ASSERT((size.immediate() % 16) == 0);
     }
   }
 
+  Sub(GetStackPointer64(), GetStackPointer64(), size);
+
+  // Make sure the real stack pointer reflects the claimed stack space.
+  // We can't use stack memory below the stack pointer, it could be clobbered by
+  // interupts and signal handlers.
   if (!sp.Is(GetStackPointer64())) {
-    BumpSystemStackPointer(size);
+    Mov(sp, GetStackPointer64());
   }
-
-  Sub(GetStackPointer64(), GetStackPointer64(), size);
 }
 
 
 void MacroAssembler::Drop(const Operand& size) {
 
   if (size.IsZero()) {
     return;
   }
--- a/js/src/jit/arm64/vixl/MozBaseAssembler-vixl.h
+++ b/js/src/jit/arm64/vixl/MozBaseAssembler-vixl.h
@@ -201,21 +201,16 @@ class MozBaseAssembler : public js::jit:
 
   // A common implementation for the LinkAndGet<Type>OffsetTo helpers.
   ptrdiff_t LinkAndGetOffsetTo(BufferOffset branch, ImmBranchRangeType branchRange,
                                unsigned elementSizeBits, js::jit::Label* label);
 
  protected:
   // The buffer into which code and relocation info are generated.
   ARMBuffer armbuffer_;
-
-  js::jit::CompactBufferWriter jumpRelocations_;
-  js::jit::CompactBufferWriter dataRelocations_;
-  js::jit::CompactBufferWriter relocations_;
-  js::jit::CompactBufferWriter preBarriers_;
 };
 
 
 }  // namespace vixl
 
 
 #endif  // jit_arm64_vixl_MozBaseAssembler_vixl_h
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3102,19 +3102,19 @@ SliceBudget::SliceBudget(WorkBudget work
 }
 
 int
 SliceBudget::describe(char* buffer, size_t maxlen) const
 {
     if (isUnlimited())
         return JS_snprintf(buffer, maxlen, "unlimited");
     else if (isWorkBudget())
-        return JS_snprintf(buffer, maxlen, "work(%lld)", workBudget.budget);
+        return JS_snprintf(buffer, maxlen, "work(%" PRId64 ")", workBudget.budget);
     else
-        return JS_snprintf(buffer, maxlen, "%lldms", timeBudget.budget);
+        return JS_snprintf(buffer, maxlen, "%" PRId64 "ms", timeBudget.budget);
 }
 
 bool
 SliceBudget::checkOverBudget()
 {
     bool over = PRMJ_Now() >= deadline;
     if (!over)
         counter = CounterReset;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3298,22 +3298,22 @@ GetObjectSlotNameFunctor::operator()(JS:
                             slotname = "with_this";
                     }
                 }
             }
 
             if (slotname)
                 JS_snprintf(buf, bufsize, pattern, slotname);
             else
-                JS_snprintf(buf, bufsize, "**UNKNOWN SLOT %ld**", (long)slot);
+                JS_snprintf(buf, bufsize, "**UNKNOWN SLOT %" PRIu32 "**", slot);
         } while (false);
     } else {
         jsid propid = shape->propid();
         if (JSID_IS_INT(propid)) {
-            JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(propid));
+            JS_snprintf(buf, bufsize, "%" PRId32 "", JSID_TO_INT(propid));
         } else if (JSID_IS_ATOM(propid)) {
             PutEscapedString(buf, bufsize, JSID_TO_ATOM(propid), 0);
         } else if (JSID_IS_SYMBOL(propid)) {
             JS_snprintf(buf, bufsize, "**SYMBOL KEY**");
         } else {
             JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
         }
     }
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -968,17 +968,17 @@ js::Disassemble1(JSContext* cx, HandleSc
         i = GET_INT32(pc);
       print_int:
         Sprint(sp, " %d", i);
         break;
       }
 
       default: {
         char numBuf[12];
-        JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) cs->format);
+        JS_snprintf(numBuf, sizeof numBuf, "%x", cs->format);
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                              JSMSG_UNKNOWN_FORMAT, numBuf);
         return 0;
       }
     }
     sp->put("\n");
     return len;
 }
--- a/js/src/jsprf.h
+++ b/js/src/jsprf.h
@@ -20,16 +20,19 @@
 **      %s - ascii string
 **      %hs - ucs2 string
 **      %c - character
 **      %p - pointer (deals with machine dependent pointer size)
 **      %f - float
 **      %g - float
 */
 
+#include "mozilla/IntegerPrintfMacros.h"
+#include "mozilla/SizePrintfMacros.h"
+
 #include <stdarg.h>
 
 #include "jstypes.h"
 
 /*
 ** sprintf into a fixed size buffer. Guarantees that a NUL is at the end
 ** of the buffer. The return value is the length of the written output,
 ** NOT including the NUL, which is guaranteed less than "outlen" on success.
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -7,16 +7,17 @@
 /* JS shell. */
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/mozalloc.h"
 #include "mozilla/PodOperations.h"
+#include "mozilla/SizePrintfMacros.h"
 
 #ifdef XP_WIN
 # include <direct.h>
 # include <process.h>
 #endif
 #include <errno.h>
 #include <fcntl.h>
 #if defined(XP_WIN)
@@ -1415,19 +1416,19 @@ Evaluate(JSContext* cx, unsigned argc, V
     }
 
     if (saveBytecode) {
         // If we are both loading and saving, we assert that we are going to
         // replace the current bytecode by the same stream of bytes.
         if (loadBytecode && assertEqBytecode) {
             if (saveLength != loadLength) {
                 char loadLengthStr[16];
-                JS_snprintf(loadLengthStr, sizeof(loadLengthStr), "%u", loadLength);
+                JS_snprintf(loadLengthStr, sizeof(loadLengthStr), "%" PRIu32, loadLength);
                 char saveLengthStr[16];
-                JS_snprintf(saveLengthStr, sizeof(saveLengthStr), "%u", saveLength);
+                JS_snprintf(saveLengthStr, sizeof(saveLengthStr), "%" PRIu32, saveLength);
 
                 JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_CACHE_EQ_SIZE_FAILED,
                                      loadLengthStr, saveLengthStr);
                 return false;
             }
 
             if (!PodEqual(loadBuffer, saveBuffer.get(), loadLength)) {
                 JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/strict/primitive-this-getter.js
@@ -0,0 +1,56 @@
+let primitives = [
+    10,
+    false,
+    "test",
+    Symbol()
+]
+
+let getter = "getter";
+let getter2 = "getter2";
+let key = "key";
+
+for (let value of primitives) {
+    let prototype = Object.getPrototypeOf(value);
+
+    // Strict getters receive a primitive this value.
+    Object.defineProperty(prototype, "getter", {get: function() {
+        "use strict";
+        assertEq(this, value);
+        return "getter";
+    }})
+
+    assertEq(value.getter, "getter");
+    assertEq(value[getter], "getter");
+
+    // The proxy's [[Get]] trap is also invoked with primitive receiver values.
+    let proxy = new Proxy({}, {
+        get(target, property, receiver) {
+            assertEq(property, "key");
+            assertEq(receiver, value);
+            return "get";
+        }
+    });
+
+    Object.setPrototypeOf(prototype, proxy);
+    assertEq(value.key, "get");
+    assertEq(value[key], "get");
+    assertEq(value.getter, "getter");
+    assertEq(value[getter], "getter");
+
+    // A getter still gets a primitive this value even after going through a proxy.
+    proxy = new Proxy({
+        get getter2() {
+            "use strict";
+            assertEq(this, value);
+            return "getter2";
+        }
+    }, {});
+
+    Object.setPrototypeOf(prototype, proxy);
+    assertEq(value.getter2, "getter2");
+    assertEq(value[getter2], "getter2");
+    assertEq(value.getter, "getter");
+    assertEq(value[getter], "getter");
+}
+
+reportCompare(true, true);
--- a/js/src/tests/ecma_6/Array/toLocaleString.js
+++ b/js/src/tests/ecma_6/Array/toLocaleString.js
@@ -1,15 +1,13 @@
 "use strict";
 
 Object.defineProperty(String.prototype, "toLocaleString", {
     get() {
-        // Congratulations! You probably fixed primitive-this getters.
-        // Change "object" to "string".
-        assertEq(typeof this, "object");
+        assertEq(typeof this, "string");
 
         return function() { return typeof this; };
     }
 })
 
 assertEq(["test"].toLocaleString(), "string");
 
 if (typeof reportCompare === "function")
--- a/js/src/tests/ecma_6/Object/toLocaleString.js
+++ b/js/src/tests/ecma_6/Object/toLocaleString.js
@@ -1,15 +1,13 @@
 "use strict";
 
 Object.defineProperty(String.prototype, "toString", {
     get() {
-        // Congratulations! You probably fixed primitive-this getters.
-        // Change "object" to "string".
-        assertEq(typeof this, "object");
+        assertEq(typeof this, "string");
 
         return function() { return typeof this; };
     }
 })
 assertEq(Object.prototype.toLocaleString.call("test"), "string");
 
 if (typeof reportCompare === "function")
     reportCompare(true, true);
--- a/js/src/tests/ecma_6/Reflect/get.js
+++ b/js/src/tests/ecma_6/Reflect/get.js
@@ -59,27 +59,14 @@ obj = new Proxy({}, {
         assertEq(k, "itself");
         return r;
     }
 });
 assertEq(Reflect.get(obj, "itself"), obj);
 assertEq(Reflect.get(obj, "itself", Math), Math);
 assertEq(Reflect.get(Object.create(obj), "itself", Math), Math);
 
-// The receiver shouldn't have to be an object---but we do not implement that
-// correctly yet (bug 603201). For now, test the wrong behavior just to make
-// sure we don't crash.
-var result;
-try {
-    result = Reflect.get(obj, "x", 37.2);
-} catch (exc) {
-    result = exc;
-}
-if (result === 37.2) {
-    throw new Error("Congratulations on fixing bug 603201! " +
-                    "Please update this test for 1 karma point.");
-}
-assertEq(result instanceof TypeError, true);
-
+// The receiver shouldn't have to be an object
+assertEq(Reflect.get(obj, "itself", 37.2), 37.2);
 
 // For more Reflect.get tests, see target.js and propertyKeys.js.
 
 reportCompare(0, 0);
--- a/js/src/tests/ecma_6/Symbol/as-base-value.js
+++ b/js/src/tests/ecma_6/Symbol/as-base-value.js
@@ -15,19 +15,18 @@ var symbols = [
 ];
 
 // Test accessor property, used below.
 var gets, sets;
 Object.defineProperty(Symbol.prototype, "prop", {
     get: function () {
         "use strict";
         gets++;
-        assertEq(typeof this, "object");
-        assertEq(this instanceof Symbol, true);
-        assertEq(this.valueOf(), sym);
+        assertEq(typeof this, "symbol");
+        assertEq(this, sym);
         return "got";
     },
     set: function (v) {
         "use strict";
         sets++;
         assertEq(typeof this, "object");
         assertEq(this instanceof Symbol, true);
         assertEq(this.valueOf(), sym);
--- a/js/src/tests/js1_8_5/reflect-parse/classes.js
+++ b/js/src/tests/js1_8_5/reflect-parse/classes.js
@@ -474,16 +474,18 @@ function testClasses() {
     assertClassError("class NAME { constructor() {", SyntaxError);
     assertClassError("class NAME { constructor() { }", SyntaxError);
     assertClassError("class NAME { static", SyntaxError);
     assertClassError("class NAME { static y", SyntaxError);
     assertClassError("class NAME { static *", SyntaxError);
     assertClassError("class NAME { static *y", SyntaxError);
     assertClassError("class NAME { static get", SyntaxError);
     assertClassError("class NAME { static get y", SyntaxError);
+    assertClassError("class NAME { static }", SyntaxError);
+    assertClassError("class NAME { static ;", SyntaxError);
     assertClassError("class NAME extends", SyntaxError);
     assertClassError("class NAME { constructor() { super", SyntaxError);
     assertClassError("class NAME { constructor() { super.", SyntaxError);
     assertClassError("class NAME { constructor() { super.x", SyntaxError);
     assertClassError("class NAME { constructor() { super.m(", SyntaxError);
     assertClassError("class NAME { constructor() { super[", SyntaxError);
     assertClassError("class NAME { constructor() { super(", SyntaxError);
 
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -29,23 +29,16 @@ skip script test262/intl402/ch11/11.3/11
 skip script test262/intl402/ch12/12.3/12.3.3_L15.js
 skip script test262/intl402/ch12/12.3/12.3.2_L15.js
 skip script test262/intl402/ch12/12.3/12.3.2_1_a_L15.js
 skip script test262/intl402/ch12/12.1/12.1_L15.js
 skip script test262/intl402/ch12/12.2/12.2.2_L15.js
 skip script test262/ch13/13.2/13.2-15-1.js
 skip script test262/ch11/11.4/11.4.1/11.4.1-5-a-28-s.js
 
-##################################################
-# Test262 tests skipped due to SpiderMonkey bugs #
-##################################################
-
-skip script test262/ch10/10.4/10.4.3/10.4.3-1-104.js # bug 603201
-skip script test262/ch10/10.4/10.4.3/10.4.3-1-106.js # bug 603201
-
 #######################################################################
 # Tests disabled due to jstest limitations wrt imported test262 tests #
 #######################################################################
 
 # These tests are disabled because jstest doesn't understand @negative (without
 # a pattern) yet.
 skip script test262/ch07/7.2/S7.2_A5_T1.js
 skip script test262/ch07/7.2/S7.2_A5_T2.js
--- a/js/src/vm/CharacterEncoding.cpp
+++ b/js/src/vm/CharacterEncoding.cpp
@@ -198,17 +198,17 @@ JS::Utf8ToOneUcs4Char(const uint8_t* utf
 
     return ucs4Char;
 }
 
 static void
 ReportInvalidCharacter(JSContext* cx, uint32_t offset)
 {
     char buffer[10];
-    JS_snprintf(buffer, 10, "%d", offset);
+    JS_snprintf(buffer, 10, "%u", offset);
     JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
                                  JSMSG_MALFORMED_UTF8_CHAR, buffer);
 }
 
 static void
 ReportBufferTooSmall(JSContext* cx, uint32_t dummy)
 {
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL);
--- a/js/src/vm/CodeCoverage.cpp
+++ b/js/src/vm/CodeCoverage.cpp
@@ -530,18 +530,18 @@ LCovRuntime::fillWithFilename(char *name
     const char* outDir = getenv("JS_CODE_COVERAGE_OUTPUT_DIR");
     if (!outDir || *outDir == 0)
         return false;
 
     int64_t timestamp = static_cast<double>(PRMJ_Now()) / PRMJ_USEC_PER_SEC;
     static mozilla::Atomic<size_t> globalRuntimeId(0);
     size_t rid = globalRuntimeId++;
 
-    size_t len = JS_snprintf(name, length, "%s/%" PRId64 "-%d-%d.info",
-                             outDir, timestamp, size_t(pid_), rid);
+    size_t len = JS_snprintf(name, length, "%s/%" PRId64 "-%" PRIuSIZE "-%" PRIuSIZE ".info",
+                             outDir, timestamp, pid_, rid);
     if (length <= len) {
         fprintf(stderr, "Warning: LCovRuntime::init: Cannot serialize file name.");
         return false;
     }
 
     return true;
 }
 
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -450,27 +450,25 @@ GetObjectElementOperation(JSContext* cx,
             return false;
     } while (false);
 
     assertSameCompartmentDebugOnly(cx, res);
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
-GetPrimitiveElementOperation(JSContext* cx, JSOp op, JS::HandleValue receiver_,
+GetPrimitiveElementOperation(JSContext* cx, JSOp op, JS::HandleValue receiver,
                              HandleValue key, MutableHandleValue res)
 {
     MOZ_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
 
-    // FIXME: We shouldn't be boxing here or exposing the boxed object as
-    //        receiver anywhere below (bug 603201).
-    RootedObject boxed(cx, ToObjectFromStack(cx, receiver_));
+    // FIXME: Bug 1234324 We shouldn't be boxing here.
+    RootedObject boxed(cx, ToObjectFromStack(cx, receiver));
     if (!boxed)
         return false;
-    RootedValue receiver(cx, ObjectValue(*boxed));
 
     do {
         uint32_t index;
         if (IsDefinitelyIndex(key, &index)) {
             if (GetElementNoGC(cx, boxed, receiver, index, res.address()))
                 break;
 
             if (!GetElement(cx, boxed, receiver, index, res))
@@ -490,17 +488,17 @@ GetPrimitiveElementOperation(JSContext* 
                 if (GetPropertyNoGC(cx, boxed, receiver, name->asPropertyName(), res.address()))
                     break;
             }
         }
 
         RootedId id(cx);
         if (!ToPropertyKey(cx, key, &id))
             return false;
-        if (!GetProperty(cx, boxed, boxed, id, res))
+        if (!GetProperty(cx, boxed, receiver, id, res))
             return false;
     } while (false);
 
     assertSameCompartmentDebugOnly(cx, res);
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -4031,22 +4031,21 @@ js::GetProperty(JSContext* cx, HandleVal
         }
         if (!proto)
             return false;
 
         if (GetPropertyPure(cx, proto, NameToId(name), vp.address()))
             return true;
     }
 
+    RootedValue receiver(cx, v);
     RootedObject obj(cx, ToObjectFromStack(cx, v));
     if (!obj)
         return false;
 
-    // Bug 603201: Pass primitive receiver here.
-    RootedValue receiver(cx, ObjectValue(*obj));
     return GetProperty(cx, obj, receiver, name, vp);
 }
 
 bool
 js::GetScopeName(JSContext* cx, HandleObject scopeChain, HandlePropertyName name, MutableHandleValue vp)
 {
     RootedShape shape(cx);
     RootedObject obj(cx), pobj(cx);
--- a/js/src/vm/JSONParser.cpp
+++ b/js/src/vm/JSONParser.cpp
@@ -85,19 +85,19 @@ void
 JSONParser<CharT>::error(const char* msg)
 {
     if (errorHandling == RaiseError) {
         uint32_t column = 1, line = 1;
         getTextPosition(&column, &line);
 
         const size_t MaxWidth = sizeof("4294967295");
         char columnNumber[MaxWidth];
-        JS_snprintf(columnNumber, sizeof columnNumber, "%lu", column);
+        JS_snprintf(columnNumber, sizeof columnNumber, "%" PRIu32, column);
         char lineNumber[MaxWidth];
-        JS_snprintf(lineNumber, sizeof lineNumber, "%lu", line);
+        JS_snprintf(lineNumber, sizeof lineNumber, "%" PRIu32, line);
 
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_JSON_BAD_PARSE,
                              msg, lineNumber, columnNumber);
     }
 }
 
 bool
 JSONParserBase::errorReturn()
--- a/js/src/vm/SPSProfiler.cpp
+++ b/js/src/vm/SPSProfiler.cpp
@@ -348,19 +348,19 @@ SPSProfiler::allocProfileString(JSScript
     if (atom) {
         JS::AutoCheckCannotGC nogc;
         auto atomStr = mozilla::UniquePtr<char, JS::FreePolicy>(
             atom->hasLatin1Chars()
             ? JS::CharsToNewUTF8CharsZ(nullptr, atom->latin1Range(nogc)).c_str()
             : JS::CharsToNewUTF8CharsZ(nullptr, atom->twoByteRange(nogc)).c_str());
         if (!atomStr)
             return nullptr;
-        ret = JS_snprintf(cstr, len + 1, "%s (%s:%llu)", atomStr.get(), filename, lineno);
+        ret = JS_snprintf(cstr, len + 1, "%s (%s:%" PRIu64 ")", atomStr.get(), filename, lineno);
     } else {
-        ret = JS_snprintf(cstr, len + 1, "%s:%llu", filename, lineno);
+        ret = JS_snprintf(cstr, len + 1, "%s:%" PRIu64, filename, lineno);
     }
 
     MOZ_ASSERT(ret == len, "Computed length should match actual length!");
 
     return cstr;
 }
 
 SPSEntryMarker::SPSEntryMarker(JSRuntime* rt,
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -1115,32 +1115,32 @@ SavedStacks::insertFrames(JSContext* cx,
                 // youngest frame of the async stack as the parent of the oldest
                 // frame of this activation. We still need to iterate over other
                 // frames in this activation before reaching the oldest frame.
                 asyncCause = activation.asyncCause();
                 asyncActivation = &activation;
             }
         }
 
-        AutoLocationValueRooter location(cx);
+        Rooted<LocationValue> location(cx);
         {
             AutoCompartment ac(cx, iter.compartment());
             if (!cx->compartment()->savedStacks().getLocation(cx, iter, &location))
                 return false;
         }
 
         // The bit set means that the next older parent (frame, pc) pair *must*
         // be in the cache.
         if (maxFrameCount == 0)
             parentIsInCache = iter.hasCachedSavedFrame();
 
         auto displayAtom = iter.isNonEvalFunctionFrame() ? iter.functionDisplayAtom() : nullptr;
-        if (!stackChain->emplaceBack(location->source,
-                                     location->line,
-                                     location->column,
+        if (!stackChain->emplaceBack(location.source(),
+                                     location.line(),
+                                     location.column(),
                                      displayAtom,
                                      nullptr,
                                      nullptr,
                                      iter.compartment()->principals(),
                                      LiveSavedFrameCache::getFramePtr(iter),
                                      iter.pc(),
                                      &activation))
         {
@@ -1318,44 +1318,46 @@ SavedStacks::sweepPCLocationMap()
         } else if (script != key.script.get()) {
             key.script = script;
             e.rekeyFront(key);
         }
     }
 }
 
 bool
-SavedStacks::getLocation(JSContext* cx, const FrameIter& iter, MutableHandleLocationValue locationp)
+SavedStacks::getLocation(JSContext* cx, const FrameIter& iter,
+                         MutableHandle<LocationValue> locationp)
 {
     // We should only ever be caching location values for scripts in this
     // compartment. Otherwise, we would get dead cross-compartment scripts in
     // the cache because our compartment's sweep method isn't called when their
     // compartment gets collected.
     assertSameCompartment(cx, this, iter.compartment());
 
     // When we have a |JSScript| for this frame, use a potentially memoized
     // location from our PCLocationMap and copy it into |locationp|. When we do
     // not have a |JSScript| for this frame (asm.js frames), we take a slow path
     // that doesn't employ memoization, and update |locationp|'s slots directly.
 
     if (!iter.hasScript()) {
         if (const char16_t* displayURL = iter.scriptDisplayURL()) {
-            locationp->source = AtomizeChars(cx, displayURL, js_strlen(displayURL));
+            locationp.setSource(AtomizeChars(cx, displayURL, js_strlen(displayURL)));
         } else {
             const char* filename = iter.scriptFilename() ? iter.scriptFilename() : "";
-            locationp->source = Atomize(cx, filename, strlen(filename));
+            locationp.setSource(Atomize(cx, filename, strlen(filename)));
         }
-        if (!locationp->source)
+        if (!locationp.source())
             return false;
 
-        locationp->line = iter.computeLine(&locationp->column);
+        uint32_t column = 0;
+        locationp.setLine(iter.computeLine(&column));
         // XXX: Make the column 1-based as in other browsers, instead of 0-based
         // which is how SpiderMonkey stores it internally. This will be
         // unnecessary once bug 1144340 is fixed.
-        locationp->column++;
+        locationp.setColumn(column + 1);
         return true;
     }
 
     RootedScript script(cx, iter.script());
     jsbytecode* pc = iter.pc();
 
     PCKey key(script, pc);
     PCLocationMap::AddPtr p = pcLocationMap.lookupForAdd(key);
--- a/js/src/vm/SavedStacks.h
+++ b/js/src/vm/SavedStacks.h
@@ -219,66 +219,55 @@ class SavedStacks {
 
     struct PCKey {
         PCKey(JSScript* script, jsbytecode* pc) : script(script), pc(pc) { }
 
         PreBarrieredScript script;
         jsbytecode*        pc;
     };
 
-    struct LocationValue {
+  public:
+    struct LocationValue : public JS::Traceable {
         LocationValue() : source(nullptr), line(0), column(0) { }
         LocationValue(JSAtom* source, size_t line, uint32_t column)
             : source(source),
               line(line),
               column(column)
         { }
 
+        static void trace(LocationValue* self, JSTracer* trc) { self->trace(trc); }
         void trace(JSTracer* trc) {
             if (source)
                 TraceEdge(trc, &source, "SavedStacks::LocationValue::source");
         }
 
         PreBarrieredAtom source;
         size_t           line;
         uint32_t         column;
     };
 
-    class MOZ_STACK_CLASS AutoLocationValueRooter : public JS::CustomAutoRooter
-    {
-      public:
-        explicit AutoLocationValueRooter(JSContext* cx)
-            : JS::CustomAutoRooter(cx),
-              value() {}
-
-        inline LocationValue* operator->() { return &value; }
-        void set(LocationValue& loc) { value = loc; }
-        LocationValue& get() { return value; }
-
+    template <typename Outer>
+    struct LocationValueOperations {
+        JSAtom* source() const { return loc().source; }
+        size_t line() const { return loc().line; }
+        uint32_t column() const { return loc().column; }
       private:
-        virtual void trace(JSTracer* trc) {
-            value.trace(trc);
-        }
-
-        SavedStacks::LocationValue value;
+        const LocationValue& loc() const { return static_cast<const Outer*>(this)->get(); }
     };
 
-    class MOZ_STACK_CLASS MutableHandleLocationValue
-    {
-      public:
-        inline MOZ_IMPLICIT MutableHandleLocationValue(AutoLocationValueRooter* location)
-            : location(location) {}
-
-        inline LocationValue* operator->() { return &location->get(); }
-        void set(LocationValue& loc) { location->set(loc); }
-
+    template <typename Outer>
+    struct MutableLocationValueOperations : public LocationValueOperations<Outer> {
+        void setSource(JSAtom* v) { loc().source = v; }
+        void setLine(size_t v) { loc().line = v; }
+        void setColumn(uint32_t v) { loc().column = v; }
       private:
-        AutoLocationValueRooter* location;
+        LocationValue& loc() { return static_cast<Outer*>(this)->get(); }
     };
 
+  private:
     struct PCLocationHasher : public DefaultHasher<PCKey> {
         typedef PointerHasher<JSScript*, 3>   ScriptPtrHasher;
         typedef PointerHasher<jsbytecode*, 3> BytecodePtrHasher;
 
         static HashNumber hash(const PCKey& key) {
             return mozilla::AddToHash(ScriptPtrHasher::hash(key.script),
                                       BytecodePtrHasher::hash(key.pc));
         }
@@ -288,16 +277,26 @@ class SavedStacks {
         }
     };
 
     typedef HashMap<PCKey, LocationValue, PCLocationHasher, SystemAllocPolicy> PCLocationMap;
 
     PCLocationMap pcLocationMap;
 
     void sweepPCLocationMap();
-    bool getLocation(JSContext* cx, const FrameIter& iter, MutableHandleLocationValue locationp);
+    bool getLocation(JSContext* cx, const FrameIter& iter, MutableHandle<LocationValue> locationp);
 };
 
 JSObject* SavedStacksMetadataCallback(JSContext* cx, JSObject* target);
 
+template <>
+class RootedBase<SavedStacks::LocationValue>
+  : public SavedStacks::MutableLocationValueOperations<JS::Rooted<SavedStacks::LocationValue>>
+{};
+
+template <>
+class MutableHandleBase<SavedStacks::LocationValue>
+  : public SavedStacks::MutableLocationValueOperations<JS::MutableHandle<SavedStacks::LocationValue>>
+{};
+
 } /* namespace js */
 
 #endif /* vm_SavedStacks_h */
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -434,17 +434,17 @@ TraceLoggerThread::getOrCreateEventPaylo
     for (size_t i = colno; i /= 10; lenColno++);
 
     size_t len = 7 + lenFilename + 1 + lenLineno + 1 + lenColno;
     char* str = js_pod_malloc<char>(len + 1);
     if (!str)
         return nullptr;
 
     DebugOnly<size_t> ret =
-        JS_snprintf(str, len + 1, "script %s:%u:%u", filename, lineno, colno);
+        JS_snprintf(str, len + 1, "script %s:%" PRIuSIZE ":%" PRIuSIZE, filename, lineno, colno);
     MOZ_ASSERT(ret == len);
     MOZ_ASSERT(strlen(str) == len);
 
     uint32_t textId = nextTextId;
     TraceLoggerEventPayload* payload = js_new<TraceLoggerEventPayload>(textId, str);
     if (!payload) {
         js_free(str);
         return nullptr;
--- a/js/src/vm/TypedArrayCommon.h
+++ b/js/src/vm/TypedArrayCommon.h
@@ -344,17 +344,17 @@ class ElementSpecific
     setFromOverlappingTypedArray(JSContext* cx,
                                  Handle<SomeTypedArray*> target,
                                  Handle<SomeTypedArray*> source,
                                  uint32_t offset)
     {
         MOZ_ASSERT(SpecificArray::ArrayTypeID() == target->type(),
                    "calling wrong setFromTypedArray specialization");
         MOZ_ASSERT(SomeTypedArray::sameBuffer(target, source),
-                   "provided arrays don't actually overlap, so it's "
+                   "the provided arrays don't actually overlap, so it's "
                    "undesirable to use this method");
 
         MOZ_ASSERT(offset <= target->length());
         MOZ_ASSERT(source->length() <= target->length() - offset);
 
         SharedMem<T*> dest = AnyTypedArrayViewData(target).template cast<T*>() + offset;
         uint32_t len = source->length();
 
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -64,16 +64,26 @@ class TypedArrayObject : public NativeOb
                   "bad inlined constant in jsfriendapi.h");
 
     typedef TypedArrayObject SomeTypedArray;
     typedef ArrayBufferObject BufferType;
 
     template<typename T> struct OfType;
 
     static bool sameBuffer(Handle<TypedArrayObject*> a, Handle<TypedArrayObject*> b) {
+        // Inline buffers.
+        if (!a->hasBuffer() || !b->hasBuffer())
+            return a.get() == b.get();
+
+        // Shared buffers.
+        if (a->isSharedMemory() && b->isSharedMemory()) {
+            return (a->bufferObject()->as<SharedArrayBufferObject>().globalID() ==
+                    b->bufferObject()->as<SharedArrayBufferObject>().globalID());
+        }
+
         return a->bufferObject() == b->bufferObject();
     }
 
     static const Class classes[Scalar::MaxTypedArrayViewType];
     static const Class protoClasses[Scalar::MaxTypedArrayViewType];
     static const Class sharedTypedArrayPrototypeClass;
 
     static const Class* classForType(Scalar::Type type) {
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -100,16 +100,21 @@ UnboxedLayout::makeConstructorCode(JSCon
     newKindReg = ecx;
     masm.loadPtr(Address(masm.getStackPointer(), sizeof(void*)), propertiesReg);
     masm.loadPtr(Address(masm.getStackPointer(), 2 * sizeof(void*)), newKindReg);
 #else
     propertiesReg = IntArgReg0;
     newKindReg = IntArgReg1;
 #endif
 
+#ifdef JS_CODEGEN_ARM64
+    // ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing.
+    masm.initStackPtr();
+#endif
+
     MOZ_ASSERT(propertiesReg.volatile_());
     MOZ_ASSERT(newKindReg.volatile_());
 
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
     regs.take(propertiesReg);
     regs.take(newKindReg);
     Register object = regs.takeAny(), scratch1 = regs.takeAny(), scratch2 = regs.takeAny();
 
--- a/js/src/vm/make_opcode_doc.py
+++ b/js/src/vm/make_opcode_doc.py
@@ -328,18 +328,37 @@ def print_opcode(opcode):
            values='<br>'.join(values),
            operands=escape(opcode.operands) or "&nbsp;",
            length=escape(override(opcode.length,
                                   opcode.length_override)),
            stack_uses=escape(opcode.stack_uses) or "&nbsp;",
            stack_defs=escape(opcode.stack_defs) or "&nbsp;",
            desc=opcode.desc)) # desc is already escaped
 
-def make_element_id(name):
-    return name.replace(' ', '-')
+id_cache = dict()
+id_count = dict()
+
+def make_element_id(category, type=''):
+    key = '{}:{}'.format(category, type)
+    if key in id_cache:
+        return id_cache[key]
+
+    if type == '':
+        id = category.replace(' ', '_')
+    else:
+        id = type.replace(' ', '_')
+
+    if id in id_count:
+        id_count[id] += 1
+        id = '{}_{}'.format(id, id_count[id])
+    else:
+        id_count[id] = 1
+
+    id_cache[key] = id
+    return id
 
 def print_doc(version, index):
     print("""<div>{{{{SpiderMonkeySidebar("Internals")}}}}</div>
 
 <h2 id="Bytecode_Listing">Bytecode Listing</h2>
 
 <p>This document is automatically generated from
 <a href="{source_base}/js/src/vm/Opcodes.h">Opcodes.h</a> and
@@ -353,17 +372,17 @@ def print_doc(version, index):
            actual_version=0xb973c0de - version))
 
     for (category_name, types) in index:
         print('<h3 id="{id}">{name}</h3>'.format(name=category_name,
                                                  id=make_element_id(category_name)))
         for (type_name, opcodes) in types:
             if type_name:
                 print('<h4 id="{id}">{name}</h4>'.format(name=type_name,
-                                                         id=make_element_id(type_name)))
+                                                         id=make_element_id(category_name, type_name)))
             print('<dl>')
             for opcode in sorted(opcodes,
                                  key=lambda opcode: opcode.sort_key):
                 print_opcode(opcode)
             print('</dl>')
 
 if __name__ == '__main__':
     if len(sys.argv) < 2:
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -4753,21 +4753,23 @@ nsDisplayScrollInfoLayer::ComputeFrameMe
       nsLayoutUtils::GetCriticalDisplayPort(mScrolledFrame->GetContent(), nullptr)) {
     params.mInLowPrecisionDisplayPort = true; 
   }
 
   nsRect viewport = mScrollFrame->GetRect() -
                     mScrollFrame->GetPosition() +
                     mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
 
-  return UniquePtr<FrameMetrics>(new FrameMetrics(
-    nsLayoutUtils::ComputeFrameMetrics(
+  FrameMetrics metrics = nsLayoutUtils::ComputeFrameMetrics(
       mScrolledFrame, mScrollFrame, mScrollFrame->GetContent(),
       ReferenceFrame(), aLayer,
-      mScrollParentId, viewport, Nothing(), false, params)));
+      mScrollParentId, viewport, Nothing(), false, params);
+  metrics.SetIsScrollInfoLayer(true);
+
+  return UniquePtr<FrameMetrics>(new FrameMetrics(metrics));
 }
 
 void
 nsDisplayScrollInfoLayer::IgnoreIfCompositorSupportsBlending(BlendModeSet aBlendModes)
 {
   mContainedBlendModes += aBlendModes;
   mIgnoreIfCompositorSupportsBlending = true;
 }
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2995,17 +2995,17 @@ nsLayoutUtils::CalculateAndSetDisplayPor
                                                  RepaintMode aRepaintMode) {
   nsIFrame* frame = do_QueryFrame(aScrollFrame);
   MOZ_ASSERT(frame);
   nsIContent* content = frame->GetContent();
   MOZ_ASSERT(content);
 
   FrameMetrics metrics = CalculateBasicFrameMetrics(aScrollFrame);
   ScreenMargin displayportMargins = APZCTreeManager::CalculatePendingDisplayPort(
-      metrics, ParentLayerPoint(0.0f, 0.0f), 0.0);
+      metrics, ParentLayerPoint(0.0f, 0.0f));
   nsIPresShell* presShell = frame->PresContext()->GetPresShell();
   return nsLayoutUtils::SetDisplayPortMargins(
       content, presShell, displayportMargins, 0, aRepaintMode);
 }
 
 bool
 nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
                                            nsIFrame* aScrollFrame,
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -1464,16 +1464,23 @@ Declaration::ToString(nsAString& aString
     aString.Truncate(aString.Length() - 1);
   }
 }
 
 #ifdef DEBUG
 /* virtual */ void
 Declaration::List(FILE* out, int32_t aIndent) const
 {
+  const Rule* owningRule = GetOwningRule();
+  if (owningRule) {
+    // More useful to print the selector and sheet URI too.
+    owningRule->List(out, aIndent);
+    return;
+  }
+
   nsAutoCString str;
   for (int32_t index = aIndent; --index >= 0; ) {
     str.AppendLiteral("  ");
   }
 
   str.AppendLiteral("{ ");
   nsAutoString s;
   ToString(s);
--- a/layout/style/Declaration.h
+++ b/layout/style/Declaration.h
@@ -320,33 +320,33 @@ public:
   }
 
   void SetOwningRule(Rule* aRule) {
     MOZ_ASSERT(!mContainer.mOwningRule || !aRule,
                "should never overwrite one rule with another");
     mContainer.mOwningRule = aRule;
   }
 
-  Rule* GetOwningRule() {
+  Rule* GetOwningRule() const {
     if (mContainer.mRaw & 0x1) {
       return nullptr;
     }
     return mContainer.mOwningRule;
   }
 
   void SetHTMLCSSStyleSheet(nsHTMLCSSStyleSheet* aHTMLCSSStyleSheet) {
     MOZ_ASSERT(!mContainer.mHTMLCSSStyleSheet || !aHTMLCSSStyleSheet,
                "should never overwrite one sheet with another");
     mContainer.mHTMLCSSStyleSheet = aHTMLCSSStyleSheet;
     if (aHTMLCSSStyleSheet) {
       mContainer.mRaw |= uintptr_t(1);
     }
   }
 
-  nsHTMLCSSStyleSheet* GetHTMLCSSStyleSheet() {
+  nsHTMLCSSStyleSheet* GetHTMLCSSStyleSheet() const {
     if (!(mContainer.mRaw & 0x1)) {
       return nullptr;
     }
     auto c = mContainer;
     c.mRaw &= ~uintptr_t(1);
     return c.mHTMLCSSStyleSheet;
   }
 
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -381,16 +381,36 @@ nsAnimationManager::SizeOfExcludingThis(
 }
 
 /* virtual */ size_t
 nsAnimationManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
 }
 
+void
+nsAnimationManager::CopyIsRunningOnCompositor(
+  KeyframeEffectReadOnly& aSourceEffect,
+  KeyframeEffectReadOnly& aDestEffect)
+{
+  nsCSSPropertySet sourceProperties;
+
+  for (AnimationProperty& property : aSourceEffect.Properties()) {
+    if (property.mIsRunningOnCompositor) {
+      sourceProperties.AddProperty(property.mProperty);
+    }
+  }
+
+  for (AnimationProperty& property : aDestEffect.Properties()) {
+    if (sourceProperties.HasProperty(property.mProperty)) {
+      property.mIsRunningOnCompositor = true;
+    }
+  }
+}
+
 nsIStyleRule*
 nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
                                        mozilla::dom::Element* aElement)
 {
   // Ignore animations for print or print preview, and for elements
   // that are not attached to the document tree.
   if (!mPresContext->IsDynamic() || !aElement->IsInComposedDoc()) {
     return nullptr;
@@ -488,16 +508,22 @@ nsAnimationManager::CheckAnimationRule(n
         // identity (and any expando properties attached to it).
         if (oldAnim->GetEffect() && newAnim->GetEffect()) {
           KeyframeEffectReadOnly* oldEffect = oldAnim->GetEffect();
           KeyframeEffectReadOnly* newEffect = newAnim->GetEffect();
           animationChanged =
             oldEffect->Timing() != newEffect->Timing() ||
             oldEffect->Properties() != newEffect->Properties();
           oldEffect->SetTiming(newEffect->Timing());
+
+          // To preserve the mIsRunningOnCompositor value on each property,
+          // we copy it from the old effect to the new effect since, in the
+          // following step, we will completely clobber the properties on the
+          // old effect with the values on the new effect.
+          CopyIsRunningOnCompositor(*oldEffect, *newEffect);
           oldEffect->Properties() = newEffect->Properties();
         }
 
         // Handle changes in play state. If the animation is idle, however,
         // changes to animation-play-state should *not* restart it.
         if (oldAnim->PlayState() != AnimationPlayState::Idle) {
           // CSSAnimation takes care of override behavior so that,
           // for example, if the author has called pause(), that will
@@ -784,17 +810,16 @@ nsAnimationManager::BuildAnimations(nsSt
         } else {
           keyframesWithProperty.AppendElement(kfIdx);
         }
         lastKey = kf.mKey;
       }
 
       AnimationProperty &propData = *destEffect->Properties().AppendElement();
       propData.mProperty = prop;
-      propData.mWinsInCascade = true;
 
       KeyframeData *fromKeyframe = nullptr;
       RefPtr<nsStyleContext> fromContext;
       bool interpolated = true;
       for (uint32_t wpIdx = 0, wpEnd = keyframesWithProperty.Length();
            wpIdx != wpEnd; ++wpIdx) {
         uint32_t kfIdx = keyframesWithProperty[wpIdx];
         KeyframeData &toKeyframe = sortedKeyframes[kfIdx];
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -17,16 +17,17 @@
 class nsIGlobalObject;
 class nsStyleContext;
 
 namespace mozilla {
 namespace css {
 class Declaration;
 } /* namespace css */
 namespace dom {
+class KeyframeEffectReadOnly;
 class Promise;
 } /* namespace dom */
 
 struct AnimationEventInfo {
   RefPtr<dom::Element> mElement;
   RefPtr<dom::Animation> mAnimation;
   InternalAnimationEvent mEvent;
   TimeStamp mTimeStamp;
@@ -368,11 +369,14 @@ private:
                     const mozilla::StyleAnimation& aAnimation,
                     float aFromKey, nsStyleContext* aFromContext,
                     mozilla::css::Declaration* aFromDeclaration,
                     float aToKey, nsStyleContext* aToContext);
 
   static void UpdateCascadeResults(nsStyleContext* aStyleContext,
                                    mozilla::AnimationCollection*
                                      aElementAnimations);
+  static void CopyIsRunningOnCompositor(
+    mozilla::dom::KeyframeEffectReadOnly& aSourceEffect,
+    mozilla::dom::KeyframeEffectReadOnly& aDestEffect);
 };
 
 #endif /* !defined(nsAnimationManager_h_) */
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -674,17 +674,16 @@ nsTransitionManager::ConsiderStartingTra
   RefPtr<ElementPropertyTransition> pt =
     new ElementPropertyTransition(aElement->OwnerDoc(), aElement,
                                   aNewStyleContext->GetPseudoType(), timing);
   pt->mStartForReversingTest = startForReversingTest;
   pt->mReversePortion = reversePortion;
 
   AnimationProperty& prop = *pt->Properties().AppendElement();
   prop.mProperty = aProperty;
-  prop.mWinsInCascade = true;
 
   AnimationPropertySegment& segment = *prop.mSegments.AppendElement();
   segment.mFromValue = startValue;
   segment.mToValue = endValue;
   segment.mFromKey = 0;
   segment.mToKey = 1;
   segment.mTimingFunction.Init(tf);
 
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -126,16 +126,17 @@ support-files = file_bug829816.css
 [test_bug887741_at-rules_in_declaration_lists.html]
 [test_bug892929.html]
 [test_bug1055933.html]
 support-files = file_bug1055933_circle-xxl.png
 [test_bug1089417.html]
 support-files = file_bug1089417_iframe.html
 [test_bug1112014.html]
 [test_bug1203766.html]
+[test_bug1232829.html]
 [test_cascade.html]
 [test_ch_ex_no_infloops.html]
 [test_compute_data_with_start_struct.html]
 skip-if = toolkit == 'android'
 [test_computed_style.html]
 [test_computed_style_no_pseudo.html]
 [test_computed_style_prefs.html]
 [test_condition_text.html]
new file mode 100644
--- /dev/null
+++ b/layout/style/test/test_bug1232829.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1232829
+-->
+<head>
+<meta charset="utf-8">
+<title>Test for Bug 1232829</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<script>
+
+/** Test for Bug 1232829 **/
+
+// This should be a crashtest but it relies on using a pop-up window which
+// isn't supported in crashtests.
+function boom() {
+  var popup = window.open("data:text/html,2");
+  setTimeout(function() {
+    var frameDoc = document.querySelector("iframe").contentDocument;
+    frameDoc.write("3");
+    frameDoc.defaultView.history.back();
+    requestAnimationFrame(function() {
+      popup.close();
+      ok(true, "Didn't crash");
+      SimpleTest.finish();
+    });
+  }, 0);
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</head>
+<body onload="boom()">
+  <iframe srcdoc="<style>@keyframes a { to { opacity: 0.5 } }</style>
+                  <div style='animation: a 1ms'></div>"></iframe>
+</body>
+</html>
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/ContentChild.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/HashFunctions.h"
+#include "mozilla/UniquePtrExtensions.h"
 
 #include "nsXULAppAPI.h"
 
 #include "mozilla/Preferences.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDataHashtable.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsICategoryManager.h"
@@ -932,35 +933,33 @@ Preferences::WritePrefFile(nsIFile* aFil
                                        -1,
                                        0600);
   if (NS_FAILED(rv)) 
       return rv;
   rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
   if (NS_FAILED(rv)) 
       return rv;  
 
-  nsAutoArrayPtr<char*> valueArray(new char*[gHashTable->EntryCount()]);
-  memset(valueArray, 0, gHashTable->EntryCount() * sizeof(char*));
-
   // get the lines that we're supposed to be writing to the file
-  pref_savePrefs(gHashTable, valueArray);
+  UniquePtr<char*[]> valueArray = pref_savePrefs(gHashTable);
 
   /* Sort the preferences to make a readable file on disk */
-  NS_QuickSort(valueArray, gHashTable->EntryCount(), sizeof(char *),
+  NS_QuickSort(valueArray.get(), gHashTable->EntryCount(), sizeof(char *),
                pref_CompareStrings, nullptr);
 
   // write out the file header
   outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
 
-  char** walker = valueArray;
-  for (uint32_t valueIdx = 0; valueIdx < gHashTable->EntryCount(); valueIdx++, walker++) {
-    if (*walker) {
-      outStream->Write(*walker, strlen(*walker), &writeAmount);
+  for (uint32_t valueIdx = 0; valueIdx < gHashTable->EntryCount(); valueIdx++) {
+    char*& pref = valueArray[valueIdx];
+    if (pref) {
+      outStream->Write(pref, strlen(pref), &writeAmount);
       outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
-      free(*walker);
+      free(pref);
+      pref = nullptr;
     }
   }
 
   // tell the safe output stream to overwrite the real prefs file
   // (it'll abort if there were any errors during writing)
   nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
   NS_ASSERTION(safeStream, "expected a safe output stream!");
   if (safeStream) {
@@ -985,33 +984,33 @@ static nsresult openPrefFile(nsIFile* aF
 
   int64_t fileSize64;
   rv = aFile->GetFileSize(&fileSize64);
   if (NS_FAILED(rv))
     return rv;
   NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
 
   uint32_t fileSize = (uint32_t)fileSize64;
-  nsAutoArrayPtr<char> fileBuffer(new char[fileSize]);
+  auto fileBuffer = MakeUniqueFallible<char[]>(fileSize);
   if (fileBuffer == nullptr)
     return NS_ERROR_OUT_OF_MEMORY;
 
   PrefParseState ps;
   PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
 
   // Read is not guaranteed to return a buf the size of fileSize,
   // but usually will.
   nsresult rv2 = NS_OK;
   uint32_t offset = 0;
   for (;;) {
     uint32_t amtRead = 0;
-    rv = inStr->Read((char*)fileBuffer, fileSize, &amtRead);
+    rv = inStr->Read(fileBuffer.get(), fileSize, &amtRead);
     if (NS_FAILED(rv) || amtRead == 0)
       break;
-    if (!PREF_ParseBuf(&ps, fileBuffer, amtRead))
+    if (!PREF_ParseBuf(&ps, fileBuffer.get(), amtRead))
       rv2 = NS_ERROR_FILE_CORRUPTED;
     offset += amtRead;
     if (offset == fileSize) {
       break;
     }
   }
 
   PREF_FinalizeParseState(&ps);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -330,25 +330,22 @@ pref("media.ffmpeg.enabled", true);
 pref("media.gmp.decoder.enabled", false);
 pref("media.gmp.decoder.aac", 0);
 pref("media.gmp.decoder.h264", 0);
 #ifdef MOZ_RAW
 pref("media.raw.enabled", true);
 #endif
 pref("media.ogg.enabled", true);
 pref("media.opus.enabled", true);
-#ifdef MOZ_WAVE
 pref("media.wave.enabled", true);
-#endif
-#ifdef MOZ_WEBM
 pref("media.webm.enabled", true);
 #if defined(MOZ_FMP4) && defined(MOZ_WMF)
 pref("media.webm.intel_decoder.enabled", false);
 #endif
-#endif
+
 #ifdef MOZ_GSTREAMER
 pref("media.gstreamer.enabled", true);
 pref("media.gstreamer.enable-blacklist", true);
 #endif
 #ifdef MOZ_APPLEMEDIA
 #ifdef MOZ_WIDGET_UIKIT
 pref("media.mp3.enabled", true);
 #endif
@@ -571,34 +568,32 @@ pref("apz.fling_friction", "0.002");
 pref("apz.fling_repaint_interval", 16);
 pref("apz.fling_stop_on_tap_threshold", "0.05");
 pref("apz.fling_stopped_threshold", "0.01");
 pref("apz.highlight_checkerboarded_areas", false);
 pref("apz.max_velocity_inches_per_ms", "-1.0");
 pref("apz.max_velocity_queue_size", 5);
 pref("apz.min_skate_speed", "1.0");
 pref("apz.minimap.enabled", false);
-pref("apz.num_paint_duration_samples", 3);
 pref("apz.overscroll.enabled", false);
 pref("apz.overscroll.min_pan_distance_ratio", "1.0");
 pref("apz.overscroll.spring_friction", "0.015");
 pref("apz.overscroll.spring_stiffness", "0.0018");
 pref("apz.overscroll.stop_distance_threshold", "5.0");
 pref("apz.overscroll.stop_velocity_threshold", "0.01");
 pref("apz.overscroll.stretch_factor", "0.35");
 pref("apz.pan_repaint_interval", 16);
 
 // Whether to print the APZC tree for debugging
 pref("apz.printtree", false);
 
 pref("apz.smooth_scroll_repaint_interval", 16);
 pref("apz.test.logging_enabled", false);
 pref("apz.touch_start_tolerance", "0.1");
 pref("apz.touch_move_tolerance", "0.03");
-pref("apz.use_paint_duration", true);
 pref("apz.velocity_bias", "1.0");
 pref("apz.velocity_relevance_time_ms", 150);
 pref("apz.x_skate_highmem_adjust", "0.0");
 pref("apz.y_skate_highmem_adjust", "0.0");
 pref("apz.x_skate_size_multiplier", "2.5");
 pref("apz.y_skate_size_multiplier", "3.5");
 pref("apz.x_stationary_size_multiplier", "3.0");
 pref("apz.y_stationary_size_multiplier", "3.5");
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -313,19 +313,22 @@ pref_SetPref(const dom::PrefSetting& aPr
     }
 
     // NB: we should never try to clear a default value, that doesn't
     // make sense
 
     return rv;
 }
 
-void
-pref_savePrefs(PLDHashTable* aTable, char** aPrefArray)
+UniquePtr<char*[]>
+pref_savePrefs(PLDHashTable* aTable)
 {
+    auto savedPrefs = MakeUnique<char*[]>(aTable->EntryCount());
+    memset(savedPrefs.get(), 0, aTable->EntryCount() * sizeof(char*));
+
     int32_t j = 0;
     for (auto iter = aTable->Iter(); !iter.Done(); iter.Next()) {
         auto pref = static_cast<PrefHashEntry*>(iter.Get());
 
         nsAutoCString prefValue;
         nsAutoCString prefPrefix;
         prefPrefix.AssignLiteral("user_pref(\"");
 
@@ -355,22 +358,24 @@ pref_savePrefs(PLDHashTable* aTable, cha
 
         } else if (pref->flags & PREF_BOOL) {
             prefValue = (sourcePref->boolVal) ? "true" : "false";
         }
 
         nsAutoCString prefName;
         str_escape(pref->key, prefName);
 
-        aPrefArray[j++] = ToNewCString(prefPrefix +
+        savedPrefs[j++] = ToNewCString(prefPrefix +
                                        prefName +
                                        NS_LITERAL_CSTRING("\", ") +
                                        prefValue +
                                        NS_LITERAL_CSTRING(");"));
     }
+
+    return savedPrefs;
 }
 
 static void
 GetPrefValueFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref,
                       WhichValue aWhich)
 {
     PrefValue* value;
     dom::PrefValue* settingValue;
--- a/modules/libpref/prefapi_private_data.h
+++ b/modules/libpref/prefapi_private_data.h
@@ -4,28 +4,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Data shared between prefapi.c and nsPref.cpp */
 
 #ifndef prefapi_private_data_h
 #define prefapi_private_data_h
 
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/UniquePtr.h"
 
 extern PLDHashTable* gHashTable;
 extern bool gDirty;
 
 namespace mozilla {
 namespace dom {
 class PrefSetting;
 } // namespace dom
 } // namespace mozilla
 
-void
-pref_savePrefs(PLDHashTable* aTable, char** aPrefArray);
+mozilla::UniquePtr<char*[]>
+pref_savePrefs(PLDHashTable* aTable);
 
 nsresult
 pref_SetPref(const mozilla::dom::PrefSetting& aPref);
 
 int pref_CompareStrings(const void *v1, const void *v2, void* unused);
 PrefHashEntry* pref_HashTableLookup(const char *key);
 
 void pref_GetPrefFromEntry(PrefHashEntry *aHashEntry,
--- a/netwerk/base/nsFileStreams.cpp
+++ b/netwerk/base/nsFileStreams.cpp
@@ -16,16 +16,18 @@
 
 #include "private/pprio.h"
 
 #include "nsFileStreams.h"
 #include "nsIFile.h"
 #include "nsReadLine.h"
 #include "nsIClassInfoImpl.h"
 #include "mozilla/ipc/InputStreamUtils.h"
+#include "mozilla/unused.h"
+#include "mozilla/FileUtils.h"
 #include "nsNetCID.h"
 #include "nsXULAppAPI.h"
 
 #define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067
 
 typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType;
 
 using namespace mozilla::ipc;
@@ -861,16 +863,30 @@ nsFileOutputStream::Init(nsIFile* file, 
         ioFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
     if (perm <= 0)
         perm = 0664;
 
     return MaybeOpen(file, ioFlags, perm,
                      mBehaviorFlags & nsIFileOutputStream::DEFER_OPEN);
 }
 
+NS_IMETHODIMP
+nsFileOutputStream::Preallocate(int64_t aLength)
+{
+    if (!mFD) {
+        return NS_ERROR_NOT_INITIALIZED;
+    }
+
+    if (!mozilla::fallocate(mFD, aLength)) {
+        return NS_ERROR_FAILURE;
+    }
+
+    return NS_OK;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsAtomicFileOutputStream
 
 NS_IMPL_ISUPPORTS_INHERITED(nsAtomicFileOutputStream,
                             nsFileOutputStream,
                             nsISafeOutputStream,
                             nsIOutputStream,
                             nsIFileOutputStream)
--- a/netwerk/base/nsIFileStreams.idl
+++ b/netwerk/base/nsIFileStreams.idl
@@ -82,17 +82,17 @@ interface nsIFileInputStream : nsIInputS
      * allows the OS to delete the file from disk just like POSIX.
      */
     const long SHARE_DELETE = 1<<5;
 };
 
 /**
  * An output stream that lets you stream to a file.
  */
-[scriptable, uuid(e6f68040-c7ec-11d3-8cda-0060b0fc14a3)]
+[scriptable, uuid(e734cac9-1295-4e6f-9684-3ac4e1f91063)]
 interface nsIFileOutputStream : nsIOutputStream
 {
     /**
      * @param file          file to write to
      * @param ioFlags       file open flags listed in prio.h (see
      *                      PR_Open documentation) or -1 to open the
      *                      file in default mode (PR_WRONLY |
      *                      PR_CREATE_FILE | PR_TRUNCATE)
@@ -100,16 +100,25 @@ interface nsIFileOutputStream : nsIOutpu
      *                      use the default permissions (0664)
      * @param behaviorFlags flags specifying various behaviors of the class
      *        (currently none supported)
      */
     void init(in nsIFile file, in long ioFlags, in long perm,
               in long behaviorFlags);
 
     /**
+     * @param length        asks the operating system to allocate storage for
+     *                      this file of at least |length| bytes long, and
+     *                      set the file length to the corresponding size.
+     * @throws NS_ERROR_FAILURE if the preallocation fails.
+     * @throws NS_ERROR_NOT_INITIALIZED if the file is not opened.
+     */
+    [noscript] void preallocate(in long long length);
+
+    /**
      * See the same constant in nsIFileInputStream. The deferred open will
      * be performed when one of the following is called:
      *   - Seek
      *   - Tell
      *   - SetEOF
      *   - Write
      *   - Flush
      *
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -1121,16 +1121,32 @@ NS_BufferOutputStream(nsIOutputStream *a
                                              aBufferSize);
     if (NS_SUCCEEDED(rv))
         return bos.forget();
 
     bos = aOutputStream;
     return bos.forget();
 }
 
+already_AddRefed<nsIInputStream>
+NS_BufferInputStream(nsIInputStream *aInputStream,
+                      uint32_t aBufferSize)
+{
+    NS_ASSERTION(aInputStream, "No input stream given!");
+
+    nsCOMPtr<nsIInputStream> bis;
+    nsresult rv = NS_NewBufferedInputStream(getter_AddRefs(bis), aInputStream,
+                                            aBufferSize);
+    if (NS_SUCCEEDED(rv))
+        return bis.forget();
+
+    bis = aInputStream;
+    return bis.forget();
+}
+
 nsresult
 NS_ReadInputStreamToBuffer(nsIInputStream *aInputStream,
                            void **aDest,
                            uint32_t aCount)
 {
     nsresult rv;
 
     if (!*aDest) {
--- a/netwerk/base/nsNetUtil.h
+++ b/netwerk/base/nsNetUtil.h
@@ -567,29 +567,32 @@ NS_NewBufferedInputStream(nsIInputStream
 
 // note: the resulting stream can be QI'ed to nsISafeOutputStream iff the
 // provided stream supports it.
 nsresult NS_NewBufferedOutputStream(nsIOutputStream **result,
                                     nsIOutputStream  *str,
                                     uint32_t          bufferSize);
 
 /**
- * Attempts to buffer a given output stream.  If this fails, it returns the
- * passed-in output stream.
+ * Attempts to buffer a given stream.  If this fails, it returns the
+ * passed-in stream.
  *
  * @param aOutputStream
  *        The output stream we want to buffer.  This cannot be null.
  * @param aBufferSize
  *        The size of the buffer for the buffered output stream.
  * @returns an nsIOutputStream that is buffered with the specified buffer size,
  *          or is aOutputStream if creating the new buffered stream failed.
  */
 already_AddRefed<nsIOutputStream>
 NS_BufferOutputStream(nsIOutputStream *aOutputStream,
                       uint32_t aBufferSize);
+already_AddRefed<nsIInputStream>
+NS_BufferInputStream(nsIInputStream *aInputStream,
+                      uint32_t aBufferSize);
 
 // returns an input stream compatible with nsIUploadChannel::SetUploadStream()
 nsresult NS_NewPostDataStream(nsIInputStream  **result,
                               bool              isFile,
                               const nsACString &data);
 
 nsresult NS_ReadInputStreamToBuffer(nsIInputStream *aInputStream,
                                     void **aDest,
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -178,17 +178,16 @@ private:
                                        InterceptStreamListener* aStreamListener);
 
   void ForceIntercepted(nsIInputStream* aSynthesizedInput);
 
   RequestHeaderTuples mClientSetRequestHeaders;
   nsCOMPtr<nsIChildChannel> mRedirectChannelChild;
   RefPtr<InterceptStreamListener> mInterceptListener;
   RefPtr<nsInputStreamPump> mSynthesizedResponsePump;
-  nsAutoPtr<nsHttpResponseHead> mSynthesizedResponseHead;
   nsCOMPtr<nsIInputStream> mSynthesizedInput;
   int64_t mSynthesizedStreamLength;
 
   bool mIsFromCache;
   bool mCacheEntryAvailable;
   uint32_t     mCacheExpirationTime;
   nsCString    mCachedCharset;
   nsCOMPtr<nsISupports> mCacheKey;
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -4,16 +4,17 @@ skip-if = buildapp == 'b2g'
 support-files =
   method.sjs
   partial_content.sjs
   rel_preconnect.sjs
   user_agent.sjs
   user_agent_update.sjs
   web_packaged_app.sjs
   signed_web_packaged_app.sjs
+  signed_web_packaged_app_random.sjs
   file_loadinfo_redirectchain.sjs
   redirect_idn.html^headers^
   redirect_idn.html
   empty.html
 
 [test_arraybufferinputstream.html]
 [test_partially_cached_content.html]
 [test_rel_preconnect.html]
@@ -24,14 +25,16 @@ skip-if = e10s
 [test_user_agent_updates.html]
 skip-if = e10s
 [test_user_agent_updates_reset.html]
 [test_xhr_method_case.html]
 [test_signed_web_packaged_app.html]
 skip-if = e10s || buildapp != 'browser'
 [test_signed_web_packaged_app_origin.html]
 skip-if = e10s || buildapp != 'browser'
+[test_signed_to_signed_web_packaged_app.html]
+skip-if = e10s || buildapp != 'browser'
 [test_web_packaged_app.html]
 [test_loadinfo_redirectchain.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_idn_redirect.html]
 [test_origin_attributes_conversion.html]
 skip-if = e10s || buildapp != 'browser'
new file mode 100644
--- /dev/null
+++ b/netwerk/test/mochitests/signed_web_packaged_app_random.sjs
@@ -0,0 +1,92 @@
+// Same as signed_web_packaged_app.sjs except this one would return a random
+// package-identifer.
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+
+var uuid = Cc["@mozilla.org/uuid-generator;1"].
+             getService(Ci.nsIUUIDGenerator).
+             generateUUID().
+             toString().replace(/[{}]/g, "");
+
+function handleRequest(request, response)
+{
+  response.setHeader("Content-Type", "application/package", false);
+  response.write(signedPackage);
+  return;
+}
+
+// The package content
+// getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format
+var signedPackage = `manifest-signature: MIIF1AYJKoZIhvcNAQcCoIIFxTCCBcECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCA54wggOaMIICgqADAgECAgECMA0GCSqGSIb3DQEBCwUAMHMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEkMCIGA1UEChMbRXhhbXBsZSBUcnVzdGVkIENvcnBvcmF0aW9uMRkwFwYDVQQDExBUcnVzdGVkIFZhbGlkIENBMB4XDTE1MDkxMDA4MDQzNVoXDTM1MDkxMDA4MDQzNVowdDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGjAYBgNVBAMTEVRydXN0ZWQgQ29ycCBDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAts8whjOzEbn/w1xkFJ67af7F/JPujBK91oyJekh2schIMzFau9pY8S1AiJQoJCulOJCJfUc8hBLKBZiGAkii+4Gpx6cVqMLe6C22MdD806Soxn8Dg4dQqbIvPuI4eeVKu5CEk80PW/BaFMmRvRHO62C7PILuH6yZeGHC4P7dTKpsk4CLxh/jRGXLC8jV2BCW0X+3BMbHBg53NoI9s1Gs7KGYnfOHbBP5wEFAa00RjHnubUaCdEBlC8Kl4X7p0S4RGb3rsB08wgFe9EmSZHIgcIm+SuVo7N4qqbI85qo2ulU6J8NN7ZtgMPHzrMhzgAgf/KnqPqwDIxnNmRNJmHTUYwIDAQABozgwNjAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAukH6cJUUj5faa8CuPCqrEa0PoLY4SYNnff9NI+TTAHkB9l+kOcFl5eo2EQOcWmZKYi7QLlWC4jy/KQYattO9FMaxiOQL4FAc6ZIbNyfwWBzZWyr5syYJTTTnkLq8A9pCKarN49+FqhJseycU+8EhJEJyP5pv5hLvDNTTHOQ6SXhASsiX8cjo3AY4bxA5pWeXuTZ459qDxOnQd+GrOe4dIeqflk0hA2xYKe3SfF+QlK8EO370B8Dj8RX230OATM1E3OtYyALe34KW3wM9Qm9rb0eViDnVyDiCWkhhQnw5yPg/XQfloug2itRYuCnfUoRt8xfeHgwz2Ymz8cUADn3KpTGCAf4wggH6AgEBMHgwczELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFRydXN0ZWQgVmFsaWQgQ0ECAQIwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE1MTAyODExMTIwMlowIwYJKoZIhvcNAQkEMRYEFENKTXRUkdej+EPd/oKRhz0Cp13zMA0GCSqGSIb3DQEBAQUABIIBAFCr+i8cwTiwzzCVjzZZI2NAqu8dnYOAJjkhD02tJjBCbvehEhXW6pP/Gk8+oyx2zoV87zbw9xBGcEU9b3ulbggdFR56S3C3w+eTbeOXMcx7A8mn9vvsoMJm+/rkT4DgEUU1iaM7pdwH48CKJOnAZP5FkjRvpRBh8TgfcDbusXveYTwG5LVpDp8856+9FBzvZ7wLz9iWDvlT/EFxfWOnGduAJunQ9qQm+pWu5cvSTwWasCMYmiPRlsuBhU9Fx7LtlXIHtE2nYYQVMTMDE58z/mzT34W0bnneecrghHREhb90UvdlUZJ2q3Jahsa3718WUGPTp7ZYwYaPBy7ryoOoWSA=\r
+--7IYGY9UDJB\r
+Content-Location: manifest.webapp\r
+Content-Type: application/x-web-app-manifest+json\r
+\r
+{
+  "moz-package-origin": "http://mochi.test:8888",
+  "name": "My App",
+  "moz-resources": [
+    {
+      "src": "page2.html",
+      "integrity": "JREF3JbXGvZ+I1KHtoz3f46ZkeIPrvXtG4VyFQrJ7II="
+    },
+    {
+      "src": "index.html",
+      "integrity": "IjQ2S/V9qsC7wW5uv/Niq40M1aivvqH5+1GKRwUnyRg="
+    },
+    {
+      "src": "scripts/script.js",
+      "integrity": "6TqtNArQKrrsXEQWu3D9ZD8xvDRIkhyV6zVdTcmsT5Q="
+    },
+    {
+      "src": "scripts/library.js",
+      "integrity": "TN2ByXZiaBiBCvS4MeZ02UyNi44vED+KjdjLInUl4o8="
+    }
+  ],
+  "moz-permissions": [
+    {
+      "systemXHR": {
+        "description": "Needed to download stuff"
+      },
+      "devicestorage:pictures": {
+        "description": "Need to load pictures"
+      }
+    }
+  ],
+
+`
+  + '  "package-identifier": "' +  uuid + '",\n\r' +
+`
+  "description": "A great app!"
+}\r
+--7IYGY9UDJB\r
+Content-Location: page2.html\r
+Content-Type: text/html\r
+\r
+<html>
+  page2.html
+</html>
+\r
+--7IYGY9UDJB\r
+Content-Location: index.html\r
+Content-Type: text/html\r
+\r
+<html>
+  Last updated: 2015/10/28
+</html>
+\r
+--7IYGY9UDJB\r
+Content-Location: scripts/script.js\r
+Content-Type: text/javascript\r
+\r
+// script.js
+\r
+--7IYGY9UDJB\r
+Content-Location: scripts/library.js\r
+Content-Type: text/javascript\r
+\r
+// library.js
+\r
+--7IYGY9UDJB--`;
new file mode 100644
--- /dev/null
+++ b/netwerk/test/mochitests/test_signed_to_signed_web_packaged_app.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title> Web packaged app </title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+
+var Cc = SpecialPowers.Cc;
+var Ci = SpecialPowers.Ci;
+var Cu = SpecialPowers.Cu;
+var Cr = SpecialPowers.Cr;
+
+SpecialPowers.pushPrefEnv(
+  { "set": [["network.http.enable-packaged-apps", true],
+            ["dom.ipc.processPriorityManager.testMode", true],
+            ["network.http.signed-packages.enabled", true],
+            ["network.http.signed-packages.trusted-origin", "http://mochi.test:8888"],
+            ["dom.ipc.processPriorityManager.enabled", true],
+            ["dom.ipc.tabs.disabled", false],
+            ["dom.ipc.processCount", 30],
+            ["dom.mozBrowserFramesEnabled", true]] },
+  () => SpecialPowers.pushPermissions([
+    { "type": "browser", "allow": 1, "context": document }
+  ], function() {
+    runTest();
+  }));
+
+SimpleTest.waitForExplicitFinish();
+
+// Listen for and count process-created event. There should be 3 processes
+// to be created:
+// 1) The remote tab
+// 2) While navigating to http://mochi.test:8888/tests/netwerk/test/mochitests/signed_web_packaged_app_random.sjs!//scripts/app.js
+// 3) While navigating to http://mochi.test:8888/tests/netwerk/test/mochitests/signed_web_packaged_app_random.sjs!//index.html
+//
+// Note that signed_web_packaged_app_random.sjs will return different package identifier
+// in each request. Therefore, step (3) should trigger process switch.
+var kProcessCreatedTopic = "process-priority-manager:TEST-ONLY:process-created";
+var processCreatedCnt = 0;
+SpecialPowers.addObserver(() => {
+  processCreatedCnt++;
+  if (processCreatedCnt == 3) {
+    SimpleTest.finish();
+  } else {
+    ok(true, "We have " + (3 - processCreatedCnt) + " processes to create.");
+  }
+}, kProcessCreatedTopic, /* weak = */ false);
+
+function runTest() {
+  var iframe = document.createElement("iframe");
+  iframe.setAttribute('mozbrowser', 'true');
+  iframe.setAttribute('remote', 'true');
+  iframe.setAttribute("src", "http://example.org:80");
+
+  iframe.addEventListener("mozbrowserloadend", function loadend(e) {
+    iframe.removeEventListener("mozbrowserloadend", loadend);
+    ok(true, "Got mozbrowserloadend 1");
+    iframe.setAttribute("src", "http://mochi.test:8888/tests/netwerk/test/mochitests/signed_web_packaged_app_random.sjs!//scripts/app.js");
+
+    iframe.addEventListener("mozbrowserloadend", function loadend(e) {
+      iframe.removeEventListener("mozbrowserloadend", loadend);
+      ok(true, "Got mozbrowserloadend 2");
+      iframe.setAttribute("src", "http://mochi.test:8888/tests/netwerk/test/mochitests/signed_web_packaged_app_random.sjs!//index.html");
+    });
+
+  });
+
+  document.body.appendChild(iframe);
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/netwerk/test/unit/test_304_responses.js
+++ b/netwerk/test/unit/test_304_responses.js
@@ -1,13 +1,13 @@
 "use strict";
 // https://bugzilla.mozilla.org/show_bug.cgi?id=761228
 
 Cu.import("resource://testing-common/httpd.js");
-Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "URL", function() {
   return "http://localhost:" + httpServer.identity.primaryPort;
 });
 
 var httpServer = null;
 const testFileName = "test_customConditionalRequest_304";
 const basePath = "/" + testFileName + "/";
@@ -21,26 +21,18 @@ const existingCached304 = "existingCache
 
 function make_uri(url) {
   var ios = Cc["@mozilla.org/network/io-service;1"].
             getService(Ci.nsIIOService);
   return ios.newURI(url, null, null);
 }
 
 function make_channel(url) {
-  var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
-  var chan = ios.newChannel2(url,
-                             null,
-                             null,
-                             null,      // aLoadingNode
-                             Services.scriptSecurityManager.getSystemPrincipal(),
-                             null,      // aTriggeringPrincipal
-                             Ci.nsILoadInfo.SEC_NORMAL,
-                             Ci.nsIContentPolicy.TYPE_OTHER).QueryInterface(Ci.nsIHttpChannel);
-  return chan;
+  return NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true})
+                .QueryInterface(Ci.nsIHttpChannel);
 }
 
 function clearCache() {
     var service = Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
         .getService(Ci.nsICacheStorageService);
     service.clear();
 }
 
@@ -71,17 +63,17 @@ function consume304(request, buffer) {
   do_check_eq(request.getResponseHeader("Returned-From-Handler"), "1");
   run_next_test();
 }
 
 // Test that we return a 304 response to the caller when we are not expecting
 // a 304 response (i.e. when the server shouldn't have sent us one).
 add_test(function test_unexpected_304() {
   var chan = make_channel(baseURI + unexpected304);
-  chan.asyncOpen(new ChannelListener(consume304, null), null);
+  chan.asyncOpen2(new ChannelListener(consume304, null));
 });
 
 // Test that we can cope with a 304 response that was (erroneously) stored in
 // the cache.
 add_test(function test_304_stored_in_cache() {
   asyncOpenCacheEntry(
     baseURI + existingCached304, "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null,
     function (entryStatus, cacheEntry) {
@@ -93,11 +85,11 @@ add_test(function test_304_stored_in_cac
       cacheEntry.close();
 
       var chan = make_channel(baseURI + existingCached304);
 
       // make it a custom conditional request
       chan.QueryInterface(Components.interfaces.nsIHttpChannel);
       chan.setRequestHeader("If-None-Match", '"foo"', false);
 
-      chan.asyncOpen(new ChannelListener(consume304, null), null);
+      chan.asyncOpen2(new ChannelListener(consume304, null));
     });
 });
--- a/netwerk/test/unit/test_bug1064258.js
+++ b/netwerk/test/unit/test_bug1064258.js
@@ -6,35 +6,26 @@
  * - check the entry has metadata, but zero-length content
  * - load the same URL again, now cached
  * - check the channel is giving no content (no call to OnDataAvailable) but succeeds
  * - repeat again, but for a different URL that is not cached (immediately expires)
  * - only difference is that we get a newer version of the content from the server during the second request
  */
 
 Cu.import("resource://testing-common/httpd.js");
-Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "URL", function() {
   return "http://localhost:" + httpServer.identity.primaryPort;
 });
 
 var httpServer = null;
 
 function make_channel(url, callback, ctx) {
-  var ios = Cc["@mozilla.org/network/io-service;1"].
-            getService(Ci.nsIIOService);
-  return ios.newChannel2(url,
-                         "",
-                         null,
-                         null,      // aLoadingNode
-                         Services.scriptSecurityManager.getSystemPrincipal(),
-                         null,      // aTriggeringPrincipal
-                         Ci.nsILoadInfo.SEC_NORMAL,
-                         Ci.nsIContentPolicy.TYPE_OTHER);
+  return NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
 }
 
 const responseBody1 = "response body 1";
 const responseBody2a = "response body 2a";
 const responseBody2b = "response body 2b";
 
 function contentHandler1(metadata, response)
 {
@@ -76,17 +67,17 @@ function run_test()
   do_test_pending();
 }
 
 function run_test_content1a()
 {
   var chan = make_channel(URL + "/content1");
   caching = chan.QueryInterface(Ci.nsICachingChannel);
   caching.cacheOnlyMetadata = true;
-  chan.asyncOpen(new ChannelListener(contentListener1a, null), null);
+  chan.asyncOpen2(new ChannelListener(contentListener1a, null));
 }
 
 function contentListener1a(request, buffer)
 {
   do_check_eq(buffer, responseBody1);
 
   asyncOpenCacheEntry(URL + "/content1", "disk", 0, null, cacheCheck1)
 }
@@ -100,17 +91,17 @@ function cacheCheck1(status, entry)
   }
   catch (ex) {
     do_throw("Missing response head");
   }
 
   var chan = make_channel(URL + "/content1");
   caching = chan.QueryInterface(Ci.nsICachingChannel);
   caching.cacheOnlyMetadata = true;
-  chan.asyncOpen(new ChannelListener(contentListener1b, null, CL_IGNORE_CL), null);
+  chan.asyncOpen2(new ChannelListener(contentListener1b, null, CL_IGNORE_CL));
 }
 
 function contentListener1b(request, buffer)
 {
   request.QueryInterface(Ci.nsIHttpChannel);
   do_check_eq(request.requestMethod, "GET");
   do_check_eq(request.responseStatus, 200);
   do_check_eq(request.getResponseHeader("Cache-control"), "max-age=999999");
@@ -121,17 +112,17 @@ function contentListener1b(request, buff
 
 // Now same set of steps but this time for an immediately expiring content.
 
 function run_test_content2a()
 {
   var chan = make_channel(URL + "/content2");
   caching = chan.QueryInterface(Ci.nsICachingChannel);
   caching.cacheOnlyMetadata = true;
-  chan.asyncOpen(new ChannelListener(contentListener2a, null), null);
+  chan.asyncOpen2(new ChannelListener(contentListener2a, null));
 }
 
 function contentListener2a(request, buffer)
 {
   do_check_eq(buffer, responseBody2a);
 
   asyncOpenCacheEntry(URL + "/content2", "disk", 0, null, cacheCheck2)
 }
@@ -146,17 +137,17 @@ function cacheCheck2(status, entry)
   }
   catch (ex) {
     do_throw("Missing response head");
   }
 
   var chan = make_channel(URL + "/content2");
   caching = chan.QueryInterface(Ci.nsICachingChannel);
   caching.cacheOnlyMetadata = true;
-  chan.asyncOpen(new ChannelListener(contentListener2b, null), null);
+  chan.asyncOpen2(new ChannelListener(contentListener2b, null));
 }
 
 function contentListener2b(request, buffer)
 {
   do_check_eq(buffer, responseBody2b);
 
   httpServer.stop(do_test_finished);
 }
--- a/netwerk/test/unit/test_bug248970_cookie.js
+++ b/netwerk/test/unit/test_bug248970_cookie.js
@@ -1,40 +1,34 @@
 /* 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/. */
 
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");