merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 23 Mar 2016 16:14:48 +0100
changeset 290021 6202ade0e6d688ffb67932398e56cfc6fa04ceb3
parent 289879 efe7d026ac641759838dd3897c37892e37e5b244 (current diff)
parent 290020 b79f70a20d4a380715f1fc79a986aac6703d993a (diff)
child 290026 67ac681f7e53516cb009e821f9fa19e057b4417d
child 290069 4b36423739fa9ccbd2e04b6e934109bc05d8db30
push id30112
push usercbook@mozilla.com
push dateWed, 23 Mar 2016 15:25:32 +0000
treeherdermozilla-central@6202ade0e6d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone48.0a1
first release with
nightly linux32
6202ade0e6d6 / 48.0a1 / 20160324030447 / files
nightly linux64
6202ade0e6d6 / 48.0a1 / 20160324030447 / files
nightly mac
6202ade0e6d6 / 48.0a1 / 20160324030447 / files
nightly win32
6202ade0e6d6 / 48.0a1 / 20160324030447 / files
nightly win64
6202ade0e6d6 / 48.0a1 / 20160324030447 / 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/base/test/chrome/test_bug650776.html
dom/base/test/chrome/test_bug650784.html
dom/base/test/chrome/test_bug750096.html
dom/promise/tests/test_dependentPromises.html
dom/xslt/nsIXSLTException.idl
gfx/layers/ipc/CompositorChild.cpp
gfx/layers/ipc/CompositorChild.h
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/CompositorParent.h
gfx/layers/ipc/PCompositor.ipdl
js/src/jit-test/tests/basic/regexp-multiline-warning.js
js/src/jit-test/tests/basic/regexp-multiline.js
js/src/tests/js1_2/regexp/RegExp_multiline.js
js/src/tests/js1_2/regexp/RegExp_multiline_as_array.js
js/src/tests/js1_5/Regress/regress-418504.js
js/xpconnect/tests/unit/test_bug641378.js
layout/reftests/invalidation/fractional-transform-1.html
layout/reftests/invalidation/fractional-transform-2.html
layout/reftests/invalidation/fractional-transform-3.html
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/base/java/org/mozilla/gecko/TextSelection.java
mobile/android/base/java/org/mozilla/gecko/home/HomeBanner.java
mobile/android/base/java/org/mozilla/gecko/home/HomeConfig.java
mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
testing/mozharness/configs/releases/postrelease_beta.py
testing/mozharness/configs/releases/postrelease_date.py
testing/mozharness/configs/releases/updates_beta.py
testing/mozharness/configs/releases/updates_date.py
--- a/b2g/common.configure
+++ b/b2g/common.configure
@@ -10,12 +10,12 @@ option(env='MOZTTDIR', nargs=1, help='Pa
 
 @depends('MOZTTDIR')
 def mozttdir(value):
     if value:
         path = value[0]
         if not os.path.isdir(path):
             error('MOZTTDIR "%s" is not a valid directory' % path)
         set_config('MOZTTDIR', path)
-        set_define('PACKAGE_MOZTT', '1')
+        set_define('PACKAGE_MOZTT', True)
 
 
 include('../toolkit/moz.configure')
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -1207,28 +1207,19 @@ if (Services.prefs.getBoolPref("privacy.
     onViewHiding: function(aEvent) {
       let forgetButton = aEvent.target.querySelector("#PanelUI-panic-view-button");
       forgetButton.removeEventListener("command", this);
     },
   });
 }
 
 if (AppConstants.E10S_TESTING_ONLY) {
-  var e10sDisabled = false;
-
-  if (AppConstants.platform == "macosx") {
-    // On OS X, "Disable Hardware Acceleration" also disables OMTC and forces
-    // a fallback to Basic Layers. This is incompatible with e10s.
-    e10sDisabled |= Services.prefs.getBoolPref("layers.acceleration.disabled");
-  }
-
   if (Services.appinfo.browserTabsRemoteAutostart) {
     CustomizableWidgets.push({
       id: "e10s-button",
-      disabled: e10sDisabled,
       defaultArea: CustomizableUI.AREA_PANEL,
       onBuild: function(aDocument) {
           node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
           node.setAttribute("tooltiptext", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
       },
       onCommand: function(aEvent) {
         let win = aEvent.view;
         if (win && typeof win.OpenBrowserWindow == "function") {
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -9,17 +9,19 @@ MOZ_UPDATER=1
 MOZ_PHOENIX=1
 
 if test "$OS_ARCH" = "WINNT"; then
   MOZ_MAINTENANCE_SERVICE=1
   if ! test "$HAVE_64BIT_BUILD"; then
     if test "$MOZ_UPDATE_CHANNEL" = "nightly" -o \
             "$MOZ_UPDATE_CHANNEL" = "aurora" -o \
             "$MOZ_UPDATE_CHANNEL" = "beta" -o \
-            "$MOZ_UPDATE_CHANNEL" = "release"; then
+            "$MOZ_UPDATE_CHANNEL" = "beta-dev" -o \
+            "$MOZ_UPDATE_CHANNEL" = "release" -o \
+            "$MOZ_UPDATE_CHANNEL" = "release-dev"; then
       if ! test "$MOZ_DEBUG"; then
         MOZ_STUB_INSTALLER=1
       fi
     fi
   fi
 fi
 
 # Enable building ./signmar and running libmar signature tests
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -443,34 +443,32 @@ AC_DEFUN([MOZ_SET_WARNINGS_CFLAGS],
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wsign-compare"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wunreachable-code"
 
     # -Wclass-varargs - catches objects passed by value to variadic functions.
     # -Wloop-analysis - catches issues around loops
     # -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
     # -Wthread-safety - catches inconsistent use of mutexes
-    # -Wunreachable-code-aggressive - catches lots of dead code
     #
     # XXX: at the time of writing, the version of clang used on the OS X test
     # machines has a bug that causes it to reject some valid files if both
     # -Wnon-literal-null-conversion and -Wsometimes-uninitialized are
     # specified. We work around this by instead using
     # -Werror=non-literal-null-conversion, but we only do that when
     # --enable-warnings-as-errors is specified so that no unexpected fatal
     # warnings are produced.
     MOZ_C_SUPPORTS_WARNING(-W, class-varargs, ac_c_has_wclass_varargs)
     MOZ_C_SUPPORTS_WARNING(-W, loop-analysis, ac_c_has_wloop_analysis)
 
     if test "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
         MOZ_C_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_c_has_non_literal_null_conversion)
     fi
 
     MOZ_C_SUPPORTS_WARNING(-W, thread-safety, ac_c_has_wthread_safety)
-    MOZ_C_SUPPORTS_WARNING(-W, unreachable-code-aggressive, ac_c_has_wunreachable_code_aggressive)
 
     # Turn off some non-useful warnings that -Wall turns on.
 
     # Prevent the following GCC warnings from being treated as errors:
     # -Wmaybe-uninitialized - too many false positives
     # -Wdeprecated-declarations - we don't want our builds held hostage when a
     #   platform-specific API becomes deprecated.
     # -Wfree-nonheap-object - false positives during PGO
@@ -493,34 +491,34 @@ AC_DEFUN([MOZ_SET_WARNINGS_CXXFLAGS],
     # -Wall - lots of useful warnings
     # -Wc++1[14z]-compat[-pedantic] - catches C++ version forward-compat issues
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
     # -Wignored-qualifiers - catches return types with qualifiers like const
     # -Woverloaded-virtual - function declaration hides virtual function from base class
     # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
     # -Wsign-compare - catches comparing signed/unsigned ints
     # -Wtype-limits - catches overflow bugs, few false positives
+    # -Wunreachable-code - catches some dead code
     # -Wwrite-strings - catches treating string literals as non-const
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wc++11-compat"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wempty-body"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wignored-qualifiers"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Woverloaded-virtual"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wpointer-arith"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wsign-compare"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wunreachable-code"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wwrite-strings"
 
     # -Wclass-varargs - catches objects passed by value to variadic functions.
     # -Wimplicit-fallthrough - catches unintentional switch case fallthroughs
     # -Wloop-analysis - catches issues around loops
     # -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
     # -Wthread-safety - catches inconsistent use of mutexes
-    # -Wunreachable-code - catches some dead code
-    # -Wunreachable-code-return - catches dead code after return call
     #
     # XXX: at the time of writing, the version of clang used on the OS X test
     # machines has a bug that causes it to reject some valid files if both
     # -Wnon-literal-null-conversion and -Wsometimes-uninitialized are
     # specified. We work around this by instead using
     # -Werror=non-literal-null-conversion, but we only do that when
     # --enable-warnings-as-errors is specified so that no unexpected fatal
     # warnings are produced.
@@ -532,18 +530,16 @@ AC_DEFUN([MOZ_SET_WARNINGS_CXXFLAGS],
     MOZ_CXX_SUPPORTS_WARNING(-W, implicit-fallthrough, ac_cxx_has_wimplicit_fallthrough)
     MOZ_CXX_SUPPORTS_WARNING(-W, loop-analysis, ac_cxx_has_wloop_analysis)
 
     if test "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
         MOZ_CXX_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_cxx_has_non_literal_null_conversion)
     fi
 
     MOZ_CXX_SUPPORTS_WARNING(-W, thread-safety, ac_cxx_has_wthread_safety)
-    MOZ_CXX_SUPPORTS_WARNING(-W, unreachable-code, ac_cxx_has_wunreachable_code)
-    MOZ_CXX_SUPPORTS_WARNING(-W, unreachable-code-return, ac_cxx_has_wunreachable_code_return)
 
     # Turn off some non-useful warnings that -Wall turns on.
 
     # -Wno-invalid-offsetof - we use offsetof on non-POD types frequently
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-invalid-offsetof"
 
     # -Wno-inline-new-delete - we inline 'new' and 'delete' in mozalloc
     MOZ_CXX_SUPPORTS_WARNING(-Wno-, inline-new-delete, ac_cxx_has_wno_inline_new_delete)
--- a/build/moz.configure/checks.configure
+++ b/build/moz.configure/checks.configure
@@ -70,10 +70,11 @@ def check_prog(var, progs, allow_missing
     @depends(check)
     @advanced
     def postcheck(value):
         set_config(var, ':' if value is not_found else value)
         if value is not_found and not allow_missing:
             from mozbuild.shellutil import quote
             error('Cannot find %s (tried: %s)'
                   % (var.lower(), ', '.join(quote(p) for p in progs)))
+        return None if value is not_found else value
 
-    return check
+    return postcheck
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -11,26 +11,33 @@ option(env='DIST', nargs=1, help='DIST d
 # Do not allow objdir == srcdir builds.
 # ==============================================================
 @depends('--help', 'DIST')
 def check_build_environment(help, dist):
     topobjdir = os.path.realpath(os.path.abspath('.'))
     topsrcdir = os.path.realpath(os.path.abspath(
         os.path.join(os.path.dirname(__file__), '..', '..')))
 
+    if dist:
+        dist = normsep(dist[0])
+    else:
+        dist = os.path.join(topobjdir, 'dist')
+
+    result = namespace(
+        topsrcdir=topsrcdir,
+        topobjdir=topobjdir,
+        dist=dist,
+    )
     set_config('TOPSRCDIR', topsrcdir)
     set_config('TOPOBJDIR', topobjdir)
     set_config('MOZ_BUILD_ROOT', topobjdir)
-    if dist:
-        set_config('DIST', normsep(dist[0]))
-    else:
-        set_config('DIST', os.path.join(topobjdir, 'dist'))
+    set_config('DIST', dist)
 
     if help:
-        return
+        return result
 
     if topsrcdir == topobjdir:
         error(
             '  ***\n'
             '  * Building directly in the main source directory is not allowed.\n'
             '  *\n'
             '  * To build, you must run configure from a separate directory\n'
             '  * (referred to as an object directory).\n'
@@ -55,16 +62,18 @@ def check_build_environment(help, dist):
             '  *\n'
             '  *   To clean up the source tree:\n'
             '  *     1. cd %s\n'
             '  *     2. gmake distclean\n'
             '  ***'
             % ('\n  '.join(conflict_files), topsrcdir)
         )
 
+    return result
+
 
 option(env='OLD_CONFIGURE', nargs=1, help='Path to the old configure script')
 
 option(env='MOZ_CURRENT_PROJECT', nargs=1, help='Current build project')
 option(env='MOZCONFIG', nargs=1, help='Mozconfig location')
 
 # Read user mozconfig
 # ==============================================================
@@ -94,17 +103,17 @@ def mozconfig(current_project, mozconfig
     # Unfortunately, there is no direct way to tell whether the running
     # configure is the js configure. The indirect way is to look at the
     # OLD_CONFIGURE path, which points to js/src/old-configure.
     # I expect we'll have figured things out for mozconfigs well before
     # old-configure dies.
     if os.path.dirname(os.path.abspath(old_configure[0])).endswith('/js/src'):
         return {'path': None}
 
-    loader = MozconfigLoader(build_env['TOPSRCDIR'])
+    loader = MozconfigLoader(build_env.topsrcdir)
     current_project = current_project[0] if current_project else None
     mozconfig = mozconfig[0] if mozconfig else None
     mozconfig = loader.find_mozconfig(env={'MOZCONFIG': mozconfig})
     mozconfig = loader.read_mozconfig(mozconfig, moz_build_app=current_project)
 
     return mozconfig
 
 
@@ -119,18 +128,23 @@ def old_configure_assignments(help):
 def extra_old_configure_args(help):
     return []
 
 @template
 def add_old_configure_assignment(var, value):
     @depends(old_configure_assignments)
     @advanced
     def add_assignment(assignments):
-        from mozbuild.shellutil import quote
-        assignments.append('%s=%s' % (var, quote(value)))
+        if value is True:
+            assignments.append('%s=1' % var)
+        elif value is False:
+            assignments.append('%s=' % var)
+        else:
+            from mozbuild.shellutil import quote
+            assignments.append('%s=%s' % (var, quote(value)))
 
 @template
 def add_old_configure_arg(arg):
     @depends(extra_old_configure_args)
     def add_arg(args):
         args.append(arg)
 
 
@@ -160,17 +174,17 @@ def virtualenv_python(env_python, build_
         elif 'PYTHON' in mozconfig['env']['modified']:
             python = mozconfig['env']['modified']['PYTHON'][1]
         elif 'PYTHON' in mozconfig['vars']['added']:
             python = mozconfig['vars']['added']['PYTHON']
         elif 'PYTHON' in mozconfig['vars']['modified']:
             python = mozconfig['vars']['modified']['PYTHON'][1]
 
     verify_python_version(sys.stderr)
-    topsrcdir, topobjdir = build_env['TOPSRCDIR'], build_env['TOPOBJDIR']
+    topsrcdir, topobjdir = build_env.topsrcdir, build_env.topobjdir
     if topobjdir.endswith('/js/src'):
         topobjdir = topobjdir[:-7]
 
     manager = VirtualenvManager(
         topsrcdir, topobjdir,
         os.path.join(topobjdir, '_virtualenv'), sys.stdout,
         os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'))
 
@@ -220,19 +234,19 @@ def command_line_helper():
     # it is a one off and because the required functionality doesn't need
     # to be exposed for other usecases.
     return depends.__self__._helper
 
 
 # All options defined above this point can't be injected in mozconfig_options
 # below, so collect them.
 @template
-@advanced
 def early_options():
     @depends('--help')
+    @advanced
     def early_options(help):
         return set(
             option.env
             for option in depends.__self__._options.itervalues()
             if option.env
         )
     return early_options
 
@@ -500,17 +514,17 @@ def target_variables(target):
         os_test = target.raw_cpu
     add_old_configure_assignment('OS_TEST', os_test)
     set_config('OS_TEST', os_test)
 
     add_old_configure_assignment('CPU_ARCH', target.cpu)
     set_config('CPU_ARCH', target.cpu)
 
     if target.cpu in ('x86', 'x86_64'):
-        set_config('INTEL_ARCHITECTURE', '1')
+        set_config('INTEL_ARCHITECTURE', True)
 
     set_config('TARGET_CPU', target.raw_cpu)
     set_config('TARGET_OS', target.raw_os)
 
 @depends(host)
 def host_variables(host):
     if host.kernel == 'kFreeBSD':
         os_arch = 'GNU_kFreeBSD'
@@ -518,111 +532,111 @@ def host_variables(host):
         os_arch = host.kernel
     add_old_configure_assignment('HOST_OS_ARCH', os_arch)
     set_config('HOST_OS_ARCH', os_arch)
 
 
 @depends(target)
 def target_platform_defines(target):
     if target.kernel == 'WINNT':
-        set_define('_WINDOWS', '1')
-        set_define('WIN32', '1')
-        set_define('XP_WIN', '1')
-        set_define('XP_WIN32', '1')
+        set_define('_WINDOWS', True)
+        set_define('WIN32', True)
+        set_define('XP_WIN', True)
+        set_define('XP_WIN32', True)
     else:
-        set_define('XP_UNIX', '1')
+        set_define('XP_UNIX', True)
 
     if target.kernel == 'Darwin':
-        set_define('XP_DARWIN', '1')
+        set_define('XP_DARWIN', True)
         if target.os == 'iOS':
-            set_define('XP_IOS', '1')
+            set_define('XP_IOS', True)
         elif target.os == 'OSX':
-            set_define('XP_MACOSX', '1')
+            set_define('XP_MACOSX', True)
     elif target.kernel == 'Linux':
-        set_define('XP_LINUX', '1')
+        set_define('XP_LINUX', True)
 
 
 # The application/project to build
 # ==============================================================
 option('--enable-application', nargs=1, env='MOZ_BUILD_APP',
        help='Application to build. Same as --enable-project.')
 
 @depends('--enable-application', '--help')
 def application(app, help):
     if app:
         imply_option(app.format('--enable-project'))
 
 
 @depends(check_build_environment, '--help')
 def default_project(build_env, help):
-    if build_env['TOPOBJDIR'].endswith('/js/src'):
+    if build_env.topobjdir.endswith('/js/src'):
         return 'js'
     return 'browser'
 
 option('--enable-project', nargs=1, default=default_project,
        help='Project to build')
 
 option('--with-external-source-dir', env='EXTERNAL_SOURCE_DIR', nargs=1,
        help='External directory containing additional build files')
 
 @depends('--enable-project', '--with-external-source-dir',
          check_build_environment, '--help')
 def include_project_configure(project, external_source_dir, build_env, help):
     if not project:
         error('--enable-project is required.')
 
-    base_dir = build_env['TOPSRCDIR']
+    base_dir = build_env.topsrcdir
     if external_source_dir:
         set_config('EXTERNAL_SOURCE_DIR', external_source_dir[0])
         add_old_configure_assignment('EXTERNAL_SOURCE_DIR',
                                      external_source_dir[0])
         base_dir = os.path.join(base_dir, external_source_dir[0])
 
     path = os.path.join(base_dir, project[0], 'moz.configure')
     if not os.path.exists(path):
         error('Cannot find project %s' % project[0])
     return path
 
 @depends(include_project_configure, check_build_environment, '--help')
 def build_project(include_project_configure, build_env, help):
     ret = os.path.dirname(os.path.relpath(include_project_configure,
-                                          build_env['TOPSRCDIR']))
+                                          build_env.topsrcdir))
     set_config('MOZ_BUILD_APP', ret)
     set_define('MOZ_BUILD_APP', ret)
     add_old_configure_assignment('MOZ_BUILD_APP', ret)
     return ret
 
 
 # set RELEASE_BUILD and NIGHTLY_BUILD variables depending on the cycle we're in
 # The logic works like this:
 # - if we have "a1" in GRE_MILESTONE, we're building Nightly (define NIGHTLY_BUILD)
 # - otherwise, if we have "a" in GRE_MILESTONE, we're building Nightly or Aurora
 # - otherwise, we're building Release/Beta (define RELEASE_BUILD)
 @depends(check_build_environment)
 @advanced
 def milestone(build_env):
-    milestone_path = os.path.join(build_env['TOPSRCDIR'],
+    milestone_path = os.path.join(build_env.topsrcdir,
                                   'config',
                                   'milestone.txt')
     with open(milestone_path, 'r') as fh:
         milestone = fh.read().splitlines()[-1]
 
     set_config('GRE_MILESTONE', milestone)
 
     is_nightly = is_release = False
 
     if 'a1' in milestone:
-        set_config('NIGHTLY_BUILD', '1')
-        set_define('NIGHTLY_BUILD', '1')
-        add_old_configure_assignment('NIGHTLY_BUILD', '1')
+        set_config('NIGHTLY_BUILD', True)
+        set_define('NIGHTLY_BUILD', True)
+        add_old_configure_assignment('NIGHTLY_BUILD', True)
         is_nightly = True
     elif 'a' not in milestone:
-        set_config('RELEASE_BUILD', '1')
-        set_define('RELEASE_BUILD', '1')
-        add_old_configure_assignment('RELEASE_BUILD', '1')
+        set_config('RELEASE_BUILD', True)
+        set_define('RELEASE_BUILD', True)
+        add_old_configure_assignment('RELEASE_BUILD', True)
         is_release = True
 
     return namespace(version=milestone,
                      is_nightly=is_nightly,
                      is_release=is_release)
 
 # This is temporary until js/src/configure and configure are merged.
 # Use instead of option() in js/moz.configure
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -102,17 +102,17 @@ def prepare_configure(old_configure, moz
         old_configure_dir = os.path.dirname(old_configure)
         if not old_configure_dir.endswith('/js/src'):
             old_configure = os.path.join(old_configure_dir, 'js', 'src',
                                          os.path.basename(old_configure))
 
     refresh = True
     if os.path.exists(old_configure):
         mtime = getmtime(old_configure)
-        aclocal = os.path.join(build_env['TOPSRCDIR'], 'build', 'autoconf',
+        aclocal = os.path.join(build_env.topsrcdir, 'build', 'autoconf',
                                '*.m4')
         for input in itertools.chain(
             (old_configure + '.in',
              os.path.join(os.path.dirname(old_configure), 'aclocal.m4')),
             glob.iglob(aclocal),
         ):
             if getmtime(input) > mtime:
                 break
--- a/configure.py
+++ b/configure.py
@@ -24,22 +24,34 @@ def main(argv):
     if sandbox._help:
         return 0
 
     return config_status(config)
 
 
 def config_status(config):
     # Sanitize config data to feed config.status
+    # Ideally, all the backend and frontend code would handle the booleans, but
+    # there are so many things involved, that it's easier to keep config.status
+    # untouched for now.
+    def sanitized_bools(v):
+        if v is True:
+            return '1'
+        if v is False:
+            return ''
+        return v
+
     sanitized_config = {}
     sanitized_config['substs'] = {
-        k: v for k, v in config.iteritems()
+        k: sanitized_bools(v) for k, v in config.iteritems()
         if k not in ('DEFINES', 'non_global_defines', 'TOPSRCDIR', 'TOPOBJDIR')
     }
-    sanitized_config['defines'] = config['DEFINES']
+    sanitized_config['defines'] = {
+        k: sanitized_bools(v) for k, v in config['DEFINES'].iteritems()
+    }
     sanitized_config['non_global_defines'] = config['non_global_defines']
     sanitized_config['topsrcdir'] = config['TOPSRCDIR']
     sanitized_config['topobjdir'] = config['TOPOBJDIR']
 
     # Create config.status. Eventually, we'll want to just do the work it does
     # here, when we're able to skip configure tests/use cached results/not rely
     # on autoconf.
     print("Creating config.status", file=sys.stderr)
--- a/devtools/server/actors/object.js
+++ b/devtools/server/actors/object.js
@@ -6,17 +6,16 @@
 
 "use strict";
 
 const { Cu, Ci } = require("chrome");
 const { GeneratedLocation } = require("devtools/server/actors/common");
 const { DebuggerServer } = require("devtools/server/main")
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const { assert, dumpn } = DevToolsUtils;
-const PromiseDebugging = require("PromiseDebugging");
 
 loader.lazyRequireGetter(this, "ThreadSafeChromeUtils");
 
 const TYPED_ARRAY_CLASSES = ["Uint8Array", "Uint8ClampedArray", "Uint16Array",
       "Uint32Array", "Int8Array", "Int16Array", "Int32Array", "Float32Array",
       "Float64Array"];
 
 // Number of items to preview in objects, arrays, maps, sets, lists,
@@ -135,32 +134,29 @@ ObjectActor.prototype = {
   },
 
   /**
    * Returns an object exposing the internal Promise state.
    */
   _createPromiseState: function() {
     const { state, value, reason } = getPromiseState(this.obj);
     let promiseState = { state };
-    let rawPromise = this.obj.unsafeDereference();
 
     if (state == "fulfilled") {
       promiseState.value = this.hooks.createValueGrip(value);
     } else if (state == "rejected") {
       promiseState.reason = this.hooks.createValueGrip(reason);
     }
 
-    promiseState.creationTimestamp = Date.now() -
-      PromiseDebugging.getPromiseLifetime(rawPromise);
+    promiseState.creationTimestamp = Date.now() - this.obj.promiseLifetime;
 
-    // If the promise is not settled, avoid adding the timeToSettle property
-    // and catch the error thrown by PromiseDebugging.getTimeToSettle.
-    try {
-      promiseState.timeToSettle = PromiseDebugging.getTimeToSettle(rawPromise);
-    } catch(e) {}
+    // Only add the timeToSettle property if the Promise isn't pending.
+    if (state !== "pending") {
+      promiseState.timeToSettle = this.obj.promiseTimeToResolution;
+    }
 
     return promiseState;
   },
 
   /**
    * Releases this actor from the pool.
    */
   release: function() {
@@ -536,35 +532,32 @@ ObjectActor.prototype = {
    */
   onDependentPromises: function() {
     if (this.obj.class != "Promise") {
       return { error: "objectNotPromise",
                message: "'dependentPromises' request is only valid for " +
                         "object grips with a 'Promise' class." };
     }
 
-    let rawPromise = this.obj.unsafeDereference();
-    let promises = PromiseDebugging.getDependentPromises(rawPromise).map(p =>
-      this.hooks.createValueGrip(this.obj.makeDebuggeeValue(p)));
+    let promises = this.obj.promiseDependentPromises.map(p => this.hooks.createValueGrip(p));
 
     return { promises };
   },
 
   /**
    * Handle a protocol request to get the allocation stack of a promise.
    */
   onAllocationStack: function() {
     if (this.obj.class != "Promise") {
       return { error: "objectNotPromise",
                message: "'allocationStack' request is only valid for " +
                         "object grips with a 'Promise' class." };
     }
 
-    let rawPromise = this.obj.unsafeDereference();
-    let stack = PromiseDebugging.getAllocationStack(rawPromise);
+    let stack = this.obj.promiseAllocationSite;
     let allocationStacks = [];
 
     while (stack) {
       if (stack.source) {
         let source = this._getSourceOriginalLocation(stack);
 
         if (source) {
           allocationStacks.push(source);
@@ -583,18 +576,17 @@ ObjectActor.prototype = {
    */
   onFulfillmentStack: function() {
     if (this.obj.class != "Promise") {
       return { error: "objectNotPromise",
                message: "'fulfillmentStack' request is only valid for " +
                         "object grips with a 'Promise' class." };
     }
 
-    let rawPromise = this.obj.unsafeDereference();
-    let stack = PromiseDebugging.getFullfillmentStack(rawPromise);
+    let stack = this.obj.promiseResolutionSite;
     let fulfillmentStacks = [];
 
     while (stack) {
       if (stack.source) {
         let source = this._getSourceOriginalLocation(stack);
 
         if (source) {
           fulfillmentStacks.push(source);
@@ -613,18 +605,17 @@ ObjectActor.prototype = {
    */
   onRejectionStack: function() {
     if (this.obj.class != "Promise") {
       return { error: "objectNotPromise",
                message: "'rejectionStack' request is only valid for " +
                         "object grips with a 'Promise' class." };
     }
 
-    let rawPromise = this.obj.unsafeDereference();
-    let stack = PromiseDebugging.getRejectionStack(rawPromise);
+    let stack = this.obj.promiseResolutionSite;
     let rejectionStacks = [];
 
     while (stack) {
       if (stack.source) {
         let source = this._getSourceOriginalLocation(stack);
 
         if (source) {
           rejectionStacks.push(source);
@@ -1645,40 +1636,31 @@ DebuggerServer.ObjectActorPreviewers.Obj
 
     return true;
   },
 
   GenericObject,
 ];
 
 /**
- * Call PromiseDebugging.getState on this Debugger.Object's referent and wrap
- * the resulting `value` or `reason` properties in a Debugger.Object instance.
- *
- * See dom/webidl/PromiseDebugging.webidl
+ * Get thisDebugger.Object referent's `promiseState`.
  *
  * @returns Object
  *          An object of one of the following forms:
  *          - { state: "pending" }
  *          - { state: "fulfilled", value }
  *          - { state: "rejected", reason }
  */
 function getPromiseState(obj) {
   if (obj.class != "Promise") {
     throw new Error(
       "Can't call `getPromiseState` on `Debugger.Object`s that don't " +
       "refer to Promise objects.");
   }
-
-  const state = PromiseDebugging.getState(obj.unsafeDereference());
-  return {
-    state: state.state,
-    value: obj.makeDebuggeeValue(state.value),
-    reason: obj.makeDebuggeeValue(state.reason)
-  };
+  return obj.promiseState;
 };
 
 /**
  * Determine if a given value is non-primitive.
  *
  * @param Any value
  *        The value to test.
  * @return Boolean
--- a/dom/animation/AnimationEffectTiming.cpp
+++ b/dom/animation/AnimationEffectTiming.cpp
@@ -4,16 +4,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/. */
 
 #include "mozilla/dom/AnimationEffectTiming.h"
 
 #include "mozilla/dom/AnimatableBinding.h"
 #include "mozilla/dom/AnimationEffectTimingBinding.h"
 #include "mozilla/TimingParams.h"
+#include "nsAString.h"
 
 namespace mozilla {
 namespace dom {
 
 JSObject*
 AnimationEffectTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return AnimationEffectTimingBinding::Wrap(aCx, this, aGivenProto);
@@ -23,28 +24,40 @@ static inline void
 PostSpecifiedTimingUpdated(KeyframeEffect* aEffect)
 {
   if (aEffect) {
     aEffect->NotifySpecifiedTimingUpdated();
   }
 }
 
 void
+AnimationEffectTiming::SetDelay(double aDelay)
+{
+  // TODO: Bug 1244633 - implement AnimationEffectTiming delay
+}
+
+void
 AnimationEffectTiming::SetEndDelay(double aEndDelay)
 {
   TimeDuration endDelay = TimeDuration::FromMilliseconds(aEndDelay);
   if (mTiming.mEndDelay == endDelay) {
     return;
   }
   mTiming.mEndDelay = endDelay;
 
   PostSpecifiedTimingUpdated(mEffect);
 }
 
 void
+AnimationEffectTiming::SetFill(const FillMode& aFill)
+{
+  // TODO: Bug 1244637 - implement AnimationEffectTiming fill
+}
+
+void
 AnimationEffectTiming::SetIterationStart(double aIterationStart,
                                          ErrorResult& aRv)
 {
   if (mTiming.mIterationStart == aIterationStart) {
     return;
   }
 
   TimingParams::ValidateIterationStart(aIterationStart, aRv);
@@ -53,16 +66,22 @@ AnimationEffectTiming::SetIterationStart
   }
 
   mTiming.mIterationStart = aIterationStart;
 
   PostSpecifiedTimingUpdated(mEffect);
 }
 
 void
+AnimationEffectTiming::SetIterations(double aIterations, ErrorResult& aRv)
+{
+  // TODO: Bug 1244640 - implement AnimationEffectTiming iterations
+}
+
+void
 AnimationEffectTiming::SetDuration(const UnrestrictedDoubleOrString& aDuration,
                                    ErrorResult& aRv)
 {
   Maybe<StickyTimeDuration> newDuration =
     TimingParams::ParseDuration(aDuration, aRv);
   if (aRv.Failed()) {
     return;
   }
@@ -71,10 +90,22 @@ AnimationEffectTiming::SetDuration(const
     return;
   }
 
   mTiming.mDuration = newDuration;
 
   PostSpecifiedTimingUpdated(mEffect);
 }
 
+void
+AnimationEffectTiming::SetDirection(const PlaybackDirection& aDirection)
+{
+  // TODO: Bug 1244642 - implement AnimationEffectTiming direction
+}
+
+void
+AnimationEffectTiming::SetEasing(const nsAString& aEasing, ErrorResult& aRv)
+{
+  // TODO: Bug 1244643 - implement AnimationEffectTiming easing
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/animation/AnimationEffectTiming.h
+++ b/dom/animation/AnimationEffectTiming.h
@@ -4,35 +4,41 @@
  * 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_AnimationEffectTiming_h
 #define mozilla_dom_AnimationEffectTiming_h
 
 #include "mozilla/dom/AnimationEffectTimingReadOnly.h"
 #include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
+#include "nsStringFwd.h"
 
 namespace mozilla {
 namespace dom {
 
 class AnimationEffectTiming : public AnimationEffectTimingReadOnly
 {
 public:
   AnimationEffectTiming(const TimingParams& aTiming, KeyframeEffect* aEffect)
     : AnimationEffectTimingReadOnly(aTiming)
     , mEffect(aEffect) { }
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void Unlink() override { mEffect = nullptr; }
 
+  void SetDelay(double aDelay);
   void SetEndDelay(double aEndDelay);
+  void SetFill(const FillMode& aFill);
   void SetIterationStart(double aIterationStart, ErrorResult& aRv);
+  void SetIterations(double aIterations, ErrorResult& aRv);
   void SetDuration(const UnrestrictedDoubleOrString& aDuration,
                    ErrorResult& aRv);
+  void SetDirection(const PlaybackDirection& aDirection);
+  void SetEasing(const nsAString& aEasing, ErrorResult& aRv);
 
 private:
   KeyframeEffect* MOZ_NON_OWNING_REF mEffect;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/animation/CSSPseudoElement.cpp
+++ b/dom/animation/CSSPseudoElement.cpp
@@ -45,17 +45,18 @@ CSSPseudoElement::GetParentObject() cons
 
 JSObject*
 CSSPseudoElement::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return CSSPseudoElementBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
-CSSPseudoElement::GetAnimations(nsTArray<RefPtr<Animation>>& aRetVal)
+CSSPseudoElement::GetAnimations(const AnimationFilter& filter,
+                                nsTArray<RefPtr<Animation>>& aRetVal)
 {
   nsIDocument* doc = mParentElement->GetComposedDoc();
   if (doc) {
     doc->FlushPendingNotifications(Flush_Style);
   }
 
   Element::GetAnimationsUnsorted(mParentElement, mPseudoType, aRetVal);
   aRetVal.Sort(AnimationPtrComparator<RefPtr<Animation>>());
--- a/dom/animation/CSSPseudoElement.h
+++ b/dom/animation/CSSPseudoElement.h
@@ -52,17 +52,18 @@ public:
       nsDependentAtomString(nsCSSPseudoElements::GetPseudoAtom(mPseudoType)));
   }
   already_AddRefed<Element> ParentElement() const
   {
     RefPtr<Element> retVal(mParentElement);
     return retVal.forget();
   }
 
-  void GetAnimations(nsTArray<RefPtr<Animation>>& aRetVal);
+  void GetAnimations(const AnimationFilter& filter,
+                     nsTArray<RefPtr<Animation>>& aRetVal);
   already_AddRefed<Animation>
     Animate(JSContext* aContext,
             JS::Handle<JSObject*> aFrames,
             const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
             ErrorResult& aError);
 
   // Given an element:pseudoType pair, returns the CSSPseudoElement stored as a
   // property on |aElement|. If there is no CSSPseudoElement for the specified
--- a/dom/animation/test/chrome/test_animation_property_state.html
+++ b/dom/animation/test/chrome/test_animation_property_state.html
@@ -717,17 +717,17 @@ function start() {
         [ { property: 'transform', runningOnCompositor: true } ]);
     }));
   }, 'transform of nsIFrame with SVG transform');
 
   promise_test(function(t) {
     var div = addDiv(t, { class: 'compositable',
                           style: 'animation: fade 100s' });
     var cssAnimation = div.getAnimations()[0];
-    var scriptAnimation = div.animate({ opacity: [ 1, 0 ] }, 1000);
+    var scriptAnimation = div.animate({ opacity: [ 1, 0 ] }, 100000);
     return scriptAnimation.ready.then(function() {
       assert_animation_property_state_equals(
         cssAnimation.effect.getProperties(),
         [ { property: 'opacity', runningOnCompositor: false } ]);
       assert_animation_property_state_equals(
         scriptAnimation.effect.getProperties(),
         [ { property: 'opacity', runningOnCompositor: true } ]);
     });
--- a/dom/animation/test/css-animations/file_element-get-animations.html
+++ b/dom/animation/test/css-animations/file_element-get-animations.html
@@ -299,11 +299,152 @@ async_test(function(t) {
     assert_equals(anims[0].animationName, 'anim1',
                   'animation order after cancelling and restarting');
     assert_equals(anims[1].animationName, 'anim2',
                   'animation order after cancelling and restarting');
     t.done();
   }));
 }, 'getAnimations for CSS Animations follows animation-name order');
 
+test(function(t) {
+  addStyle(t, { '#target::after': 'animation: anim1 10s;',
+                '#target::before': 'animation: anim1 10s;' });
+  var target = addDiv(t, { 'id': 'target' });
+  target.style.animation = 'anim1 100s';
+
+  var animations = target.getAnimations({ subtree: false });
+  assert_equals(animations.length, 1,
+                'Should find only the element');
+  assert_equals(animations[0].effect.target, target,
+                'Effect target should be the element');
+}, 'Test AnimationFilter{ subtree: false } with single element');
+
+test(function(t) {
+  addStyle(t, { '#target::after': 'animation: anim1 10s;',
+                '#target::before': 'animation: anim1 10s;' });
+  var target = addDiv(t, { 'id': 'target' });
+  target.style.animation = 'anim1 100s';
+
+  var animations = target.getAnimations({ subtree: true });
+  assert_equals(animations.length, 3,
+                'getAnimations({ subtree: true }) ' +
+                'should return animations on pseudo-elements');
+  assert_equals(animations[0].effect.target, target,
+                'The animation targeting the parent element ' +
+                'should be returned first');
+  assert_equals(animations[1].effect.target.type, '::before',
+                'The animation targeting the ::before pseudo-element ' +
+                'should be returned second');
+  assert_equals(animations[2].effect.target.type, '::after',
+                'The animation targeting the ::after pesudo-element ' +
+                'should be returned last');
+}, 'Test AnimationFilter{ subtree: true } with single element');
+
+test(function(t) {
+  addStyle(t, { '#parent::after': 'animation: anim1 10s;',
+                '#parent::before': 'animation: anim1 10s;',
+                '#child::after': 'animation: anim1 10s;',
+                '#child::before': 'animation: anim1 10s;' });
+  var parent = addDiv(t, { 'id': 'parent' });
+  parent.style.animation = 'anim1 100s';
+  var child = addDiv(t, { 'id': 'child' });
+  child.style.animation = 'anim1 100s';
+  parent.appendChild(child);
+
+  var animations = parent.getAnimations({ subtree: false });
+  assert_equals(animations.length, 1,
+                'Should find only the element even if it has a child');
+  assert_equals(animations[0].effect.target, parent,
+                'Effect target shuld be the element');
+}, 'Test AnimationFilter{ subtree: false } with element that has a child');
+
+test(function(t) {
+  addStyle(t, { '#parent::after': 'animation: anim1 10s;',
+                '#parent::before': 'animation: anim1 10s;',
+                '#child::after': 'animation: anim1 10s;',
+                '#child::before': 'animation: anim1 10s;' });
+  var parent = addDiv(t, { 'id': 'parent' });
+  var child = addDiv(t, { 'id': 'child' });
+  parent.style.animation = 'anim1 100s';
+  child.style.animation = 'anim1 100s';
+  parent.appendChild(child);
+
+  var animations = parent.getAnimations({ subtree: true });
+  assert_equals(animations.length, 6,
+                'Should find all elements, pesudo-elements that parent has');
+
+  assert_equals(animations[0].effect.target, parent,
+                'The animation targeting the parent element ' +
+                'should be returned first');
+  assert_equals(animations[1].effect.target.type, '::before',
+                'The animation targeting the ::before pseudo-element ' +
+                'should be returned second');
+  assert_equals(animations[1].effect.target.parentElement, parent,
+                'This ::before element should be child of parent element');
+  assert_equals(animations[2].effect.target.type, '::after',
+                'The animation targeting the ::after pesudo-element ' +
+                'should be returned third');
+  assert_equals(animations[2].effect.target.parentElement, parent,
+                'This ::after element should be child of parent element');
+
+  assert_equals(animations[3].effect.target, child,
+                'The animation targeting the child element ' +
+                'should be returned fourth');
+  assert_equals(animations[4].effect.target.type, '::before',
+                'The animation targeting the ::before pseudo-element ' +
+                'should be returned fifth');
+  assert_equals(animations[4].effect.target.parentElement, child,
+                'This ::before element should be child of child element');
+  assert_equals(animations[5].effect.target.type, '::after',
+                'The animation targeting the ::after pesudo-element ' +
+                'should be returned last');
+  assert_equals(animations[5].effect.target.parentElement, child,
+                'This ::after element should be child of child element');
+}, 'Test AnimationFilter{ subtree: true } with element that has a child');
+
+test(function(t) {
+  var parent = addDiv(t, { 'id': 'parent' });
+  var child1 = addDiv(t, { 'id': 'child1' });
+  var grandchild1 = addDiv(t, { 'id': 'grandchild1' });
+  var grandchild2 = addDiv(t, { 'id': 'grandchild2' });
+  var child2 = addDiv(t, { 'id': 'child2' });
+
+  parent.style.animation = 'anim1 100s';
+  child1.style.animation = 'anim1 100s';
+  grandchild1.style.animation = 'anim1 100s';
+  grandchild2.style.animation = 'anim1 100s';
+  child2.style.animation = 'anim1 100s';
+
+  parent.appendChild(child1);
+  child1.appendChild(grandchild1);
+  child1.appendChild(grandchild2);
+  parent.appendChild(child2);
+
+  var animations = parent.getAnimations({ subtree: true });
+  assert_equals(
+    parent.getAnimations({ subtree: true }).length, 5,
+                         'Should find all descendants of the element');
+
+  assert_equals(animations[0].effect.target, parent,
+                'The animation targeting the parent element ' +
+                'should be returned first');
+
+  assert_equals(animations[1].effect.target, child1,
+                'The animation targeting the child1 element ' +
+                'should be returned second');
+
+  assert_equals(animations[2].effect.target, grandchild1,
+                'The animation targeting the grandchild1 element ' +
+                'should be returned third');
+
+  assert_equals(animations[3].effect.target, grandchild2,
+                'The animation targeting the grandchild2 element ' +
+                'should be returned fourth');
+
+  assert_equals(animations[4].effect.target, child2,
+                'The animation targeting the child2 element ' +
+                'should be returned last');
+
+}, 'Test AnimationFilter{ subtree: true } with element that has many descendant');
+
 done();
 </script>
 </body>
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -1028,74 +1028,68 @@ Console::NoopMethod()
 {
   AssertIsOnOwningThread();
 
   // Nothing to do.
 }
 
 static
 nsresult
-StackFrameToStackEntry(nsIStackFrame* aStackFrame,
-                       ConsoleStackEntry& aStackEntry,
-                       uint32_t aLanguage)
+StackFrameToStackEntry(JSContext* aCx, nsIStackFrame* aStackFrame,
+                       ConsoleStackEntry& aStackEntry)
 {
   MOZ_ASSERT(aStackFrame);
 
-  nsresult rv = aStackFrame->GetFilename(aStackEntry.mFilename);
+  nsresult rv = aStackFrame->GetFilename(aCx, aStackEntry.mFilename);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t lineNumber;
-  rv = aStackFrame->GetLineNumber(&lineNumber);
+  rv = aStackFrame->GetLineNumber(aCx, &lineNumber);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aStackEntry.mLineNumber = lineNumber;
 
   int32_t columnNumber;
-  rv = aStackFrame->GetColumnNumber(&columnNumber);
+  rv = aStackFrame->GetColumnNumber(aCx, &columnNumber);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aStackEntry.mColumnNumber = columnNumber;
 
-  rv = aStackFrame->GetName(aStackEntry.mFunctionName);
+  rv = aStackFrame->GetName(aCx, aStackEntry.mFunctionName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsString cause;
-  rv = aStackFrame->GetAsyncCause(cause);
+  rv = aStackFrame->GetAsyncCause(aCx, cause);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!cause.IsEmpty()) {
     aStackEntry.mAsyncCause.Construct(cause);
   }
 
-  aStackEntry.mLanguage = aLanguage;
+  aStackEntry.mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
   return NS_OK;
 }
 
 static
 nsresult
-ReifyStack(nsIStackFrame* aStack, nsTArray<ConsoleStackEntry>& aRefiedStack)
+ReifyStack(JSContext* aCx, nsIStackFrame* aStack,
+           nsTArray<ConsoleStackEntry>& aRefiedStack)
 {
   nsCOMPtr<nsIStackFrame> stack(aStack);
 
   while (stack) {
-    uint32_t language;
-    nsresult rv = stack->GetLanguage(&language);
+    ConsoleStackEntry& data = *aRefiedStack.AppendElement();
+    nsresult rv = StackFrameToStackEntry(aCx, stack, data);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    if (language == nsIProgrammingLanguage::JAVASCRIPT) {
-      ConsoleStackEntry& data = *aRefiedStack.AppendElement();
-      rv = StackFrameToStackEntry(stack, data, language);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-
     nsCOMPtr<nsIStackFrame> caller;
-    rv = stack->GetCaller(getter_AddRefs(caller));
+    rv = stack->GetCaller(aCx, getter_AddRefs(caller));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!caller) {
-      rv = stack->GetAsyncCaller(getter_AddRefs(caller));
+      rv = stack->GetAsyncCaller(aCx, getter_AddRefs(caller));
       NS_ENSURE_SUCCESS(rv, rv);
     }
     stack.swap(caller);
   }
 
   return NS_OK;
 }
 
@@ -1124,56 +1118,32 @@ Console::Method(JSContext* aCx, MethodNa
 
     loadContext->GetUsePrivateBrowsing(&callData->mPrivate);
   }
 
   uint32_t maxDepth = ShouldIncludeStackTrace(aMethodName) ?
                       DEFAULT_MAX_STACKTRACE_DEPTH : 1;
   nsCOMPtr<nsIStackFrame> stack = CreateStack(aCx, maxDepth);
 
-  if (!stack) {
-    return;
-  }
-
-  // Walk up to the first JS stack frame and save it if we find it.
-  do {
-    uint32_t language;
-    nsresult rv = stack->GetLanguage(&language);
+  if (stack) {
+    callData->mTopStackFrame.emplace();
+    nsresult rv = StackFrameToStackEntry(aCx, stack,
+                                         *callData->mTopStackFrame);
     if (NS_FAILED(rv)) {
       return;
     }
-
-    if (language == nsIProgrammingLanguage::JAVASCRIPT) {
-      callData->mTopStackFrame.emplace();
-      nsresult rv = StackFrameToStackEntry(stack,
-                                           *callData->mTopStackFrame,
-                                           language);
-      if (NS_FAILED(rv)) {
-        return;
-      }
-
-      break;
-    }
-
-    nsCOMPtr<nsIStackFrame> caller;
-    rv = stack->GetCaller(getter_AddRefs(caller));
-    if (NS_FAILED(rv)) {
-      return;
-    }
-
-    stack.swap(caller);
-  } while (stack);
+  }
 
   if (NS_IsMainThread()) {
     callData->mStack = stack;
   } else {
     // nsIStackFrame is not threadsafe, so we need to snapshot it now,
     // before we post our runnable to the main thread.
     callData->mReifiedStack.emplace();
-    nsresult rv = ReifyStack(stack, *callData->mReifiedStack);
+    nsresult rv = ReifyStack(aCx, stack, *callData->mReifiedStack);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
   }
 
   DOMHighResTimeStamp monotonicTimer;
 
   // Monotonic timer for 'time' and 'timeEnd'
@@ -1296,17 +1266,17 @@ LazyStackGetter(JSContext* aCx, unsigned
   if (v.isUndefined()) {
     // Already reified.
     args.rval().set(js::GetFunctionNativeReserved(callee, SLOT_STACKOBJ));
     return true;
   }
 
   nsIStackFrame* stack = reinterpret_cast<nsIStackFrame*>(v.toPrivate());
   nsTArray<ConsoleStackEntry> reifiedStack;
-  nsresult rv = ReifyStack(stack, reifiedStack);
+  nsresult rv = ReifyStack(aCx, stack, reifiedStack);
   if (NS_FAILED(rv)) {
     Throw(aCx, rv);
     return false;
   }
 
   JS::Rooted<JS::Value> stackVal(aCx);
   if (!ToJSValue(aCx, reifiedStack, &stackVal)) {
     return false;
--- a/dom/base/DOMException.cpp
+++ b/dom/base/DOMException.cpp
@@ -213,47 +213,17 @@ Exception::Exception(const nsACString& a
   // shared prototype. So... We force one to be created via the factory
   // *once* and then go about our business.
   if (!sEverMadeOneFromFactory) {
     nsCOMPtr<nsIXPCException> e =
         do_CreateInstance(XPC_EXCEPTION_CONTRACTID);
     sEverMadeOneFromFactory = true;
   }
 
-  nsCOMPtr<nsIStackFrame> location;
-  if (aLocation) {
-    location = aLocation;
-  } else {
-    location = GetCurrentJSStack();
-    // it is legal for there to be no active JS stack, if C++ code
-    // is operating on a JS-implemented interface pointer without
-    // having been called in turn by JS.  This happens in the JS
-    // component loader, and will become more common as additional
-    // components are implemented in JS.
-  }
-  // We want to trim off any leading native 'dataless' frames
-  if (location) {
-    while (1) {
-      uint32_t language;
-      int32_t lineNumber;
-      if (NS_FAILED(location->GetLanguage(&language)) ||
-          language == nsIProgrammingLanguage::JAVASCRIPT ||
-          NS_FAILED(location->GetLineNumber(&lineNumber)) ||
-          lineNumber) {
-        break;
-      }
-      nsCOMPtr<nsIStackFrame> caller;
-      if (NS_FAILED(location->GetCaller(getter_AddRefs(caller))) || !caller) {
-        break;
-      }
-      location = caller;
-    }
-  }
-
-  Initialize(aMessage, aResult, aName, location, aData);
+  Initialize(aMessage, aResult, aName, aLocation, aData);
 }
 
 Exception::Exception()
   : mResult(NS_OK),
     mLineNumber(-1),
     mInitialized(false),
     mHoldingJSVal(false)
 {
@@ -333,37 +303,37 @@ Exception::GetName(nsACString& aName)
       aName.Assign(name);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-Exception::GetFilename(nsAString& aFilename)
+Exception::GetFilename(JSContext* aCx, nsAString& aFilename)
 {
   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
 
   if (mLocation) {
-    return mLocation->GetFilename(aFilename);
+    return mLocation->GetFilename(aCx, aFilename);
   }
 
   aFilename.Assign(mFilename);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-Exception::GetLineNumber(uint32_t *aLineNumber)
+Exception::GetLineNumber(JSContext* aCx, uint32_t *aLineNumber)
 {
   NS_ENSURE_ARG_POINTER(aLineNumber);
   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
 
   if (mLocation) {
     int32_t lineno;
-    nsresult rv = mLocation->GetLineNumber(&lineno);
+    nsresult rv = mLocation->GetLineNumber(aCx, &lineno);
     *aLineNumber = lineno;
     return rv;
   }
 
   *aLineNumber = mLineNumber;
   return NS_OK;
 }
 
@@ -395,30 +365,30 @@ Exception::GetData(nsISupports** aData)
   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
 
   nsCOMPtr<nsISupports> data = mData;
   data.forget(aData);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-Exception::ToString(nsACString& _retval)
+Exception::ToString(JSContext* aCx, nsACString& _retval)
 {
   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
 
   static const char defaultMsg[] = "<no message>";
   static const char defaultLocation[] = "<unknown>";
   static const char format[] =
 "[Exception... \"%s\"  nsresult: \"0x%x (%s)\"  location: \"%s\"  data: %s]";
 
   nsCString location;
 
   if (mLocation) {
     // we need to free this if it does not fail
-    nsresult rv = mLocation->ToString(location);
+    nsresult rv = mLocation->ToString(aCx, location);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (location.IsEmpty()) {
     location.Assign(defaultLocation);
   }
 
   const char* msg = mMessage.IsEmpty() ? nullptr : mMessage.get();
@@ -449,22 +419,21 @@ Exception::Initialize(const nsACString& 
 
   mMessage = aMessage;
   mName = aName;
   mResult = aResult;
 
   if (aLocation) {
     mLocation = aLocation;
   } else {
-    nsresult rv;
-    nsXPConnect* xpc = nsXPConnect::XPConnect();
-    rv = xpc->GetCurrentJSStack(getter_AddRefs(mLocation));
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
+    mLocation = GetCurrentJSStack();
+    // it is legal for there to be no active JS stack, if C++ code
+    // is operating on a JS-implemented interface pointer without
+    // having been called in turn by JS.  This happens in the JS
+    // component loader.
   }
 
   mData = aData;
 
   mInitialized = true;
   return NS_OK;
 }
 
@@ -500,21 +469,21 @@ Exception::GetName(nsString& retval)
   DebugOnly<nsresult> rv =
 #endif
   GetName(str);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   CopyUTF8toUTF16(str, retval);
 }
 
 uint32_t
-Exception::LineNumber() const
+Exception::LineNumber(JSContext* aCx) const
 {
   if (mLocation) {
     int32_t lineno;
-    if (NS_SUCCEEDED(mLocation->GetLineNumber(&lineno))) {
+    if (NS_SUCCEEDED(mLocation->GetLineNumber(aCx, &lineno))) {
       return lineno;
     }
     return 0;
   }
 
   return mLineNumber;
 }
 
@@ -534,31 +503,31 @@ Exception::GetLocation() const
 already_AddRefed<nsISupports>
 Exception::GetData() const
 {
   nsCOMPtr<nsISupports> data = mData;
   return data.forget();
 }
 
 void
-Exception::GetStack(nsAString& aStack, ErrorResult& aRv) const
+Exception::GetStack(JSContext* aCx, nsAString& aStack, ErrorResult& aRv) const
 {
   if (mLocation) {
-    aRv = mLocation->GetFormattedStack(aStack);
+    aRv = mLocation->GetFormattedStack(aCx, aStack);
   }
 }
 
 void
-Exception::Stringify(nsString& retval)
+Exception::Stringify(JSContext* aCx, nsString& retval)
 {
   nsCString str;
 #ifdef DEBUG
   DebugOnly<nsresult> rv =
 #endif
-  ToString(str);
+  ToString(aCx, str);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   CopyUTF8toUTF16(str, retval);
 }
 
 NS_IMPL_ADDREF_INHERITED(DOMException, Exception)
 NS_IMPL_RELEASE_INHERITED(DOMException, Exception)
 NS_INTERFACE_MAP_BEGIN(DOMException)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDOMException)
@@ -587,17 +556,17 @@ DOMException::GetCode(uint16_t* aCode)
       doc->WarnOnceAbout(nsIDocument::eDOMExceptionCode);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-DOMException::ToString(nsACString& aReturn)
+DOMException::ToString(JSContext* aCx, nsACString& aReturn)
 {
   aReturn.Truncate();
 
   static const char defaultMsg[] = "<no message>";
   static const char defaultLocation[] = "<unknown>";
   static const char defaultName[] = "<unknown>";
   static const char format[] =
     "[Exception... \"%s\"  code: \"%d\" nsresult: \"0x%x (%s)\"  location: \"%s\"]";
--- a/dom/base/DOMException.h
+++ b/dom/base/DOMException.h
@@ -73,27 +73,27 @@ public:
 
   uint32_t Result() const;
 
   void GetName(nsString& retval);
 
   // The XPCOM GetFilename does the right thing.  It might throw, but we want to
   // return an empty filename in that case anyway, instead of throwing.
 
-  uint32_t LineNumber() const;
+  uint32_t LineNumber(JSContext* aCx) const;
 
   uint32_t ColumnNumber() const;
 
   already_AddRefed<nsIStackFrame> GetLocation() const;
 
   already_AddRefed<nsISupports> GetData() const;
 
-  void GetStack(nsAString& aStack, ErrorResult& aRv) const;
+  void GetStack(JSContext* aCx, nsAString& aStack, ErrorResult& aRv) const;
 
-  void Stringify(nsString& retval);
+  void Stringify(JSContext* aCx, nsString& retval);
 
   // XPCOM factory ctor.
   Exception();
 
   Exception(const nsACString& aMessage,
             nsresult aResult,
             const nsACString& aName,
             nsIStackFrame *aLocation,
@@ -126,17 +126,17 @@ class DOMException : public Exception,
 public:
   DOMException(nsresult aRv, const nsACString& aMessage,
                const nsACString& aName, uint16_t aCode);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMDOMEXCEPTION
 
   // nsIException overrides
-  NS_IMETHOD ToString(nsACString& aReturn) override;
+  NS_IMETHOD ToString(JSContext* aCx, nsACString& aReturn) override;
 
   // nsWrapperCache overrides
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     override;
 
   static already_AddRefed<DOMException>
   Constructor(GlobalObject& /* unused */,
               const nsAString& aMessage,
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2078,17 +2078,17 @@ Element::DispatchClickEvent(nsPresContex
                             bool aFullDispatch,
                             const EventFlags* aExtraEventFlags,
                             nsEventStatus* aStatus)
 {
   NS_PRECONDITION(aTarget, "Must have target");
   NS_PRECONDITION(aSourceEvent, "Must have source event");
   NS_PRECONDITION(aStatus, "Null out param?");
 
-  WidgetMouseEvent event(aSourceEvent->mFlags.mIsTrusted, eMouseClick,
+  WidgetMouseEvent event(aSourceEvent->IsTrusted(), eMouseClick,
                          aSourceEvent->widget, WidgetMouseEvent::eReal);
   event.refPoint = aSourceEvent->refPoint;
   uint32_t clickCount = 1;
   float pressure = 0;
   uint16_t inputSource = 0;
   WidgetMouseEvent* sourceMouseEvent = aSourceEvent->AsMouseEvent();
   if (sourceMouseEvent) {
     clickCount = sourceMouseEvent->clickCount;
@@ -2873,17 +2873,17 @@ Element::Describe(nsAString& aOutDescrip
   }
 }
 
 bool
 Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
                                               nsIURI** aURI) const
 {
   if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
-      (!aVisitor.mEvent->mFlags.mIsTrusted &&
+      (!aVisitor.mEvent->IsTrusted() &&
        (aVisitor.mEvent->mMessage != eMouseClick) &&
        (aVisitor.mEvent->mMessage != eKeyPress) &&
        (aVisitor.mEvent->mMessage != eLegacyDOMActivate)) ||
       !aVisitor.mPresContext ||
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented) {
     return false;
   }
 
@@ -3374,17 +3374,18 @@ Element::Animate(const Nullable<ElementO
   if (aError.Failed()) {
     return nullptr;
   }
 
   return animation.forget();
 }
 
 void
-Element::GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations)
+Element::GetAnimations(const AnimationFilter& filter,
+                       nsTArray<RefPtr<Animation>>& aAnimations)
 {
   nsIDocument* doc = GetComposedDoc();
   if (doc) {
     doc->FlushPendingNotifications(Flush_Style);
   }
 
   Element* elem = this;
   CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo;
@@ -3398,17 +3399,36 @@ Element::GetAnimations(nsTArray<RefPtr<A
     elem = GetParentElement();
     pseudoType = CSSPseudoElementType::after;
   }
 
   if (!elem) {
     return;
   }
 
-  GetAnimationsUnsorted(elem, pseudoType, aAnimations);
+  if (!filter.mSubtree ||
+      pseudoType == CSSPseudoElementType::before ||
+      pseudoType == CSSPseudoElementType::after) {
+    GetAnimationsUnsorted(elem, pseudoType, aAnimations);
+  } else {
+    for (nsIContent* node = this;
+         node;
+         node = node->GetNextNode(this)) {
+      if (!node->IsElement()) {
+        continue;
+      }
+      Element* element = node->AsElement();
+      Element::GetAnimationsUnsorted(element, CSSPseudoElementType::NotPseudo,
+                                     aAnimations);
+      Element::GetAnimationsUnsorted(element, CSSPseudoElementType::before,
+                                     aAnimations);
+      Element::GetAnimationsUnsorted(element, CSSPseudoElementType::after,
+                                     aAnimations);
+    }
+  }
   aAnimations.Sort(AnimationPtrComparator<RefPtr<Animation>>());
 }
 
 /* static */ void
 Element::GetAnimationsUnsorted(Element* aElement,
                                CSSPseudoElementType aPseudoType,
                                nsTArray<RefPtr<Animation>>& aAnimations)
 {
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -50,16 +50,17 @@ struct nsRect;
 class nsFocusManager;
 class nsGlobalWindow;
 class nsICSSDeclaration;
 class nsISMILAttr;
 class nsDocument;
 
 namespace mozilla {
 namespace dom {
+  struct AnimationFilter;
   struct ScrollIntoViewOptions;
   struct ScrollToOptions;
   class ElementOrCSSPseudoElement;
   class UnrestrictedDoubleOrKeyframeAnimationOptions;
 } // namespace dom
 } // namespace mozilla
 
 
@@ -176,17 +177,17 @@ public:
    * situation it is the caller's responsibility to dispatch them.
    *
    * In general, aNotify should only be false if we're guaranteed that
    * the element can't have a frame no matter what its style is
    * (e.g. if we're in the middle of adding it to the document or
    * removing it from the document).
    */
   void UpdateState(bool aNotify);
-  
+
   /**
    * Method to update mState with link state information.  This does not notify.
    */
   void UpdateLinkState(EventStates aState);
 
   /**
    * Returns true if this element is either a full-screen element or an
    * ancestor of the full-screen element.
@@ -336,17 +337,17 @@ public:
           AddStatesSilently(NS_EVENT_STATE_LTR);
         }
         break;
 
       default:
         break;
     }
 
-    /* 
+    /*
      * Only call UpdateState if we need to notify, because we call
      * SetDirectionality for every element, and UpdateState is very very slow
      * for some elements.
      */
     if (aNotify) {
       UpdateState(true);
     }
   }
@@ -839,17 +840,18 @@ public:
   static already_AddRefed<Animation>
   Animate(const Nullable<ElementOrCSSPseudoElement>& aTarget,
           JSContext* aContext,
           JS::Handle<JSObject*> aFrames,
           const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
           ErrorResult& aError);
 
   // Note: GetAnimations will flush style while GetAnimationsUnsorted won't.
-  void GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations);
+  void GetAnimations(const AnimationFilter& filter,
+                     nsTArray<RefPtr<Animation>>& aAnimations);
   static void GetAnimationsUnsorted(Element* aElement,
                                     CSSPseudoElementType aPseudoType,
                                     nsTArray<RefPtr<Animation>>& aAnimations);
 
   NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
   virtual void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
   void GetOuterHTML(nsAString& aOuterHTML);
   void SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError);
@@ -973,17 +975,17 @@ public:
    * GetEnumValue() returns one of the above constants.
    */
   static void ParseCORSValue(const nsAString& aValue, nsAttrValue& aResult);
 
   /**
    * Return the CORS mode for a given string
    */
   static CORSMode StringToCORSMode(const nsAString& aValue);
-  
+
   /**
    * Return the CORS mode for a given nsAttrValue (which may be null,
    * but if not should have been parsed via ParseCORSValue).
    */
   static CORSMode AttrValueToCORSMode(const nsAttrValue* aValue);
 
   // These are just used to implement nsIDOMElement using
   // NS_FORWARD_NSIDOMELEMENT_TO_GENERIC and for quickstubs.
--- a/dom/base/TextInputProcessor.cpp
+++ b/dom/base/TextInputProcessor.cpp
@@ -707,17 +707,18 @@ TextInputProcessor::OnRemovedFrom(TextEv
 
 NS_IMETHODIMP_(void)
 TextInputProcessor::WillDispatchKeyboardEvent(
                       TextEventDispatcher* aTextEventDispatcher,
                       WidgetKeyboardEvent& aKeyboardEvent,
                       uint32_t aIndexOfKeypress,
                       void* aData)
 {
-  // TextInputProcessor doesn't set alternative char code.
+  // TextInputProcessor doesn't set alternative char code nor modify charCode
+  // even when Ctrl key is pressed.
 }
 
 nsresult
 TextInputProcessor::PrepareKeyboardEventToDispatch(
                       WidgetKeyboardEvent& aKeyboardEvent,
                       uint32_t aKeyFlags)
 {
   if (NS_WARN_IF(aKeyboardEvent.mCodeNameIndex == CODE_NAME_INDEX_USE_STRING)) {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -4900,198 +4900,16 @@ nsContentUtils::GetLocalizedEllipsis()
                           uint32_t(ArrayLength(sBuf) - 1));
     CopyUnicodeTo(tmp, 0, sBuf, len);
     if (!sBuf[0])
       sBuf[0] = char16_t(0x2026);
   }
   return nsDependentString(sBuf);
 }
 
-static bool
-HasASCIIDigit(const nsTArray<nsShortcutCandidate>& aCandidates)
-{
-  for (uint32_t i = 0; i < aCandidates.Length(); ++i) {
-    uint32_t ch = aCandidates[i].mCharCode;
-    if (ch >= '0' && ch <= '9')
-      return true;
-  }
-  return false;
-}
-
-static bool
-CharsCaseInsensitiveEqual(uint32_t aChar1, uint32_t aChar2)
-{
-  return aChar1 == aChar2 ||
-         (IS_IN_BMP(aChar1) && IS_IN_BMP(aChar2) &&
-          ToLowerCase(char16_t(aChar1)) == ToLowerCase(char16_t(aChar2)));
-}
-
-static bool
-IsCaseChangeableChar(uint32_t aChar)
-{
-  return IS_IN_BMP(aChar) &&
-         ToLowerCase(char16_t(aChar)) != ToUpperCase(char16_t(aChar));
-}
-
-/* static */
-void
-nsContentUtils::GetAccelKeyCandidates(nsIDOMKeyEvent* aDOMKeyEvent,
-                  nsTArray<nsShortcutCandidate>& aCandidates)
-{
-  NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
-
-  nsAutoString eventType;
-  aDOMKeyEvent->AsEvent()->GetType(eventType);
-  // Don't process if aDOMKeyEvent is not a keypress event.
-  if (!eventType.EqualsLiteral("keypress"))
-    return;
-
-  WidgetKeyboardEvent* nativeKeyEvent =
-    aDOMKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
-  if (nativeKeyEvent) {
-    NS_ASSERTION(nativeKeyEvent->mClass == eKeyboardEventClass,
-                 "wrong type of native event");
-    // nsShortcutCandidate::mCharCode is a candidate charCode.
-    // nsShoftcutCandidate::mIgnoreShift means the mCharCode should be tried to
-    // execute a command with/without shift key state. If this is TRUE, the
-    // shifted key state should be ignored. Otherwise, don't ignore the state.
-    // the priority of the charCodes are (shift key is not pressed):
-    //   0: charCode/false,
-    //   1: unshiftedCharCodes[0]/false, 2: unshiftedCharCodes[1]/false...
-    // the priority of the charCodes are (shift key is pressed):
-    //   0: charCode/false,
-    //   1: shiftedCharCodes[0]/false, 2: shiftedCharCodes[0]/true,
-    //   3: shiftedCharCodes[1]/false, 4: shiftedCharCodes[1]/true...
-    if (nativeKeyEvent->charCode) {
-      nsShortcutCandidate key(nativeKeyEvent->charCode, false);
-      aCandidates.AppendElement(key);
-    }
-
-    uint32_t len = nativeKeyEvent->alternativeCharCodes.Length();
-    if (!nativeKeyEvent->IsShift()) {
-      for (uint32_t i = 0; i < len; ++i) {
-        uint32_t ch =
-          nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
-        if (!ch || ch == nativeKeyEvent->charCode)
-          continue;
-
-        nsShortcutCandidate key(ch, false);
-        aCandidates.AppendElement(key);
-      }
-      // If unshiftedCharCodes doesn't have numeric but shiftedCharCode has it,
-      // this keyboard layout is AZERTY or similar layout, probably.
-      // In this case, Accel+[0-9] should be accessible without shift key.
-      // However, the priority should be lowest.
-      if (!HasASCIIDigit(aCandidates)) {
-        for (uint32_t i = 0; i < len; ++i) {
-          uint32_t ch =
-            nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
-          if (ch >= '0' && ch <= '9') {
-            nsShortcutCandidate key(ch, false);
-            aCandidates.AppendElement(key);
-            break;
-          }
-        }
-      }
-    } else {
-      for (uint32_t i = 0; i < len; ++i) {
-        uint32_t ch = nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
-        if (!ch)
-          continue;
-
-        if (ch != nativeKeyEvent->charCode) {
-          nsShortcutCandidate key(ch, false);
-          aCandidates.AppendElement(key);
-        }
-
-        // If the char is an alphabet, the shift key state should not be
-        // ignored. E.g., Ctrl+Shift+C should not execute Ctrl+C.
-
-        // And checking the charCode is same as unshiftedCharCode too.
-        // E.g., for Ctrl+Shift+(Plus of Numpad) should not run Ctrl+Plus.
-        uint32_t unshiftCh =
-          nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
-        if (CharsCaseInsensitiveEqual(ch, unshiftCh))
-          continue;
-
-        // On the Hebrew keyboard layout on Windows, the unshifted char is a
-        // localized character but the shifted char is a Latin alphabet,
-        // then, we should not execute without the shift state. See bug 433192.
-        if (IsCaseChangeableChar(ch))
-          continue;
-
-        // Setting the alternative charCode candidates for retry without shift
-        // key state only when the shift key is pressed.
-        nsShortcutCandidate key(ch, true);
-        aCandidates.AppendElement(key);
-      }
-    }
-
-    // Special case for "Space" key.  With some keyboard layouts, "Space" with
-    // or without Shift key causes non-ASCII space.  For such keyboard layouts,
-    // we should guarantee that the key press works as an ASCII white space key
-    // press.
-    if (nativeKeyEvent->mCodeNameIndex == CODE_NAME_INDEX_Space &&
-        nativeKeyEvent->charCode != static_cast<uint32_t>(' ')) {
-      nsShortcutCandidate spaceKey(static_cast<uint32_t>(' '), false);
-      aCandidates.AppendElement(spaceKey);
-    }
-  } else {
-    uint32_t charCode;
-    aDOMKeyEvent->GetCharCode(&charCode);
-    if (charCode) {
-      nsShortcutCandidate key(charCode, false);
-      aCandidates.AppendElement(key);
-    }
-  }
-}
-
-/* static */
-void
-nsContentUtils::GetAccessKeyCandidates(WidgetKeyboardEvent* aNativeKeyEvent,
-                                       nsTArray<uint32_t>& aCandidates)
-{
-  NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
-
-  // return the lower cased charCode candidates for access keys.
-  // the priority of the charCodes are:
-  //   0: charCode, 1: unshiftedCharCodes[0], 2: shiftedCharCodes[0]
-  //   3: unshiftedCharCodes[1], 4: shiftedCharCodes[1],...
-  if (aNativeKeyEvent->charCode) {
-    uint32_t ch = aNativeKeyEvent->charCode;
-    if (IS_IN_BMP(ch))
-      ch = ToLowerCase(char16_t(ch));
-    aCandidates.AppendElement(ch);
-  }
-  for (uint32_t i = 0;
-       i < aNativeKeyEvent->alternativeCharCodes.Length(); ++i) {
-    uint32_t ch[2] =
-      { aNativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode,
-        aNativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode };
-    for (uint32_t j = 0; j < 2; ++j) {
-      if (!ch[j])
-        continue;
-      if (IS_IN_BMP(ch[j]))
-        ch[j] = ToLowerCase(char16_t(ch[j]));
-      // Don't append the charCode that was already appended.
-      if (aCandidates.IndexOf(ch[j]) == aCandidates.NoIndex)
-        aCandidates.AppendElement(ch[j]);
-    }
-  }
-  // Special case for "Space" key.  With some keyboard layouts, "Space" with
-  // or without Shift key causes non-ASCII space.  For such keyboard layouts,
-  // we should guarantee that the key press works as an ASCII white space key
-  // press.
-  if (aNativeKeyEvent->mCodeNameIndex == CODE_NAME_INDEX_Space &&
-      aNativeKeyEvent->charCode != static_cast<uint32_t>(' ')) {
-    aCandidates.AppendElement(static_cast<uint32_t>(' '));
-  }
-  return;
-}
-
 /* static */
 void
 nsContentUtils::AddScriptBlocker()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!sScriptBlockerCount) {
     MOZ_ASSERT(sRunnersCountAtFirstBlocker == 0,
                "Should not already have a count");
@@ -5404,18 +5222,19 @@ nsContentUtils::GetDragSession()
     dragService->GetCurrentSession(getter_AddRefs(dragSession));
   return dragSession.forget();
 }
 
 /* static */
 nsresult
 nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent)
 {
-  if (aDragEvent->dataTransfer || !aDragEvent->mFlags.mIsTrusted)
+  if (aDragEvent->dataTransfer || !aDragEvent->IsTrusted()) {
     return NS_OK;
+  }
 
   // For draggesture and dragstart events, the data transfer object is
   // created before the event fires, so it should already be set. For other
   // drag events, get the object from the drag session.
   NS_ASSERTION(aDragEvent->mMessage != eLegacyDragGesture &&
                aDragEvent->mMessage != eDragStart,
                "draggesture event created without a dataTransfer");
 
@@ -6679,19 +6498,19 @@ nsContentUtils::IsPatternMatching(nsAStr
   // regexp evaluation, not actual script execution.
   JSAutoCompartment ac(cx, xpc::UnprivilegedJunkScope());
 
   // The pattern has to match the entire value.
   aPattern.Insert(NS_LITERAL_STRING("^(?:"), 0);
   aPattern.AppendLiteral(")$");
 
   JS::Rooted<JSObject*> re(cx,
-    JS_NewUCRegExpObjectNoStatics(cx,
-                                  static_cast<char16_t*>(aPattern.BeginWriting()),
-                                  aPattern.Length(), JSREG_UNICODE));
+    JS_NewUCRegExpObject(cx,
+                         static_cast<char16_t*>(aPattern.BeginWriting()),
+                         aPattern.Length(), JSREG_UNICODE));
   if (!re) {
     // Remove extra patterns added above to report with the original pattern.
     aPattern.Cut(0, 4);
     aPattern.Cut(aPattern.Length() - 2, 2);
     ReportPatternCompileFailure(aPattern, aDocument, cx);
     return true;
   }
 
@@ -7885,17 +7704,17 @@ nsContentUtils::SendKeyEvent(nsIWidget* 
 
   event.refPoint.x = event.refPoint.y = 0;
   event.time = PR_IntervalNow();
   if (!(aAdditionalFlags & nsIDOMWindowUtils::KEY_FLAG_NOT_SYNTHESIZED_FOR_TESTS)) {
     event.mFlags.mIsSynthesizedForTests = true;
   }
 
   if (aAdditionalFlags & nsIDOMWindowUtils::KEY_FLAG_PREVENT_DEFAULT) {
-    event.mFlags.mDefaultPrevented = true;
+    event.PreventDefaultBeforeDispatch();
   }
 
   nsEventStatus status;
   nsresult rv = aWidget->DispatchEvent(&event, status);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aDefaultActionTaken = (status != nsEventStatus_eConsumeNoDefault);
 
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -166,25 +166,16 @@ struct EventNameMapping
   // This holds pointers to nsGkAtoms members, and is therefore safe as a
   // non-owning reference.
   nsIAtom* MOZ_NON_OWNING_REF mAtom;
   int32_t  mType;
   mozilla::EventMessage mMessage;
   mozilla::EventClassID mEventClassID;
 };
 
-struct nsShortcutCandidate {
-  nsShortcutCandidate(uint32_t aCharCode, bool aIgnoreShift) :
-    mCharCode(aCharCode), mIgnoreShift(aIgnoreShift)
-  {
-  }
-  uint32_t mCharCode;
-  bool     mIgnoreShift;
-};
-
 typedef void (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
                                            void* aArg);
 
 class nsContentUtils
 {
   friend class nsAutoScriptBlockerSuppressNodeRemoved;
   typedef mozilla::dom::Element Element;
   typedef mozilla::TimeDuration TimeDuration;
@@ -1507,37 +1498,16 @@ public:
   static nsIWidget* GetTopLevelWidget(nsIWidget* aWidget);
 
   /**
    * Return the localized ellipsis for UI.
    */
   static const nsDependentString GetLocalizedEllipsis();
 
   /**
-   * Get the candidates for accelkeys for aDOMKeyEvent.
-   *
-   * @param aDOMKeyEvent [in] the key event for accelkey handling.
-   * @param aCandidates [out] the candidate shortcut key combination list.
-   *                          the first item is most preferred.
-   */
-  static void GetAccelKeyCandidates(nsIDOMKeyEvent* aDOMKeyEvent,
-                                    nsTArray<nsShortcutCandidate>& aCandidates);
-
-  /**
-   * Get the candidates for accesskeys for aNativeKeyEvent.
-   *
-   * @param aNativeKeyEvent [in] the key event for accesskey handling.
-   * @param aCandidates [out] the candidate access key list.
-   *                          the first item is most preferred.
-   */
-  static void GetAccessKeyCandidates(
-                mozilla::WidgetKeyboardEvent* aNativeKeyEvent,
-                nsTArray<uint32_t>& aCandidates);
-
-  /**
    * Hide any XUL popups associated with aDocument, including any documents
    * displayed in child frames. Does nothing if aDocument is null.
    */
   static void HidePopupsInDocument(nsIDocument* aDocument);
 
   /**
    * Retrieve the current drag session, or null if no drag is currently occuring
    */
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsDOMWindowUtils.h"
 
-#include "mozilla/layers/CompositorChild.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "nsPresContext.h"
 #include "nsDOMClassInfoID.h"
 #include "nsError.h"
 #include "nsIDOMEvent.h"
 #include "nsQueryContentEventResult.h"
 #include "nsGlobalWindow.h"
 #include "nsIDocument.h"
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -196,16 +196,17 @@
 
 #include "mozilla/Preferences.h"
 
 #include "imgILoader.h"
 #include "imgRequestProxy.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsSandboxFlags.h"
 #include "nsIAppsService.h"
+#include "mozilla/dom/AnimatableBinding.h"
 #include "mozilla/dom/AnonymousContent.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/DocumentTimeline.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/HTMLBodyElement.h"
 #include "mozilla/dom/HTMLInputElement.h"
 #include "mozilla/dom/MediaQueryList.h"
@@ -1454,17 +1455,17 @@ nsIDocument::nsIDocument()
     mPostedFlushUserFontSet(false),
     mPartID(0),
     mDidFireDOMContentLoaded(true),
     mHasScrollLinkedEffect(false),
     mUserHasInteracted(false)
 {
   SetInDocument();
 
-  PR_INIT_CLIST(&mDOMMediaQueryLists);  
+  PR_INIT_CLIST(&mDOMMediaQueryLists);
 }
 
 // NOTE! nsDocument::operator new() zeroes out all members, so don't
 // bother initializing members to 0.
 
 nsDocument::nsDocument(const char* aContentType)
   : nsIDocument()
   , mAnimatingImages(true)
@@ -3195,36 +3196,23 @@ nsDocument::Timeline()
   }
 
   return mDocumentTimeline;
 }
 
 void
 nsDocument::GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations)
 {
-  FlushPendingNotifications(Flush_Style);
-
-  for (nsIContent* node = nsINode::GetFirstChild();
-       node;
-       node = node->GetNextNode(this)) {
-    if (!node->IsElement()) {
-      continue;
-    }
-
-    Element* element = node->AsElement();
-    Element::GetAnimationsUnsorted(element, CSSPseudoElementType::NotPseudo,
-                                   aAnimations);
-    Element::GetAnimationsUnsorted(element, CSSPseudoElementType::before,
-                                   aAnimations);
-    Element::GetAnimationsUnsorted(element, CSSPseudoElementType::after,
-                                   aAnimations);
-  }
-
-  // Sort animations by priority
-  aAnimations.Sort(AnimationPtrComparator<RefPtr<Animation>>());
+  Element* root = GetRootElement();
+  if (!root) {
+    return;
+  }
+  AnimationFilter filter;
+  filter.mSubtree = true;
+  root->GetAnimations(filter, aAnimations);
 }
 
 /* Return true if the document is in the focused top-level window, and is an
  * ancestor of the focused DOMWindow. */
 NS_IMETHODIMP
 nsDocument::HasFocus(bool* aResult)
 {
   ErrorResult rv;
@@ -13191,17 +13179,17 @@ nsDocument::ReportUseCounters()
     Telemetry::Accumulate(Telemetry::CONTENT_DOCUMENTS_DESTROYED, 1);
     if (IsTopLevelContentDocument()) {
       Telemetry::Accumulate(Telemetry::TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED, 1);
     }
 
     for (int32_t c = 0;
          c < eUseCounter_Count; ++c) {
       UseCounter uc = static_cast<UseCounter>(c);
-      
+
       Telemetry::ID id =
         static_cast<Telemetry::ID>(Telemetry::HistogramFirstUseCounter + uc * 2);
       bool value = GetUseCounter(uc);
 
       if (value) {
         if (sDebugUseCounters) {
           const char* name = Telemetry::GetHistogramName(id);
           if (name) {
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -87,17 +87,17 @@
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "nsIAppsService.h"
 #include "GeckoProfiler.h"
 
 #include "jsapi.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "nsSandboxFlags.h"
-#include "mozilla/layers/CompositorChild.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
 
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/WebBrowserPersistLocalDocument.h"
 
 #include "nsPrincipal.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
@@ -1732,17 +1732,17 @@ nsFrameLoader::ShouldUseRemoteProcess()
   if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
       Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
     return false;
   }
 
   // Don't try to launch nested children if we don't have OMTC.
   // They won't render!
   if (XRE_IsContentProcess() &&
-      !CompositorChild::ChildProcessHasCompositor()) {
+      !CompositorBridgeChild::ChildProcessHasCompositor()) {
     return false;
   }
 
   if (XRE_IsContentProcess() &&
       !(PR_GetEnv("MOZ_NESTED_OOP_TABS") ||
         Preferences::GetBool("dom.ipc.tabs.nested.enabled", false))) {
     return false;
   }
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -1041,16 +1041,17 @@ GK_ATOM(refresh, "refresh")
 GK_ATOM(rel, "rel")
 GK_ATOM(onreloadpage, "onreloadpage")
 GK_ATOM(rem, "rem")
 GK_ATOM(removeelement, "removeelement")
 GK_ATOM(renderingobserverlist, "renderingobserverlist")
 GK_ATOM(repeat, "repeat")
 GK_ATOM(replace, "replace")
 GK_ATOM(required, "required")
+GK_ATOM(reserved, "reserved")
 GK_ATOM(reset, "reset")
 GK_ATOM(resizeafter, "resizeafter")
 GK_ATOM(resizebefore, "resizebefore")
 GK_ATOM(resizer, "resizer")
 GK_ATOM(resolution, "resolution")
 GK_ATOM(resource, "resource")
 GK_ATOM(resources, "resources")
 GK_ATOM(result, "result")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3114,44 +3114,44 @@ nsGlobalWindow::PreHandleEvent(EventChai
       int16_t myCoord[2];
 
       myCoord[0] = aVisitor.mEvent->refPoint.x;
       myCoord[1] = aVisitor.mEvent->refPoint.y;
       gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
       gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
                                       sizeof(uint32_t));
     }
-  } else if (msg == eResize && aVisitor.mEvent->mFlags.mIsTrusted) {
+  } else if (msg == eResize && aVisitor.mEvent->IsTrusted()) {
     // QIing to window so that we can keep the old behavior also in case
     // a child window is handling resize.
     nsCOMPtr<nsPIDOMWindowInner> window =
       do_QueryInterface(aVisitor.mEvent->originalTarget);
     if (window) {
       mIsHandlingResizeEvent = true;
     }
-  } else if (msg == eMouseDown && aVisitor.mEvent->mFlags.mIsTrusted) {
+  } else if (msg == eMouseDown && aVisitor.mEvent->IsTrusted()) {
     gMouseDown = true;
   } else if ((msg == eMouseUp || msg == eDragEnd) &&
-             aVisitor.mEvent->mFlags.mIsTrusted) {
+             aVisitor.mEvent->IsTrusted()) {
     gMouseDown = false;
     if (gDragServiceDisabled) {
       nsCOMPtr<nsIDragService> ds =
         do_GetService("@mozilla.org/widget/dragservice;1");
       if (ds) {
         gDragServiceDisabled = false;
         ds->Unsuppress();
       }
     }
   }
 
   aVisitor.mParentTarget = GetParentTarget();
 
   // Handle 'active' event.
   if (!mIdleObservers.IsEmpty() &&
-      aVisitor.mEvent->mFlags.mIsTrusted &&
+      aVisitor.mEvent->IsTrusted() &&
       (aVisitor.mEvent->HasMouseEventMessage() ||
        aVisitor.mEvent->HasDragEventMessage())) {
     mAddActiveEventFuzzTime = false;
   }
 
   return NS_OK;
 }
 
@@ -3319,38 +3319,38 @@ nsGlobalWindow::PostHandleEvent(EventCha
    function under some circumstances (events that destroy the window)
    without this addref. */
   nsCOMPtr<nsIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
   nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
 
   if (aVisitor.mEvent->mMessage == eResize) {
     mIsHandlingResizeEvent = false;
   } else if (aVisitor.mEvent->mMessage == eUnload &&
-             aVisitor.mEvent->mFlags.mIsTrusted) {
+             aVisitor.mEvent->IsTrusted()) {
     // Execute bindingdetached handlers before we tear ourselves
     // down.
     if (mDoc) {
       mDoc->BindingManager()->ExecuteDetachedHandlers();
     }
     mIsDocumentLoaded = false;
   } else if (aVisitor.mEvent->mMessage == eLoad &&
-             aVisitor.mEvent->mFlags.mIsTrusted) {
+             aVisitor.mEvent->IsTrusted()) {
     // This is page load event since load events don't propagate to |window|.
     // @see nsDocument::PreHandleEvent.
     mIsDocumentLoaded = true;
 
     nsCOMPtr<Element> element = GetOuterWindow()->GetFrameElementInternal();
     nsIDocShell* docShell = GetDocShell();
     if (element && GetParentInternal() &&
         docShell && docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
       // If we're not in chrome, or at a chrome boundary, fire the
       // onload event for the frame element.
 
       nsEventStatus status = nsEventStatus_eIgnore;
-      WidgetEvent event(aVisitor.mEvent->mFlags.mIsTrusted, eLoad);
+      WidgetEvent event(aVisitor.mEvent->IsTrusted(), eLoad);
       event.mFlags.mBubbles = false;
 
       // Most of the time we could get a pres context to pass in here,
       // but not always (i.e. if this window is not shown there won't
       // be a pres context available). Since we're not firing a GUI
       // event we don't need a pres context anyway so we just pass
       // null as the pres context all the time here.
       EventDispatcher::Dispatch(element, nullptr, &event, nullptr, &status);
@@ -11532,17 +11532,17 @@ nsGlobalWindow::OpenInternal(const nsASt
     nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
     if (!aCalledNoScript) {
       // We asserted at the top of this function that aNavigate is true for
       // !aCalledNoScript.
       rv = pwwatch->OpenWindow2(AsOuter(), url.get(), name_ptr,
                                 options_ptr, /* aCalledFromScript = */ true,
                                 aDialog, aNavigate, nullptr, argv,
-                                getter_AddRefs(domReturn));
+                                1.0f, 0, getter_AddRefs(domReturn));
     } else {
       // Force a system caller here so that the window watcher won't screw us
       // up.  We do NOT want this case looking at the JS context on the stack
       // when searching.  Compare comments on
       // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
 
       // Note: Because nsWindowWatcher is so broken, it's actually important
       // that we don't force a system caller here, because that screws it up
@@ -11552,17 +11552,17 @@ nsGlobalWindow::OpenInternal(const nsASt
       if (!aContentModal) {
         nojsapi.emplace();
       }
 
 
       rv = pwwatch->OpenWindow2(AsOuter(), url.get(), name_ptr,
                                 options_ptr, /* aCalledFromScript = */ false,
                                 aDialog, aNavigate, nullptr, aExtraArgument,
-                                getter_AddRefs(domReturn));
+                                1.0f, 0, getter_AddRefs(domReturn));
 
     }
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // success!
 
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsHostObjectProtocolHandler.h"
 
 #include "DOMMediaStream.h"
+#include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/MediaSource.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/ModuleUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsClassHashtable.h"
 #include "nsError.h"
 #include "nsHostObjectURI.h"
@@ -196,35 +197,36 @@ class BlobURLsReporter final : public ns
     nsCString& stack = aInfo->mStack;
     MOZ_ASSERT(stack.IsEmpty());
     const uint32_t maxFrames = Preferences::GetUint("memory.blob_report.stack_frames");
 
     if (maxFrames == 0) {
       return;
     }
 
-    nsresult rv;
-    nsIXPConnect* xpc = nsContentUtils::XPConnect();
-    nsCOMPtr<nsIStackFrame> frame;
-    rv = xpc->GetCurrentJSStack(getter_AddRefs(frame));
-    NS_ENSURE_SUCCESS_VOID(rv);
+    nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack(maxFrames);
 
     nsAutoCString origin;
     nsCOMPtr<nsIURI> principalURI;
     if (NS_SUCCEEDED(aInfo->mPrincipal->GetURI(getter_AddRefs(principalURI)))
         && principalURI) {
       principalURI->GetPrePath(origin);
     }
 
-    for (uint32_t i = 0; i < maxFrames && frame; ++i) {
+    // If we got a frame, we better have a current JSContext.  This is cheating
+    // a bit; ideally we'd have our caller pass in a JSContext, or have
+    // GetCurrentJSStack() hand out the JSContext it found.
+    JSContext* cx = frame ? nsContentUtils::GetCurrentJSContext() : nullptr;
+
+    for (uint32_t i = 0; frame; ++i) {
       nsString fileNameUTF16;
       int32_t lineNumber = 0;
 
-      frame->GetFilename(fileNameUTF16);
-      frame->GetLineNumber(&lineNumber);
+      frame->GetFilename(cx, fileNameUTF16);
+      frame->GetLineNumber(cx, &lineNumber);
 
       if (!fileNameUTF16.IsEmpty()) {
         NS_ConvertUTF16toUTF8 fileName(fileNameUTF16);
         stack += "js(";
         if (!origin.IsEmpty()) {
           // Make the file name root-relative for conciseness if possible.
           const char* originData;
           uint32_t originLen;
@@ -241,18 +243,20 @@ class BlobURLsReporter final : public ns
         stack += fileName;
         if (lineNumber > 0) {
           stack += ", line=";
           stack.AppendInt(lineNumber);
         }
         stack += ")/";
       }
 
-      rv = frame->GetCaller(getter_AddRefs(frame));
+      nsCOMPtr<nsIStackFrame> caller;
+      nsresult rv = frame->GetCaller(cx, getter_AddRefs(caller));
       NS_ENSURE_SUCCESS_VOID(rv);
+      caller.swap(frame);
     }
   }
 
  private:
   ~BlobURLsReporter() {}
 
   static void BuildPath(nsAutoCString& path,
                         nsCStringHashKey::KeyType aKey,
--- a/dom/base/test/chrome/chrome.ini
+++ b/dom/base/test/chrome/chrome.ini
@@ -41,21 +41,18 @@ support-files = ../file_bug357450.js
 [test_bug430050.xul]
 [test_bug467123.xul]
 [test_bug549682.xul]
 [test_bug571390.xul]
 [test_bug1098074_throw_from_ReceiveMessage.xul]
 skip-if = buildapp == 'mulet'
 [test_bug616841.xul]
 [test_bug635835.xul]
-[test_bug650776.html]
-[test_bug650784.html]
 [test_bug682305.html]
 [test_bug683852.xul]
-[test_bug750096.html]
 [test_bug752226-3.xul]
 [test_bug752226-4.xul]
 [test_bug765993.html]
 [test_bug780199.xul]
 [test_bug780529.xul]
 [test_bug800386.xul]
 [test_bug814638.xul]
 [test_bug816340.xul]
deleted file mode 100644
--- a/dom/base/test/chrome/test_bug650776.html
+++ /dev/null
@@ -1,110 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=650776
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 650776</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650776">Mozilla Bug 650776</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 650776 **/
-
-var u = Components.interfaces.nsIParserUtils;
-var s = Components.classes["@mozilla.org/parserutils;1"]
-        .getService(u);
-
-// Basic sanity
-is(s.sanitize("foo", 0), "<html><head></head><body>foo</body></html>", "Wrong sanitizer result 1");
-// Scripts get removed
-is(s.sanitize("<script>\u003c/script>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 2");
-// Event handlers get removed
-is(s.sanitize("<a onclick='boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 3");
-// By default, styles are removed
-is(s.sanitize("<style>p { color: red; }</style><p style='background-color: blue;'></p>", 0), "<html><head></head><body><p></p></body></html>", "Wrong sanitizer result 4");
-// Can allow styles
-is(s.sanitize("<style>p { color: red; }</style><p style='background-color: blue;'></p>", u.SanitizerAllowStyle), '<html><head><style>p { color: red; }</style></head><body><p style="background-color: blue;"></p></body></html>', "Wrong sanitizer result 5");
-// -moz-binding gets dropped when styles allowed; however, reconstructing the p { ... } part seems broken!
-todo_is(s.sanitize("<style>p { color: red; -moz-binding: url(foo); }</style><p style='background-color: blue; -moz-binding: url(foo);'></p>", u.SanitizerAllowStyle), '<html><head><style>p { color: red; }</style></head><body><p style="background-color: blue;"></p></body></html>', "Wrong sanitizer result 6");
-// Various cid: embeds only cases
-is(s.sanitize("<img src='foo.html'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img></body></html>', "Wrong sanitizer result 7");
-is(s.sanitize("<img src='cid:foo'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img src="cid:foo"></body></html>', "Wrong sanitizer result 8");
-is(s.sanitize("<img src='data:image/png,'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img></body></html>', "Wrong sanitizer result 9");
-is(s.sanitize("<img src='http://mochi.test/'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img></body></html>', "Wrong sanitizer result 10");
-is(s.sanitize("<a href='http://mochi.test/'></a>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><a href="http://mochi.test/"></a></body></html>', "Wrong sanitizer result 11");
-is(s.sanitize("<body background='http://mochi.test/'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body></body></html>', "Wrong sanitizer result 12");
-is(s.sanitize("<body background='cid:foo'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body background="cid:foo"></body></html>', "Wrong sanitizer result 13");
-is(s.sanitize("<svg></svg>", u.SanitizerCidEmbedsOnly), '<html><head></head><body></body></html>', "Wrong sanitizer result 14");
-is(s.sanitize("<math definitionURL='cid:foo' altimg='cid:foo'></math>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><math></math></body></html>', "Wrong sanitizer result 14");
-is(s.sanitize("<video><source src='http://mochi.test/'></video>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><video controls="controls"><source></video></body></html>', "Wrong sanitizer result 15");
-is(s.sanitize("<style></style>", u.SanitizerAllowStyle | u.SanitizerCidEmbedsOnly), '<html><head></head><body></body></html>', "Wrong sanitizer result 16");
-// Dangerous links
-is(s.sanitize("<a href='javascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 17");
-is(s.sanitize("<a href='JavaScript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 18");
-is(s.sanitize("<a href=' javascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 19");
-is(s.sanitize("<a href='\njavascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 20");
-is(s.sanitize("<a href='\fjavascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 21");
-is(s.sanitize("<a href='\u00A0javascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 22");
-is(s.sanitize("<a href='foo.html'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 23");
-// Comments
-is(s.sanitize("<!-- foo -->", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 24");
-is(s.sanitize("<!-- foo -->", u.SanitizerAllowComments), "<!-- foo -->\n<html><head></head><body></body></html>", "Wrong sanitizer result 25");
-// noscript
-is(s.sanitize("<body><noscript><p class=bar>foo</p></noscript>", 0), '<html><head></head><body><noscript><p class="bar">foo</p></noscript></body></html>', "Wrong sanitizer result 26");
-// dangerous elements
-is(s.sanitize("<iframe></iframe>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 27");
-is(s.sanitize("<object></object>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 28");
-is(s.sanitize("<embed>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 29");
-// presentationalism
-is(s.sanitize("<font></font>", 0), "<html><head></head><body><font></font></body></html>", "Wrong sanitizer result 30");
-is(s.sanitize("<center></center>", 0), "<html><head></head><body><center></center></body></html>", "Wrong sanitizer result 31");
-is(s.sanitize("<div align=center></div>", 0), '<html><head></head><body><div align="center"></div></body></html>', "Wrong sanitizer result 32");
-is(s.sanitize("<table><tr><td bgcolor=#FFFFFF>", 0), '<html><head></head><body><table><tbody><tr><td bgcolor="#FFFFFF"></td></tr></tbody></table></body></html>', "Wrong sanitizer result 33");
-is(s.sanitize("<font></font>", u.SanitizerDropNonCSSPresentation), "<html><head></head><body></body></html>", "Wrong sanitizer result 34");
-is(s.sanitize("<center></center>", u.SanitizerDropNonCSSPresentation), "<html><head></head><body></body></html>", "Wrong sanitizer result 35");
-is(s.sanitize("<div align=center></div>", u.SanitizerDropNonCSSPresentation), '<html><head></head><body><div></div></body></html>', "Wrong sanitizer result 36");
-is(s.sanitize("<table><tr><td bgcolor=#FFFFFF>", u.SanitizerDropNonCSSPresentation), '<html><head></head><body><table><tbody><tr><td></td></tr></tbody></table></body></html>', "Wrong sanitizer result 37");
-// metadata
-is(s.sanitize("<meta charset=utf-7>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 38");
-is(s.sanitize("<meta http-equiv=content-type content='text/html; charset=utf-7'>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 39");
-is(s.sanitize("<meta itemprop=foo content=bar>", 0), '<html><head><meta itemprop="foo" content="bar"></head><body></body></html>', "Wrong sanitizer result 40");
-is(s.sanitize("<link rel=whatever href=http://mochi.test/ >", 0), '<html><head></head><body></body></html>', "Wrong sanitizer result 41");
-is(s.sanitize("<link itemprop=foo href=http://mochi.test/ >", 0), '<html><head><link itemprop="foo" href="http://mochi.test/"></head><body></body></html>', "Wrong sanitizer result 42");
-is(s.sanitize("<link rel=stylesheet itemprop=foo href=http://mochi.test/ >", 0), '<html><head><link itemprop="foo" href="http://mochi.test/"></head><body></body></html>', "Wrong sanitizer result 43");
-is(s.sanitize("<meta name=foo content=bar>", 0), '<html><head><meta name="foo" content="bar"></head><body></body></html>', "Wrong sanitizer result 44");
-// forms
-is(s.sanitize("<form></form>", 0), '<html><head></head><body><form></form></body></html>', "Wrong sanitizer result 45");
-is(s.sanitize("<fieldset><legend></legend></fieldset>", 0), '<html><head></head><body><fieldset><legend></legend></fieldset></body></html>', "Wrong sanitizer result 46");
-is(s.sanitize("<input>", 0), '<html><head></head><body><input></body></html>', "Wrong sanitizer result 47");
-is(s.sanitize("<button>foo</button>", 0), '<html><head></head><body><button>foo</button></body></html>', "Wrong sanitizer result 48");
-is(s.sanitize("<select><optgroup><option>foo</option></optgroup></select></button>", 0), '<html><head></head><body><select><optgroup><option>foo</option></optgroup></select></body></html>', "Wrong sanitizer result 49");
-is(s.sanitize("<form></form>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 50");
-is(s.sanitize("<fieldset><legend></legend></fieldset>", u.SanitizerDropForms), '<html><head></head><body><fieldset><legend></legend></fieldset></body></html>', "Wrong sanitizer result 51");
-is(s.sanitize("<input>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 52");
-is(s.sanitize("<button>foo</button>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 53");
-is(s.sanitize("<select><optgroup><option>foo</option></optgroup></select></button>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 54");
-// doctype
-is(s.sanitize("<!DOCTYPE html>", 0), '<!DOCTYPE html>\n<html><head></head><body></body></html>', "Wrong sanitizer result 55");
-// title
-is(s.sanitize("<title></title>", 0), '<html><head><title></title></head><body></body></html>', "Wrong sanitizer result 56");
-// Drop media
-is(s.sanitize("<img>", u.SanitizerDropMedia), '<html><head></head><body></body></html>', "Wrong sanitizer result 57");
-is(s.sanitize("<svg>foo</svg>", u.SanitizerDropMedia), '<html><head></head><body>foo</body></html>', "Wrong sanitizer result 58");
-is(s.sanitize("<video><source></video>", u.SanitizerDropMedia), '<html><head></head><body></body></html>', "Wrong sanitizer result 59");
-is(s.sanitize("<audio><source></audio>", u.SanitizerDropMedia), '<html><head></head><body></body></html>', "Wrong sanitizer result 60");
-
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/base/test/chrome/test_bug650784.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=650776
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 650776</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650776">Mozilla Bug 650776</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 650776 **/
-
-var c = Components.interfaces.nsIDocumentEncoder;
-var s = Components.classes["@mozilla.org/parserutils;1"]
-        .getService(Components.interfaces.nsIParserUtils);
-
-is(s.convertToPlainText("foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 1");
-is(s.convertToPlainText("foo foo foo", c.OutputWrap | c.OutputLFLineBreak, 7), "foo foo\nfoo", "Wrong conversion result 2");
-is(s.convertToPlainText("<body><noscript>b<span>a</span>r</noscript>foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 3");
-is(s.convertToPlainText("<body><noscript>b<span>a</span>r</noscript>foo", c.OutputNoScriptContent, 0), "barfoo", "Wrong conversion result 4");
-is(s.convertToPlainText("foo\u00A0bar", c.OutputPersistNBSP | c.OutputLFLineBreak, 0), "foo\u00A0bar", "Wrong conversion result 5");
-is(s.convertToPlainText("foo\u00A0bar", c.OutputLFLineBreak, 0), "foo bar", "Wrong conversion result 6");
-is(s.convertToPlainText("<body><noframes>bar</noframes>foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 7");
-// OutputNoFramesContent doesn't actually work, because the flag gets overridden in all cases.
-is(s.convertToPlainText("<body><noframes>bar</noframes>foo", c.OutputNoFramesContent | c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 8");
-is(s.convertToPlainText("<i>foo</i> <b>bar</b>", c.OutputFormatted | c.OutputLFLineBreak, 0), "/foo/ *bar*\n", "Wrong conversion result 9");
-is(s.convertToPlainText("<p>foo</p> <p>bar</p>", c.OutputLFLineBreak, 0), "foo\n\nbar", "Wrong conversion result 10");
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/base/test/chrome/test_bug750096.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=750096
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 750096</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=750096">Mozilla Bug 750096</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 750096 **/
-
-SimpleTest.waitForExplicitFinish();
-
-var u = Components.interfaces.nsIParserUtils;
-var s = Components.classes["@mozilla.org/parserutils;1"]
-        .getService(u);
-
-var elt = document.getElementById("content");
-
-var embed = s.parseFragment("<embed src=\'javascript:this.fail = true;\'>", 0, false, null, elt);
-var img = s.parseFragment("<img src=\'javascript:this.fail = true;\'>", 0, false, null, elt);
-var video = s.parseFragment("<video src=\'javascript:this.fail = true;\'></video>", 0, false, null, elt);
-var object = s.parseFragment("<object data=\'javascript:this.fail = true;\'></object>", 0, false, null, elt);
-var iframe = s.parseFragment("<iframe src=\'javascript:this.fail = true;\'></iframe>", 0, false, null, elt);
-
-setTimeout(function() {
-  ok(!window.fail, "Should not have failed.");
-  SimpleTest.finish();
-}, 0);
-
-</script>
-</pre>
-</body>
-</html>
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -636,16 +636,18 @@ skip-if = toolkit == 'android' #bug 6870
 [test_bug622246.html]
 [test_bug625722.html]
 [test_bug626262.html]
 [test_bug628938.html]
 [test_bug631615.html]
 [test_bug638112.html]
 [test_bug647518.html]
 [test_bug650001.html]
+[test_bug650776.html]
+[test_bug650784.html]
 [test_bug656283.html]
 [test_bug664916.html]
 [test_bug666604.html]
 skip-if = buildapp == 'b2g' # b2g(dom.disable_open_during_load not implemented in b2g) b2g-debug(dom.disable_open_during_load not implemented in b2g) b2g-desktop(dom.disable_open_during_load not implemented in b2g)
 [test_bug675121.html]
 skip-if = buildapp == 'b2g' # b2g(bug 901378) b2g-debug(bug 901378) b2g-desktop(bug 901378)
 [test_bug675166.html]
 [test_bug682463.html]
@@ -688,16 +690,17 @@ skip-if = os == "mac" # fails intermitte
 [test_bug719533.html]
 [test_bug726364.html]
 [test_bug737087.html]
 [test_bug737565.html]
 [test_bug737612.html]
 [test_bug738108.html]
 [test_bug744830.html]
 [test_bug749367.html]
+[test_bug750096.html]
 [test_bug753278.html]
 [test_bug761120.html]
 [test_bug782342.html]
 [test_bug787778.html]
 [test_bug789315.html]
 [test_bug789856.html]
 [test_bug804395.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #bug 901343, specialpowers.wrap issue createsystemxhr
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug650776.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650776
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 650776</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650776">Mozilla Bug 650776</a>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650776 **/
+
+var u = SpecialPowers.Ci.nsIParserUtils;
+var s = SpecialPowers.ParserUtils;
+
+// Basic sanity
+is(s.sanitize("foo", 0), "<html><head></head><body>foo</body></html>", "Wrong sanitizer result 1");
+// Scripts get removed
+is(s.sanitize("<script>\u003c/script>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 2");
+// Event handlers get removed
+is(s.sanitize("<a onclick='boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 3");
+// By default, styles are removed
+is(s.sanitize("<style>p { color: red; }</style><p style='background-color: blue;'></p>", 0), "<html><head></head><body><p></p></body></html>", "Wrong sanitizer result 4");
+// Can allow styles
+is(s.sanitize("<style>p { color: red; }</style><p style='background-color: blue;'></p>", u.SanitizerAllowStyle), '<html><head><style>p { color: red; }</style></head><body><p style="background-color: blue;"></p></body></html>', "Wrong sanitizer result 5");
+// -moz-binding gets dropped when styles allowed; however, reconstructing the p { ... } part seems broken!
+todo_is(s.sanitize("<style>p { color: red; -moz-binding: url(foo); }</style><p style='background-color: blue; -moz-binding: url(foo);'></p>", u.SanitizerAllowStyle), '<html><head><style>p { color: red; }</style></head><body><p style="background-color: blue;"></p></body></html>', "Wrong sanitizer result 6");
+// Various cid: embeds only cases
+is(s.sanitize("<img src='foo.html'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img></body></html>', "Wrong sanitizer result 7");
+is(s.sanitize("<img src='cid:foo'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img src="cid:foo"></body></html>', "Wrong sanitizer result 8");
+is(s.sanitize("<img src='data:image/png,'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img></body></html>', "Wrong sanitizer result 9");
+is(s.sanitize("<img src='http://mochi.test/'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img></body></html>', "Wrong sanitizer result 10");
+is(s.sanitize("<a href='http://mochi.test/'></a>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><a href="http://mochi.test/"></a></body></html>', "Wrong sanitizer result 11");
+is(s.sanitize("<body background='http://mochi.test/'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body></body></html>', "Wrong sanitizer result 12");
+is(s.sanitize("<body background='cid:foo'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body background="cid:foo"></body></html>', "Wrong sanitizer result 13");
+is(s.sanitize("<svg></svg>", u.SanitizerCidEmbedsOnly), '<html><head></head><body></body></html>', "Wrong sanitizer result 14");
+is(s.sanitize("<math definitionURL='cid:foo' altimg='cid:foo'></math>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><math></math></body></html>', "Wrong sanitizer result 14");
+is(s.sanitize("<video><source src='http://mochi.test/'></video>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><video controls="controls"><source></video></body></html>', "Wrong sanitizer result 15");
+is(s.sanitize("<style></style>", u.SanitizerAllowStyle | u.SanitizerCidEmbedsOnly), '<html><head></head><body></body></html>', "Wrong sanitizer result 16");
+// Dangerous links
+is(s.sanitize("<a href='javascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 17");
+is(s.sanitize("<a href='JavaScript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 18");
+is(s.sanitize("<a href=' javascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 19");
+is(s.sanitize("<a href='\njavascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 20");
+is(s.sanitize("<a href='\fjavascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 21");
+is(s.sanitize("<a href='\u00A0javascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 22");
+is(s.sanitize("<a href='foo.html'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 23");
+// Comments
+is(s.sanitize("<!-- foo -->", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 24");
+is(s.sanitize("<!-- foo -->", u.SanitizerAllowComments), "<!-- foo -->\n<html><head></head><body></body></html>", "Wrong sanitizer result 25");
+// noscript
+is(s.sanitize("<body><noscript><p class=bar>foo</p></noscript>", 0), '<html><head></head><body><noscript><p class="bar">foo</p></noscript></body></html>', "Wrong sanitizer result 26");
+// dangerous elements
+is(s.sanitize("<iframe></iframe>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 27");
+is(s.sanitize("<object></object>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 28");
+is(s.sanitize("<embed>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 29");
+// presentationalism
+is(s.sanitize("<font></font>", 0), "<html><head></head><body><font></font></body></html>", "Wrong sanitizer result 30");
+is(s.sanitize("<center></center>", 0), "<html><head></head><body><center></center></body></html>", "Wrong sanitizer result 31");
+is(s.sanitize("<div align=center></div>", 0), '<html><head></head><body><div align="center"></div></body></html>', "Wrong sanitizer result 32");
+is(s.sanitize("<table><tr><td bgcolor=#FFFFFF>", 0), '<html><head></head><body><table><tbody><tr><td bgcolor="#FFFFFF"></td></tr></tbody></table></body></html>', "Wrong sanitizer result 33");
+is(s.sanitize("<font></font>", u.SanitizerDropNonCSSPresentation), "<html><head></head><body></body></html>", "Wrong sanitizer result 34");
+is(s.sanitize("<center></center>", u.SanitizerDropNonCSSPresentation), "<html><head></head><body></body></html>", "Wrong sanitizer result 35");
+is(s.sanitize("<div align=center></div>", u.SanitizerDropNonCSSPresentation), '<html><head></head><body><div></div></body></html>', "Wrong sanitizer result 36");
+is(s.sanitize("<table><tr><td bgcolor=#FFFFFF>", u.SanitizerDropNonCSSPresentation), '<html><head></head><body><table><tbody><tr><td></td></tr></tbody></table></body></html>', "Wrong sanitizer result 37");
+// metadata
+is(s.sanitize("<meta charset=utf-7>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 38");
+is(s.sanitize("<meta http-equiv=content-type content='text/html; charset=utf-7'>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 39");
+is(s.sanitize("<meta itemprop=foo content=bar>", 0), '<html><head><meta itemprop="foo" content="bar"></head><body></body></html>', "Wrong sanitizer result 40");
+is(s.sanitize("<link rel=whatever href=http://mochi.test/ >", 0), '<html><head></head><body></body></html>', "Wrong sanitizer result 41");
+is(s.sanitize("<link itemprop=foo href=http://mochi.test/ >", 0), '<html><head><link itemprop="foo" href="http://mochi.test/"></head><body></body></html>', "Wrong sanitizer result 42");
+is(s.sanitize("<link rel=stylesheet itemprop=foo href=http://mochi.test/ >", 0), '<html><head><link itemprop="foo" href="http://mochi.test/"></head><body></body></html>', "Wrong sanitizer result 43");
+is(s.sanitize("<meta name=foo content=bar>", 0), '<html><head><meta name="foo" content="bar"></head><body></body></html>', "Wrong sanitizer result 44");
+// forms
+is(s.sanitize("<form></form>", 0), '<html><head></head><body><form></form></body></html>', "Wrong sanitizer result 45");
+is(s.sanitize("<fieldset><legend></legend></fieldset>", 0), '<html><head></head><body><fieldset><legend></legend></fieldset></body></html>', "Wrong sanitizer result 46");
+is(s.sanitize("<input>", 0), '<html><head></head><body><input></body></html>', "Wrong sanitizer result 47");
+is(s.sanitize("<button>foo</button>", 0), '<html><head></head><body><button>foo</button></body></html>', "Wrong sanitizer result 48");
+is(s.sanitize("<select><optgroup><option>foo</option></optgroup></select></button>", 0), '<html><head></head><body><select><optgroup><option>foo</option></optgroup></select></body></html>', "Wrong sanitizer result 49");
+is(s.sanitize("<form></form>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 50");
+is(s.sanitize("<fieldset><legend></legend></fieldset>", u.SanitizerDropForms), '<html><head></head><body><fieldset><legend></legend></fieldset></body></html>', "Wrong sanitizer result 51");
+is(s.sanitize("<input>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 52");
+is(s.sanitize("<button>foo</button>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 53");
+is(s.sanitize("<select><optgroup><option>foo</option></optgroup></select></button>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 54");
+// doctype
+is(s.sanitize("<!DOCTYPE html>", 0), '<!DOCTYPE html>\n<html><head></head><body></body></html>', "Wrong sanitizer result 55");
+// title
+is(s.sanitize("<title></title>", 0), '<html><head><title></title></head><body></body></html>', "Wrong sanitizer result 56");
+// Drop media
+is(s.sanitize("<img>", u.SanitizerDropMedia), '<html><head></head><body></body></html>', "Wrong sanitizer result 57");
+is(s.sanitize("<svg>foo</svg>", u.SanitizerDropMedia), '<html><head></head><body>foo</body></html>', "Wrong sanitizer result 58");
+is(s.sanitize("<video><source></video>", u.SanitizerDropMedia), '<html><head></head><body></body></html>', "Wrong sanitizer result 59");
+is(s.sanitize("<audio><source></audio>", u.SanitizerDropMedia), '<html><head></head><body></body></html>', "Wrong sanitizer result 60");
+
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug650784.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650776
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 650776</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650776">Mozilla Bug 650776</a>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650776 **/
+
+var c = SpecialPowers.Ci.nsIDocumentEncoder;
+var s = SpecialPowers.ParserUtils;
+
+is(s.convertToPlainText("foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 1");
+is(s.convertToPlainText("foo foo foo", c.OutputWrap | c.OutputLFLineBreak, 7), "foo foo\nfoo", "Wrong conversion result 2");
+is(s.convertToPlainText("<body><noscript>b<span>a</span>r</noscript>foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 3");
+is(s.convertToPlainText("<body><noscript>b<span>a</span>r</noscript>foo", c.OutputNoScriptContent, 0), "barfoo", "Wrong conversion result 4");
+is(s.convertToPlainText("foo\u00A0bar", c.OutputPersistNBSP | c.OutputLFLineBreak, 0), "foo\u00A0bar", "Wrong conversion result 5");
+is(s.convertToPlainText("foo\u00A0bar", c.OutputLFLineBreak, 0), "foo bar", "Wrong conversion result 6");
+is(s.convertToPlainText("<body><noframes>bar</noframes>foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 7");
+// OutputNoFramesContent doesn't actually work, because the flag gets overridden in all cases.
+is(s.convertToPlainText("<body><noframes>bar</noframes>foo", c.OutputNoFramesContent | c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 8");
+is(s.convertToPlainText("<i>foo</i> <b>bar</b>", c.OutputFormatted | c.OutputLFLineBreak, 0), "/foo/ *bar*\n", "Wrong conversion result 9");
+is(s.convertToPlainText("<p>foo</p> <p>bar</p>", c.OutputLFLineBreak, 0), "foo\n\nbar", "Wrong conversion result 10");
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug750096.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=750096
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 750096</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=750096">Mozilla Bug 750096</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 750096 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var u = SpecialPowers.Ci.nsIParserUtils;
+var s = SpecialPowers.ParserUtils;
+
+var elt = document.getElementById("content");
+
+var embed = s.parseFragment("<embed src=\'javascript:this.fail = true;\'>", 0, false, null, elt);
+var img = s.parseFragment("<img src=\'javascript:this.fail = true;\'>", 0, false, null, elt);
+var video = s.parseFragment("<video src=\'javascript:this.fail = true;\'></video>", 0, false, null, elt);
+var object = s.parseFragment("<object data=\'javascript:this.fail = true;\'></object>", 0, false, null, elt);
+var iframe = s.parseFragment("<iframe src=\'javascript:this.fail = true;\'></iframe>", 0, false, null, elt);
+
+setTimeout(function() {
+  ok(!window.fail, "Should not have failed.");
+  SimpleTest.finish();
+}, 0);
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -404,16 +404,17 @@ DOMInterfaces = {
 'DominatorTree': {
     'nativeType': 'mozilla::devtools::DominatorTree'
 },
 
 'DOMException': {
     'binaryNames': {
         'message': 'messageMoz',
     },
+    'implicitJSContext': [ 'filename', 'lineNumber', 'stack' ],
 },
 
 'DOMMatrixReadOnly': {
     'headerFile': 'mozilla/dom/DOMMatrix.h',
     'concrete': False,
 },
 
 'DOMPointReadOnly': {
@@ -473,16 +474,17 @@ DOMInterfaces = {
     'jsImplParent': 'mozilla::DOMEventTargetHelper'
 },
 
 'Exception': {
     'headerFile': 'mozilla/dom/DOMException.h',
     'binaryNames': {
         'message': 'messageMoz',
     },
+    'implicitJSContext': [ '__stringifier', 'filename', 'lineNumber', 'stack' ],
 },
 
 'ExtendableEvent': {
     'headerFile': 'mozilla/dom/ServiceWorkerEvents.h',
     'nativeType': 'mozilla::dom::workers::ExtendableEvent',
     'implicitJSContext': [ 'waitUntil' ],
 },
 
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -170,205 +170,130 @@ CreateException(JSContext* aCx, nsresult
 
   // If not, use the default.
   RefPtr<Exception> exception =
     new Exception(aMessage, aRv, EmptyCString(), nullptr, nullptr);
   return exception.forget();
 }
 
 already_AddRefed<nsIStackFrame>
-GetCurrentJSStack()
+GetCurrentJSStack(int32_t aMaxDepth)
 {
   // is there a current context available?
-  JSContext* cx = nullptr;
-
-  if (NS_IsMainThread()) {
-    MOZ_ASSERT(nsContentUtils::XPConnect());
-    cx = nsContentUtils::GetCurrentJSContext();
-  } else {
-    cx = workers::GetCurrentThreadJSContext();
-  }
+  JSContext* cx = nsContentUtils::GetCurrentJSContextForThread();
 
   if (!cx || !js::GetContextCompartment(cx)) {
     return nullptr;
   }
 
-  nsCOMPtr<nsIStackFrame> stack = exceptions::CreateStack(cx);
-  if (!stack) {
-    return nullptr;
-  }
-
-  // Note that CreateStack only returns JS frames, so we're done here.
-  return stack.forget();
+  return exceptions::CreateStack(cx, aMaxDepth);
 }
 
 AutoForceSetExceptionOnContext::AutoForceSetExceptionOnContext(JSContext* aCx)
   : mCx(aCx)
 {
   mOldValue = JS::ContextOptionsRef(mCx).autoJSAPIOwnsErrorReporting();
   JS::ContextOptionsRef(mCx).setAutoJSAPIOwnsErrorReporting(true);
 }
 
 AutoForceSetExceptionOnContext::~AutoForceSetExceptionOnContext()
 {
   JS::ContextOptionsRef(mCx).setAutoJSAPIOwnsErrorReporting(mOldValue);
 }
 
 namespace exceptions {
 
-class StackFrame : public nsIStackFrame
+class JSStackFrame : public nsIStackFrame
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(StackFrame)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(JSStackFrame)
   NS_DECL_NSISTACKFRAME
 
-  StackFrame()
-    : mLineno(0)
-    , mColNo(0)
-    , mLanguage(nsIProgrammingLanguage::UNKNOWN)
-  {
-  }
+  // aStack must not be null.
+  explicit JSStackFrame(JS::Handle<JSObject*> aStack);
 
 protected:
-  virtual ~StackFrame();
+  int32_t GetLineno(JSContext* aCx);
 
-  virtual bool IsJSFrame() const
-  {
-    return false;
-  }
+  int32_t GetColNo(JSContext* aCx);
 
-  virtual int32_t GetLineno()
-  {
-    return mLineno;
-  }
+private:
+  virtual ~JSStackFrame();
 
-  virtual int32_t GetColNo()
-  {
-    return mColNo;
-  }
+  JS::Heap<JSObject*> mStack;
+  nsString mFormattedStack;
 
   nsCOMPtr<nsIStackFrame> mCaller;
   nsCOMPtr<nsIStackFrame> mAsyncCaller;
   nsString mFilename;
   nsString mFunname;
   nsString mAsyncCause;
   int32_t mLineno;
   int32_t mColNo;
-  uint32_t mLanguage;
-};
-
-StackFrame::~StackFrame()
-{
-}
-
-NS_IMPL_CYCLE_COLLECTION(StackFrame, mCaller, mAsyncCaller)
-NS_IMPL_CYCLE_COLLECTING_ADDREF(StackFrame)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(StackFrame)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StackFrame)
-  NS_INTERFACE_MAP_ENTRY(nsIStackFrame)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-class JSStackFrame : public StackFrame
-{
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(JSStackFrame,
-                                                         StackFrame)
-
-  // aStack must not be null.
-  explicit JSStackFrame(JS::Handle<JSObject*> aStack);
-
-  static already_AddRefed<nsIStackFrame>
-  CreateStack(JSContext* aCx, int32_t aMaxDepth = -1);
-
-  NS_IMETHOD GetLanguageName(nsACString& aLanguageName) override;
-  NS_IMETHOD GetFilename(nsAString& aFilename) override;
-  NS_IMETHOD GetName(nsAString& aFunction) override;
-  NS_IMETHOD GetAsyncCause(nsAString& aAsyncCause) override;
-  NS_IMETHOD GetAsyncCaller(nsIStackFrame** aAsyncCaller) override;
-  NS_IMETHOD GetCaller(nsIStackFrame** aCaller) override;
-  NS_IMETHOD GetFormattedStack(nsAString& aStack) override;
-  NS_IMETHOD GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame) override;
-
-protected:
-  virtual bool IsJSFrame() const override {
-    return true;
-  }
-
-  virtual int32_t GetLineno() override;
-  virtual int32_t GetColNo() override;
-
-private:
-  virtual ~JSStackFrame();
-
-  JS::Heap<JSObject*> mStack;
-  nsString mFormattedStack;
 
   bool mFilenameInitialized;
   bool mFunnameInitialized;
   bool mLinenoInitialized;
   bool mColNoInitialized;
   bool mAsyncCauseInitialized;
   bool mAsyncCallerInitialized;
   bool mCallerInitialized;
   bool mFormattedStackInitialized;
 };
 
 JSStackFrame::JSStackFrame(JS::Handle<JSObject*> aStack)
   : mStack(aStack)
+  , mLineno(0)
+  , mColNo(0)
   , mFilenameInitialized(false)
   , mFunnameInitialized(false)
   , mLinenoInitialized(false)
   , mColNoInitialized(false)
   , mAsyncCauseInitialized(false)
   , mAsyncCallerInitialized(false)
   , mCallerInitialized(false)
   , mFormattedStackInitialized(false)
 {
   MOZ_ASSERT(mStack);
 
   mozilla::HoldJSObjects(this);
-  mLineno = 0;
-  mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
 }
 
 JSStackFrame::~JSStackFrame()
 {
   mozilla::DropJSObjects(this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(JSStackFrame)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(JSStackFrame, StackFrame)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(JSStackFrame)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCaller)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAsyncCaller)
   tmp->mStack = nullptr;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(JSStackFrame, StackFrame)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(JSStackFrame)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCaller)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAsyncCaller)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(JSStackFrame, StackFrame)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(JSStackFrame)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStack)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-NS_IMPL_ADDREF_INHERITED(JSStackFrame, StackFrame)
-NS_IMPL_RELEASE_INHERITED(JSStackFrame, StackFrame)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(JSStackFrame)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(JSStackFrame)
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(JSStackFrame)
-NS_INTERFACE_MAP_END_INHERITING(StackFrame)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSStackFrame)
+  NS_INTERFACE_MAP_ENTRY(nsIStackFrame)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
 
-NS_IMETHODIMP StackFrame::GetLanguage(uint32_t* aLanguage)
+NS_IMETHODIMP JSStackFrame::GetLanguage(uint32_t* aLanguage)
 {
-  *aLanguage = mLanguage;
-  return NS_OK;
-}
-
-NS_IMETHODIMP StackFrame::GetLanguageName(nsACString& aLanguageName)
-{
-  aLanguageName.AssignLiteral("C++");
+  *aLanguage = nsIProgrammingLanguage::JAVASCRIPT;
   return NS_OK;
 }
 
 NS_IMETHODIMP JSStackFrame::GetLanguageName(nsACString& aLanguageName)
 {
   aLanguageName.AssignLiteral("JavaScript");
   return NS_OK;
 }
@@ -406,423 +331,353 @@ GetValueIfNotCached(JSContext* aCx, JSOb
   }
 
   *aUseCachedValue = false;
   JS::ExposeObjectToActiveJS(stack);
 
   aPropGetter(aCx, stack, aValue, JS::SavedFrameSelfHosted::Exclude);
 }
 
-NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename)
+NS_IMETHODIMP JSStackFrame::GetFilename(JSContext* aCx, nsAString& aFilename)
 {
   if (!mStack) {
     aFilename.Truncate();
     return NS_OK;
   }
 
-  ThreadsafeAutoJSContext cx;
-  JS::Rooted<JSString*> filename(cx);
+  JS::Rooted<JSString*> filename(aCx);
   bool canCache = false, useCachedValue = false;
-  GetValueIfNotCached(cx, mStack, JS::GetSavedFrameSource, mFilenameInitialized,
+  GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameSource,
+                      mFilenameInitialized,
                       &canCache, &useCachedValue, &filename);
   if (useCachedValue) {
-    return StackFrame::GetFilename(aFilename);
+    aFilename = mFilename;
+    return NS_OK;
   }
 
   nsAutoJSString str;
-  if (!str.init(cx, filename)) {
-    JS_ClearPendingException(cx);
+  if (!str.init(aCx, filename)) {
+    JS_ClearPendingException(aCx);
     aFilename.Truncate();
     return NS_OK;
   }
   aFilename = str;
 
   if (canCache) {
     mFilename = str;
     mFilenameInitialized = true;
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP StackFrame::GetFilename(nsAString& aFilename)
-{
-  // The filename must be set to null if empty.
-  if (mFilename.IsEmpty()) {
-    aFilename.SetIsVoid(true);
-  } else {
-    aFilename.Assign(mFilename);
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction)
+NS_IMETHODIMP JSStackFrame::GetName(JSContext* aCx, nsAString& aFunction)
 {
   if (!mStack) {
     aFunction.Truncate();
     return NS_OK;
   }
 
-  ThreadsafeAutoJSContext cx;
-  JS::Rooted<JSString*> name(cx);
+  JS::Rooted<JSString*> name(aCx);
   bool canCache = false, useCachedValue = false;
-  GetValueIfNotCached(cx, mStack, JS::GetSavedFrameFunctionDisplayName,
+  GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameFunctionDisplayName,
                       mFunnameInitialized, &canCache, &useCachedValue,
                       &name);
 
   if (useCachedValue) {
-    return StackFrame::GetName(aFunction);
+    aFunction = mFunname;
+    return NS_OK;
   }
 
   if (name) {
     nsAutoJSString str;
-    if (!str.init(cx, name)) {
-      JS_ClearPendingException(cx);
+    if (!str.init(aCx, name)) {
+      JS_ClearPendingException(aCx);
       aFunction.Truncate();
       return NS_OK;
     }
     aFunction = str;
   } else {
     aFunction.SetIsVoid(true);
   }
 
   if (canCache) {
     mFunname = aFunction;
     mFunnameInitialized = true;
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP StackFrame::GetName(nsAString& aFunction)
-{
-  // The function name must be set to null if empty.
-  if (mFunname.IsEmpty()) {
-    aFunction.SetIsVoid(true);
-  } else {
-    aFunction.Assign(mFunname);
-  }
-
-  return NS_OK;
-}
-
-// virtual
 int32_t
-JSStackFrame::GetLineno()
+JSStackFrame::GetLineno(JSContext* aCx)
 {
   if (!mStack) {
     return 0;
   }
 
-  ThreadsafeAutoJSContext cx;
   uint32_t line;
   bool canCache = false, useCachedValue = false;
-  GetValueIfNotCached(cx, mStack, JS::GetSavedFrameLine, mLinenoInitialized,
+  GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameLine, mLinenoInitialized,
                       &canCache, &useCachedValue, &line);
 
   if (useCachedValue) {
-    return StackFrame::GetLineno();
+    return mLineno;
   }
 
   if (canCache) {
     mLineno = line;
     mLinenoInitialized = true;
   }
 
   return line;
 }
 
-NS_IMETHODIMP StackFrame::GetLineNumber(int32_t* aLineNumber)
+NS_IMETHODIMP JSStackFrame::GetLineNumber(JSContext* aCx, int32_t* aLineNumber)
 {
-  *aLineNumber = GetLineno();
+  *aLineNumber = GetLineno(aCx);
   return NS_OK;
 }
 
-// virtual
 int32_t
-JSStackFrame::GetColNo()
+JSStackFrame::GetColNo(JSContext* aCx)
 {
   if (!mStack) {
     return 0;
   }
 
-  ThreadsafeAutoJSContext cx;
   uint32_t col;
   bool canCache = false, useCachedValue = false;
-  GetValueIfNotCached(cx, mStack, JS::GetSavedFrameColumn, mColNoInitialized,
+  GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameColumn, mColNoInitialized,
                       &canCache, &useCachedValue, &col);
 
   if (useCachedValue) {
-    return StackFrame::GetColNo();
+    return mColNo;
   }
 
   if (canCache) {
     mColNo = col;
     mColNoInitialized = true;
   }
 
   return col;
 }
 
-NS_IMETHODIMP StackFrame::GetColumnNumber(int32_t* aColumnNumber)
+NS_IMETHODIMP JSStackFrame::GetColumnNumber(JSContext* aCx,
+                                            int32_t* aColumnNumber)
 {
-  *aColumnNumber = GetColNo();
+  *aColumnNumber = GetColNo(aCx);
   return NS_OK;
 }
 
-NS_IMETHODIMP StackFrame::GetSourceLine(nsACString& aSourceLine)
+NS_IMETHODIMP JSStackFrame::GetSourceLine(nsACString& aSourceLine)
 {
   aSourceLine.Truncate();
   return NS_OK;
 }
 
-NS_IMETHODIMP JSStackFrame::GetAsyncCause(nsAString& aAsyncCause)
+NS_IMETHODIMP JSStackFrame::GetAsyncCause(JSContext* aCx,
+                                          nsAString& aAsyncCause)
 {
   if (!mStack) {
     aAsyncCause.Truncate();
     return NS_OK;
   }
 
-  ThreadsafeAutoJSContext cx;
-  JS::Rooted<JSString*> asyncCause(cx);
+  JS::Rooted<JSString*> asyncCause(aCx);
   bool canCache = false, useCachedValue = false;
-  GetValueIfNotCached(cx, mStack, JS::GetSavedFrameAsyncCause,
+  GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameAsyncCause,
                       mAsyncCauseInitialized, &canCache, &useCachedValue,
                       &asyncCause);
 
   if (useCachedValue) {
-    return StackFrame::GetAsyncCause(aAsyncCause);
+    aAsyncCause = mAsyncCause;
+    return NS_OK;
   }
 
   if (asyncCause) {
     nsAutoJSString str;
-    if (!str.init(cx, asyncCause)) {
-      JS_ClearPendingException(cx);
+    if (!str.init(aCx, asyncCause)) {
+      JS_ClearPendingException(aCx);
       aAsyncCause.Truncate();
       return NS_OK;
     }
     aAsyncCause = str;
   } else {
     aAsyncCause.SetIsVoid(true);
   }
 
   if (canCache) {
     mAsyncCause = aAsyncCause;
     mAsyncCauseInitialized = true;
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP StackFrame::GetAsyncCause(nsAString& aAsyncCause)
-{
-  // The async cause must be set to null if empty.
-  if (mAsyncCause.IsEmpty()) {
-    aAsyncCause.SetIsVoid(true);
-  } else {
-    aAsyncCause.Assign(mAsyncCause);
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP JSStackFrame::GetAsyncCaller(nsIStackFrame** aAsyncCaller)
+NS_IMETHODIMP JSStackFrame::GetAsyncCaller(JSContext* aCx,
+                                           nsIStackFrame** aAsyncCaller)
 {
   if (!mStack) {
     *aAsyncCaller = nullptr;
     return NS_OK;
   }
 
-  ThreadsafeAutoJSContext cx;
-  JS::Rooted<JSObject*> asyncCallerObj(cx);
+  JS::Rooted<JSObject*> asyncCallerObj(aCx);
   bool canCache = false, useCachedValue = false;
-  GetValueIfNotCached(cx, mStack, JS::GetSavedFrameAsyncParent,
+  GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameAsyncParent,
                       mAsyncCallerInitialized, &canCache, &useCachedValue,
                       &asyncCallerObj);
 
   if (useCachedValue) {
-    return StackFrame::GetAsyncCaller(aAsyncCaller);
+    NS_IF_ADDREF(*aAsyncCaller = mAsyncCaller);
+    return NS_OK;
   }
 
   nsCOMPtr<nsIStackFrame> asyncCaller =
     asyncCallerObj ? new JSStackFrame(asyncCallerObj) : nullptr;
   asyncCaller.forget(aAsyncCaller);
 
   if (canCache) {
     mAsyncCaller = *aAsyncCaller;
     mAsyncCallerInitialized = true;
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP StackFrame::GetAsyncCaller(nsIStackFrame** aAsyncCaller)
-{
-  NS_IF_ADDREF(*aAsyncCaller = mAsyncCaller);
-  return NS_OK;
-}
-
-NS_IMETHODIMP JSStackFrame::GetCaller(nsIStackFrame** aCaller)
+NS_IMETHODIMP JSStackFrame::GetCaller(JSContext* aCx, nsIStackFrame** aCaller)
 {
   if (!mStack) {
     *aCaller = nullptr;
     return NS_OK;
   }
 
-  ThreadsafeAutoJSContext cx;
-  JS::Rooted<JSObject*> callerObj(cx);
+  JS::Rooted<JSObject*> callerObj(aCx);
   bool canCache = false, useCachedValue = false;
-  GetValueIfNotCached(cx, mStack, JS::GetSavedFrameParent, mCallerInitialized,
+  GetValueIfNotCached(aCx, mStack, JS::GetSavedFrameParent, mCallerInitialized,
                       &canCache, &useCachedValue, &callerObj);
 
   if (useCachedValue) {
-    return StackFrame::GetCaller(aCaller);
+    NS_IF_ADDREF(*aCaller = mCaller);
+    return NS_OK;
   }
 
   nsCOMPtr<nsIStackFrame> caller =
     callerObj ? new JSStackFrame(callerObj) : nullptr;
   caller.forget(aCaller);
 
   if (canCache) {
     mCaller = *aCaller;
     mCallerInitialized = true;
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP StackFrame::GetCaller(nsIStackFrame** aCaller)
-{
-  NS_IF_ADDREF(*aCaller = mCaller);
-  return NS_OK;
-}
-
-NS_IMETHODIMP JSStackFrame::GetFormattedStack(nsAString& aStack)
+NS_IMETHODIMP JSStackFrame::GetFormattedStack(JSContext* aCx, nsAString& aStack)
 {
   if (!mStack) {
     aStack.Truncate();
     return NS_OK;
   }
 
   // Sadly we can't use GetValueIfNotCached here, because our getter
   // returns bool, not JS::SavedFrameResult.  Maybe it's possible to
   // make the templates more complicated to deal, but in the meantime
   // let's just inline GetValueIfNotCached here.
-  ThreadsafeAutoJSContext cx;
 
-  // Allow caching if cx and stack are same-compartment.  Otherwise take the
+  // Allow caching if aCx and stack are same-compartment.  Otherwise take the
   // slow path.
   bool canCache =
-    js::GetContextCompartment(cx) == js::GetObjectCompartment(mStack);
+    js::GetContextCompartment(aCx) == js::GetObjectCompartment(mStack);
   if (canCache && mFormattedStackInitialized) {
     aStack = mFormattedStack;
     return NS_OK;
   }
 
   JS::ExposeObjectToActiveJS(mStack);
-  JS::Rooted<JSObject*> stack(cx, mStack);
+  JS::Rooted<JSObject*> stack(aCx, mStack);
 
-  JS::Rooted<JSString*> formattedStack(cx);
-  if (!JS::BuildStackString(cx, stack, &formattedStack)) {
-    JS_ClearPendingException(cx);
+  JS::Rooted<JSString*> formattedStack(aCx);
+  if (!JS::BuildStackString(aCx, stack, &formattedStack)) {
+    JS_ClearPendingException(aCx);
     aStack.Truncate();
     return NS_OK;
   }
 
   nsAutoJSString str;
-  if (!str.init(cx, formattedStack)) {
-    JS_ClearPendingException(cx);
+  if (!str.init(aCx, formattedStack)) {
+    JS_ClearPendingException(aCx);
     aStack.Truncate();
     return NS_OK;
   }
 
   aStack = str;
 
   if (canCache) {
     mFormattedStack = str;
     mFormattedStackInitialized = true;
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP StackFrame::GetFormattedStack(nsAString& aStack)
-{
-  aStack.Truncate();
-  return NS_OK;
-}
-
 NS_IMETHODIMP JSStackFrame::GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame)
 {
   aSavedFrame.setObjectOrNull(mStack);
   return NS_OK;
 }
 
-NS_IMETHODIMP StackFrame::GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame)
-{
-  aSavedFrame.setNull();
-  return NS_OK;
-}
-
-NS_IMETHODIMP StackFrame::ToString(nsACString& _retval)
+NS_IMETHODIMP JSStackFrame::ToString(JSContext* aCx, nsACString& _retval)
 {
   _retval.Truncate();
 
-  const char* frametype = IsJSFrame() ? "JS" : "native";
-
   nsString filename;
-  nsresult rv = GetFilename(filename);
+  nsresult rv = GetFilename(aCx, filename);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (filename.IsEmpty()) {
     filename.AssignLiteral("<unknown filename>");
   }
 
   nsString funname;
-  rv = GetName(funname);
+  rv = GetName(aCx, funname);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (funname.IsEmpty()) {
     funname.AssignLiteral("<TOP_LEVEL>");
   }
 
-  int32_t lineno = GetLineno();
+  int32_t lineno = GetLineno(aCx);
 
-  static const char format[] = "%s frame :: %s :: %s :: line %d";
-  _retval.AppendPrintf(format, frametype,
+  static const char format[] = "JS frame :: %s :: %s :: line %d";
+  _retval.AppendPrintf(format,
                        NS_ConvertUTF16toUTF8(filename).get(),
                        NS_ConvertUTF16toUTF8(funname).get(),
                        lineno);
   return NS_OK;
 }
 
-/* static */ already_AddRefed<nsIStackFrame>
-JSStackFrame::CreateStack(JSContext* aCx, int32_t aMaxDepth)
+already_AddRefed<nsIStackFrame>
+CreateStack(JSContext* aCx, int32_t aMaxDepth)
 {
   static const unsigned MAX_FRAMES = 100;
   if (aMaxDepth < 0) {
     aMaxDepth = MAX_FRAMES;
   }
 
   JS::Rooted<JSObject*> stack(aCx);
   if (!JS::CaptureCurrentStack(aCx, &stack, aMaxDepth)) {
     return nullptr;
   }
 
-  nsCOMPtr<nsIStackFrame> first;
   if (!stack) {
-    first = new StackFrame();
-  } else {
-    first = new JSStackFrame(stack);
+    return nullptr;
   }
-  return first.forget();
-}
 
-already_AddRefed<nsIStackFrame>
-CreateStack(JSContext* aCx, int32_t aMaxDepth)
-{
-  return JSStackFrame::CreateStack(aCx, aMaxDepth);
+  nsCOMPtr<nsIStackFrame> frame = new JSStackFrame(stack);
+  return frame.forget();
 }
 
 } // namespace exceptions
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/Exceptions.h
+++ b/dom/bindings/Exceptions.h
@@ -43,18 +43,21 @@ ThrowExceptionObject(JSContext* aCx, nsI
 // it pending on aCx.  If we're throwing a DOMException and aMessage is empty,
 // the default message for the nsresult in question will be used.
 //
 // This never returns null.
 already_AddRefed<Exception>
 CreateException(JSContext* aCx, nsresult aRv,
                 const nsACString& aMessage = EmptyCString());
 
+// aMaxDepth can be used to define a maximal depth for the stack trace. If the
+// value is -1, a default maximal depth will be selected.  Will return null if
+// there is no JS stack right now.
 already_AddRefed<nsIStackFrame>
-GetCurrentJSStack();
+GetCurrentJSStack(int32_t aMaxDepth = -1);
 
 // Throwing a TypeError on an ErrorResult may result in SpiderMonkey using its
 // own error reporting mechanism instead of just setting the exception on the
 // context.  This happens if no script is running. Bug 1107777 adds a flag that
 // forcibly turns this behaviour off. This is a stack helper to set the flag.
 class MOZ_STACK_CLASS AutoForceSetExceptionOnContext {
 private:
   JSContext* mCx;
@@ -63,17 +66,18 @@ public:
   explicit AutoForceSetExceptionOnContext(JSContext* aCx);
   ~AutoForceSetExceptionOnContext();
 };
 
 // Internal stuff not intended to be widely used.
 namespace exceptions {
 
 // aMaxDepth can be used to define a maximal depth for the stack trace. If the
-// value is -1, a default maximal depth will be selected.
+// value is -1, a default maximal depth will be selected.  Will return null if
+// there is no JS stack right now.
 already_AddRefed<nsIStackFrame>
 CreateStack(JSContext* aCx, int32_t aMaxDepth = -1);
 
 } // namespace exceptions
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/events/AsyncEventDispatcher.cpp
+++ b/dom/events/AsyncEventDispatcher.cpp
@@ -25,17 +25,17 @@ AsyncEventDispatcher::AsyncEventDispatch
   : mTarget(aTarget)
 {
   MOZ_ASSERT(mTarget);
   RefPtr<Event> event =
     EventDispatcher::CreateEvent(aTarget, nullptr, &aEvent, EmptyString());
   mEvent = do_QueryInterface(event);
   NS_ASSERTION(mEvent, "Should never fail to create an event");
   mEvent->DuplicatePrivateData();
-  mEvent->SetTrusted(aEvent.mFlags.mIsTrusted);
+  mEvent->SetTrusted(aEvent.IsTrusted());
 }
 
 NS_IMETHODIMP
 AsyncEventDispatcher::Run()
 {
   if (mCanceled) {
     return NS_OK;
   }
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -461,32 +461,31 @@ Event::GetTimeStamp(uint64_t* aTimeStamp
 {
   *aTimeStamp = mEvent->time;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Event::StopPropagation()
 {
-  mEvent->mFlags.mPropagationStopped = true;
+  mEvent->StopPropagation();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Event::StopImmediatePropagation()
 {
-  mEvent->mFlags.mPropagationStopped = true;
-  mEvent->mFlags.mImmediatePropagationStopped = true;
+  mEvent->StopImmediatePropagation();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Event::StopCrossProcessForwarding()
 {
-  mEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
+  mEvent->StopCrossProcessForwarding();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Event::GetIsTrusted(bool* aIsTrusted)
 {
   *aIsTrusted = IsTrusted();
   return NS_OK;
@@ -515,27 +514,17 @@ Event::PreventDefault(JSContext* aCx)
 
 void
 Event::PreventDefaultInternal(bool aCalledByDefaultHandler)
 {
   if (!mEvent->mFlags.mCancelable) {
     return;
   }
 
-  mEvent->mFlags.mDefaultPrevented = true;
-
-  // Note that even if preventDefault() has already been called by chrome,
-  // a call of preventDefault() by content needs to overwrite
-  // mDefaultPreventedByContent to true because in such case, defaultPrevented
-  // must be true when web apps check it after they call preventDefault().
-  if (!aCalledByDefaultHandler) {
-    mEvent->mFlags.mDefaultPreventedByContent = true;
-  } else {
-    mEvent->mFlags.mDefaultPreventedByChrome = true;
-  }
+  mEvent->PreventDefault(aCalledByDefaultHandler);
 
   if (!IsTrusted()) {
     return;
   }
 
   WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
   if (!dragEvent) {
     return;
@@ -620,17 +609,17 @@ Event::SetTarget(nsIDOMEventTarget* aTar
 {
   mEvent->target = do_QueryInterface(aTarget);
   return NS_OK;
 }
 
 NS_IMETHODIMP_(bool)
 Event::IsDispatchStopped()
 {
-  return mEvent->mFlags.mPropagationStopped;
+  return mEvent->PropagationStopped();
 }
 
 NS_IMETHODIMP_(WidgetEvent*)
 Event::WidgetEventPtr()
 {
   return mEvent;
 }
 
@@ -749,17 +738,17 @@ Event::GetEventPopupControlState(WidgetE
         abuse = openControlled;
         break;
       default:
         break;
       }
     }
     break;
   case eKeyboardEventClass:
-    if (aEvent->mFlags.mIsTrusted) {
+    if (aEvent->IsTrusted()) {
       uint32_t key = aEvent->AsKeyboardEvent()->keyCode;
       switch(aEvent->mMessage) {
       case eKeyPress:
         // return key on focused button. see note at eMouseClick.
         if (key == nsIDOMKeyEvent::DOM_VK_RETURN) {
           abuse = openAllowed;
         } else if (PopupAllowedForEvent("keypress")) {
           abuse = openControlled;
@@ -779,17 +768,17 @@ Event::GetEventPopupControlState(WidgetE
         }
         break;
       default:
         break;
       }
     }
     break;
   case eTouchEventClass:
-    if (aEvent->mFlags.mIsTrusted) {
+    if (aEvent->IsTrusted()) {
       switch (aEvent->mMessage) {
       case eTouchStart:
         if (PopupAllowedForEvent("touchstart")) {
           abuse = openControlled;
         }
         break;
       case eTouchEnd:
         if (PopupAllowedForEvent("touchend")) {
@@ -797,17 +786,17 @@ Event::GetEventPopupControlState(WidgetE
         }
         break;
       default:
         break;
       }
     }
     break;
   case eMouseEventClass:
-    if (aEvent->mFlags.mIsTrusted &&
+    if (aEvent->IsTrusted() &&
         aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
       switch(aEvent->mMessage) {
       case eMouseUp:
         if (PopupAllowedForEvent("mouseup")) {
           abuse = openControlled;
         }
         break;
       case eMouseDown:
@@ -1056,24 +1045,24 @@ Event::GetEventName(EventMessage aEventT
 bool
 Event::DefaultPrevented(JSContext* aCx) const
 {
   MOZ_ASSERT(aCx, "JS context must be specified");
 
   NS_ENSURE_TRUE(mEvent, false);
 
   // If preventDefault() has never been called, just return false.
-  if (!mEvent->mFlags.mDefaultPrevented) {
+  if (!mEvent->DefaultPrevented()) {
     return false;
   }
 
   // If preventDefault() has been called by content, return true.  Otherwise,
   // i.e., preventDefault() has been called by chrome, return true only when
   // this is called by chrome.
-  return mEvent->mFlags.mDefaultPreventedByContent || IsChrome(aCx);
+  return mEvent->DefaultPreventedByContent() || IsChrome(aCx);
 }
 
 double
 Event::TimeStamp() const
 {
   if (!sReturnHighResTimeStamp) {
     return static_cast<double>(mEvent->time);
   }
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -182,27 +182,27 @@ public:
 
   // You MUST NOT call DefaultPrevented(JSContext*) from C++ code.  This may
   // return false even if PreventDefault() has been called.
   // See comments in its implementation for the detail.
   bool DefaultPrevented(JSContext* aCx) const;
 
   bool DefaultPrevented() const
   {
-    return mEvent->mFlags.mDefaultPrevented;
+    return mEvent->DefaultPrevented();
   }
 
   bool MultipleActionsPrevented() const
   {
     return mEvent->mFlags.mMultipleActionsPrevented;
   }
 
   bool IsTrusted() const
   {
-    return mEvent->mFlags.mIsTrusted;
+    return mEvent->IsTrusted();
   }
 
   bool IsSynthesized() const
   {
     return mEvent->mFlags.mIsSynthesizedForTests;
   }
 
   double TimeStamp() const;
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -239,17 +239,17 @@ public:
    * manager, this method calls EventListenerManager::HandleEvent().
    */
   void HandleEvent(EventChainPostVisitor& aVisitor,
                    ELMCreationDetector& aCd)
   {
     if (WantsWillHandleEvent()) {
       mTarget->WillHandleEvent(aVisitor);
     }
-    if (aVisitor.mEvent->mFlags.mPropagationStopped) {
+    if (aVisitor.mEvent->PropagationStopped()) {
       return;
     }
     if (aVisitor.mEvent->mFlags.mOnlySystemGroupDispatchInContent &&
         !aVisitor.mEvent->mFlags.mInSystemGroup &&
         !IsCurrentTargetChrome()) {
       return;
     }
     if (!mManager) {
@@ -338,17 +338,17 @@ EventTargetChainItem::HandleEventTargetC
 
   // Capture
   aVisitor.mEvent->mFlags.mInCapturePhase = true;
   aVisitor.mEvent->mFlags.mInBubblingPhase = false;
   for (uint32_t i = chainLength - 1; i > 0; --i) {
     EventTargetChainItem& item = aChain[i];
     if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
          item.ForceContentDispatch()) &&
-        !aVisitor.mEvent->mFlags.mPropagationStopped) {
+        !aVisitor.mEvent->PropagationStopped()) {
       item.HandleEvent(aVisitor, aCd);
     }
 
     if (item.GetNewTarget()) {
       // item is at anonymous boundary. Need to retarget for the child items.
       for (uint32_t j = i; j > 0; --j) {
         uint32_t childIndex = j - 1;
         EventTarget* newTarget = aChain[childIndex].GetNewTarget();
@@ -358,17 +358,17 @@ EventTargetChainItem::HandleEventTargetC
         }
       }
     }
   }
 
   // Target
   aVisitor.mEvent->mFlags.mInBubblingPhase = true;
   EventTargetChainItem& targetItem = aChain[0];
-  if (!aVisitor.mEvent->mFlags.mPropagationStopped &&
+  if (!aVisitor.mEvent->PropagationStopped() &&
       (!aVisitor.mEvent->mFlags.mNoContentDispatch ||
        targetItem.ForceContentDispatch())) {
     targetItem.HandleEvent(aVisitor, aCd);
   }
   if (aVisitor.mEvent->mFlags.mInSystemGroup) {
     targetItem.PostHandleEvent(aVisitor);
   }
 
@@ -381,17 +381,17 @@ EventTargetChainItem::HandleEventTargetC
       // Item is at anonymous boundary. Need to retarget for the current item
       // and for parent items.
       aVisitor.mEvent->target = newTarget;
     }
 
     if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
       if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
            item.ForceContentDispatch()) &&
-          !aVisitor.mEvent->mFlags.mPropagationStopped) {
+          !aVisitor.mEvent->PropagationStopped()) {
         item.HandleEvent(aVisitor, aCd);
       }
       if (aVisitor.mEvent->mFlags.mInSystemGroup) {
         item.PostHandleEvent(aVisitor);
       }
     }
   }
   aVisitor.mEvent->mFlags.mInBubblingPhase = false;
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -1185,18 +1185,21 @@ EventListenerManager::GetDocShellForTarg
 void
 EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
                                           WidgetEvent* aEvent,
                                           nsIDOMEvent** aDOMEvent,
                                           EventTarget* aCurrentTarget,
                                           nsEventStatus* aEventStatus)
 {
   //Set the value of the internal PreventDefault flag properly based on aEventStatus
-  if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
-    aEvent->mFlags.mDefaultPrevented = true;
+  if (!aEvent->DefaultPrevented() &&
+      *aEventStatus == nsEventStatus_eConsumeNoDefault) {
+    // Assume that if only aEventStatus claims that the event has already been
+    // consumed, the consumer is default event handler.
+    aEvent->PreventDefault();
   }
 
   Maybe<nsAutoPopupStatePusher> popupStatePusher;
   if (mIsMainThreadELM) {
     popupStatePusher.emplace(Event::GetEventPopupControlState(aEvent, *aDOMEvent));
   }
 
   bool hasListener = false;
@@ -1214,18 +1217,17 @@ EventListenerManager::HandleEventInterna
       Listener* listener = &iter.GetNext();
       // Check that the phase is same in event and event listener.
       // Handle only trusted events, except when listener permits untrusted events.
       if (ListenerCanHandle(listener, aEvent, eventMessage)) {
         hasListener = true;
         hasListenerForCurrentGroup = hasListenerForCurrentGroup ||
           listener->mFlags.mInSystemGroup == aEvent->mFlags.mInSystemGroup;
         if (listener->IsListening(aEvent) &&
-            (aEvent->mFlags.mIsTrusted ||
-             listener->mFlags.mAllowUntrustedEvents)) {
+            (aEvent->IsTrusted() || listener->mFlags.mAllowUntrustedEvents)) {
           if (!*aDOMEvent) {
             // This is tiny bit slow, but happens only once per event.
             nsCOMPtr<EventTarget> et =
               do_QueryInterface(aEvent->originalTarget);
             RefPtr<Event> event = EventDispatcher::CreateEvent(et, aPresContext,
                                                                aEvent,
                                                                EmptyString());
             event.forget(aDOMEvent);
@@ -1301,17 +1303,17 @@ EventListenerManager::HandleEventInterna
 
   aEvent->currentTarget = nullptr;
 
   if (mIsMainThreadELM && !hasListener) {
     mNoListenerForEvent = aEvent->mMessage;
     mNoListenerForEventAtom = aEvent->userType;
   }
 
-  if (aEvent->mFlags.mDefaultPrevented) {
+  if (aEvent->DefaultPrevented()) {
     *aEventStatus = nsEventStatus_eConsumeNoDefault;
   }
 }
 
 void
 EventListenerManager::Disconnect()
 {
   mTarget = nullptr;
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -323,17 +323,17 @@ public:
   void RemoveEventHandler(nsIAtom *aName, const nsAString& aTypeString);
 
   void HandleEvent(nsPresContext* aPresContext,
                    WidgetEvent* aEvent, 
                    nsIDOMEvent** aDOMEvent,
                    dom::EventTarget* aCurrentTarget,
                    nsEventStatus* aEventStatus)
   {
-    if (mListeners.IsEmpty() || aEvent->mFlags.mPropagationStopped) {
+    if (mListeners.IsEmpty() || aEvent->PropagationStopped()) {
       return;
     }
 
     if (!mMayHaveCapturingListeners && !aEvent->mFlags.mInBubblingPhase) {
       return;
     }
 
     if (!mMayHaveSystemGroupListeners && aEvent->mFlags.mInSystemGroup) {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -523,17 +523,17 @@ EventStateManager::PreHandleEvent(nsPres
                    "aTargetFrame should be related with aTargetContent");
 
   mCurrentTarget = aTargetFrame;
   mCurrentTargetContent = nullptr;
 
   // Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
   // a page when user is not active doesn't change the state to active.
   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
-  if (aEvent->mFlags.mIsTrusted &&
+  if (aEvent->IsTrusted() &&
       ((mouseEvent && mouseEvent->IsReal() &&
         IsMessageMouseUserActivity(mouseEvent->mMessage)) ||
        aEvent->mClass == eWheelEventClass ||
        aEvent->mClass == ePointerEventClass ||
        aEvent->mClass == eTouchEventClass ||
        aEvent->mClass == eKeyboardEventClass ||
        IsMessageGamepadUserActivity(aEvent->mMessage))) {
     if (gMouseOrKeyboardEventCounter == 0) {
@@ -571,17 +571,17 @@ EventStateManager::PreHandleEvent(nsPres
   if (aEvent->HasDragEventMessage() && sIsPointerLocked) {
     NS_ASSERTION(sIsPointerLocked,
       "sIsPointerLocked is true. Drag events should be suppressed when "
       "the pointer is locked.");
   }
 #endif
   // Store last known screenPoint and clientPoint so pointer lock
   // can use these values as constants.
-  if (aEvent->mFlags.mIsTrusted &&
+  if (aEvent->IsTrusted() &&
       ((mouseEvent && mouseEvent->IsReal()) ||
        aEvent->mClass == eWheelEventClass) &&
       !sIsPointerLocked) {
     sLastScreenPoint =
       Event::GetScreenCoords(aPresContext, aEvent, aEvent->refPoint);
     sLastClientPoint =
       Event::GetClientCoords(aPresContext, aEvent, aEvent->refPoint, CSSIntPoint(0, 0));
   }
@@ -637,34 +637,34 @@ EventStateManager::PreHandleEvent(nsPres
   }
   case eMouseEnterIntoWidget:
     // In some cases on e10s eMouseEnterIntoWidget
     // event was sent twice into child process of content.
     // (From specific widget code (sending is not permanent) and
     // from ESM::DispatchMouseOrPointerEvent (sending is permanent)).
     // Flag mNoCrossProcessBoundaryForwarding helps to
     // suppress sending accidental event from widget code.
-    aEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
+    aEvent->StopCrossProcessForwarding();
     break;
   case eMouseExitFromWidget:
     // If this is a remote frame, we receive eMouseExitFromWidget from the
     // parent the mouse exits our content. Since the parent may update the
     // cursor while the mouse is outside our frame, and since PuppetWidget
     // caches the current cursor internally, re-entering our content (say from
     // over a window edge) wont update the cursor if the cached value and the
     // current cursor match. So when the mouse exits a remote frame, clear the
     // cached widget cursor so a proper update will occur when the mouse
     // re-enters.
     if (XRE_IsContentProcess()) {
       ClearCachedWidgetCursor(mCurrentTarget);
     }
 
     // Flag helps to suppress double event sending into process of content.
     // For more information see comment above, at eMouseEnterIntoWidget case.
-    aEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
+    aEvent->StopCrossProcessForwarding();
 
     // If the event is not a top-level window exit, then it's not
     // really an exit --- we may have traversed widget boundaries but
     // we're still in our toplevel window.
     if (mouseEvent->exit != WidgetMouseEvent::eTopLevel) {
       // Treat it as a synthetic move so we don't generate spurious
       // "exit" or "move" events.  Any necessary "out" or "over" events
       // will be generated by GenerateMouseEnterExit
@@ -728,20 +728,20 @@ EventStateManager::PreHandleEvent(nsPres
       if (keyEvent->IsOS())
         modifierMask |= NS_MODIFIER_OS;
 
       // Prevent keyboard scrolling while an accesskey modifier is in use.
       if (modifierMask &&
           (modifierMask == Prefs::ChromeAccessModifierMask() ||
            modifierMask == Prefs::ContentAccessModifierMask())) {
         AutoTArray<uint32_t, 10> accessCharCodes;
-        nsContentUtils::GetAccessKeyCandidates(keyEvent, accessCharCodes);
+        keyEvent->GetAccessKeyCandidates(accessCharCodes);
 
         if (HandleAccessKey(aPresContext, accessCharCodes,
-                            keyEvent->mFlags.mIsTrusted, modifierMask)) {
+                            keyEvent->IsTrusted(), modifierMask)) {
           *aStatus = nsEventStatus_eConsumeNoDefault;
         }
       }
     }
     // then fall through...
     MOZ_FALLTHROUGH;
   case eBeforeKeyDown:
   case eKeyDown:
@@ -766,17 +766,17 @@ EventStateManager::PreHandleEvent(nsPres
         IMEStateManager::GetTextCompositionFor(aPresContext);
       aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
     }
     break;
   case eWheel:
   case eWheelOperationStart:
   case eWheelOperationEnd:
     {
-      NS_ASSERTION(aEvent->mFlags.mIsTrusted,
+      NS_ASSERTION(aEvent->IsTrusted(),
                    "Untrusted wheel event shouldn't be here");
 
       nsIContent* content = GetFocusedContent();
       if (content) {
         mCurrentTargetContent = content;
       }
 
       if (aEvent->mMessage != eWheel) {
@@ -811,17 +811,17 @@ EventStateManager::PreHandleEvent(nsPres
   case eContentCommandRedo:
   case eContentCommandPasteTransferable:
     DoContentCommandEvent(aEvent->AsContentCommandEvent());
     break;
   case eContentCommandScroll:
     DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
     break;
   case eCompositionStart:
-    if (aEvent->mFlags.mIsTrusted) {
+    if (aEvent->IsTrusted()) {
       // If the event is trusted event, set the selected text to data of
       // composition event.
       WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
       WidgetQueryContentEvent selectedText(true, eQuerySelectedText,
                                            compositionEvent->widget);
       HandleQueryContentEvent(&selectedText);
       NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
       compositionEvent->mData = selectedText.mReply.mString;
@@ -1371,17 +1371,17 @@ EventStateManager::HandleCrossProcessEve
 // is a one-shot that will be cancelled when the user moves enough to fire
 // a drag.
 //
 void
 EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
                                         nsIFrame* inDownFrame,
                                         WidgetGUIEvent* inMouseDownEvent)
 {
-  if (!inMouseDownEvent->mFlags.mIsTrusted ||
+  if (!inMouseDownEvent->IsTrusted() ||
       IsRemoteTarget(mGestureDownContent) ||
       sIsPointerLocked) {
     return;
   }
 
   // just to be anal (er, safe)
   if (mClickHoldTimer) {
     mClickHoldTimer->Cancel();
@@ -1729,21 +1729,20 @@ EventStateManager::GenerateDragGesture(n
       // Use our targetContent, now that we've determined it, as the
       // parent object of the DataTransfer.
       dataTransfer->SetParentObject(targetContent);
 
       sLastDragOverFrame = nullptr;
       nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
 
       // get the widget from the target frame
-      WidgetDragEvent startEvent(aEvent->mFlags.mIsTrusted,
-                                 eDragStart, widget);
+      WidgetDragEvent startEvent(aEvent->IsTrusted(), eDragStart, widget);
       FillInEventFromGestureDown(&startEvent);
 
-      WidgetDragEvent gestureEvent(aEvent->mFlags.mIsTrusted,
+      WidgetDragEvent gestureEvent(aEvent->IsTrusted(),
                                    eLegacyDragGesture, widget);
       FillInEventFromGestureDown(&gestureEvent);
 
       startEvent.dataTransfer = gestureEvent.dataTransfer = dataTransfer;
       startEvent.inputSource = gestureEvent.inputSource = aEvent->inputSource;
 
       // Dispatch to the DOM. By setting mCurrentTarget we are faking
       // out the ESM and telling it that the current target frame is
@@ -1789,17 +1788,17 @@ EventStateManager::GenerateDragGesture(n
       // change during the drag.
       dataTransfer->SetReadOnly();
 
       if (status != nsEventStatus_eConsumeNoDefault) {
         bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
                                               targetContent, selection);
         if (dragStarted) {
           sActiveESM = nullptr;
-          aEvent->mFlags.mPropagationStopped = true;
+          aEvent->StopPropagation();
         }
       }
 
       // Note that frame event handling doesn't care about eLegacyDragGesture,
       // which is just as well since we don't really know which frame to
       // send it to
 
       // Reset mCurretTargetContent to what it was
@@ -2220,17 +2219,17 @@ EventStateManager::DispatchLegacyMouseSc
   // 1. Vertical scroll
   // 2. Vertical pixel scroll (even if #1 isn't consumed)
   // 3. Horizontal scroll (even if #1 and/or #2 are consumed)
   // 4. Horizontal pixel scroll (even if #3 isn't consumed)
 
   nsWeakFrame targetFrame(aTargetFrame);
 
   MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault &&
-             !aEvent->mFlags.mDefaultPrevented,
+             !aEvent->DefaultPrevented(),
              "If you make legacy events dispatched for default prevented wheel "
              "event, you need to initialize stateX and stateY");
   EventState stateX, stateY;
   if (scrollDeltaY) {
     SendLineScrollEvent(aTargetFrame, aEvent, stateY,
                         scrollDeltaY, DELTA_DIRECTION_Y);
     if (!targetFrame.IsAlive()) {
       *aStatus = nsEventStatus_eConsumeNoDefault;
@@ -2260,21 +2259,24 @@ EventStateManager::DispatchLegacyMouseSc
     SendPixelScrollEvent(aTargetFrame, aEvent, stateX,
                          pixelDeltaX, DELTA_DIRECTION_X);
     if (!targetFrame.IsAlive()) {
       *aStatus = nsEventStatus_eConsumeNoDefault;
       return;
     }
   }
 
-  if (stateY.mDefaultPrevented || stateX.mDefaultPrevented) {
+  if (stateY.mDefaultPrevented) {
     *aStatus = nsEventStatus_eConsumeNoDefault;
-    aEvent->mFlags.mDefaultPrevented = true;
-    aEvent->mFlags.mDefaultPreventedByContent |=
-      stateY.mDefaultPreventedByContent || stateX.mDefaultPreventedByContent;
+    aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
+  }
+
+  if (stateX.mDefaultPrevented) {
+    *aStatus = nsEventStatus_eConsumeNoDefault;
+    aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
   }
 }
 
 void
 EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
                                        WidgetWheelEvent* aEvent,
                                        EventState& aState,
                                        int32_t aDelta,
@@ -2285,17 +2287,17 @@ EventStateManager::SendLineScrollEvent(n
     targetContent = GetFocusedContent();
   if (!targetContent)
     return;
 
   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
     targetContent = targetContent->GetParent();
   }
 
-  WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted,
+  WidgetMouseScrollEvent event(aEvent->IsTrusted(),
                                eLegacyMouseLineOrPageScroll, aEvent->widget);
   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
   event.refPoint = aEvent->refPoint;
   event.widget = aEvent->widget;
   event.time = aEvent->time;
   event.timeStamp = aEvent->timeStamp;
   event.modifiers = aEvent->modifiers;
@@ -2303,18 +2305,18 @@ EventStateManager::SendLineScrollEvent(n
   event.isHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
   event.delta = aDelta;
   event.inputSource = aEvent->inputSource;
 
   nsEventStatus status = nsEventStatus_eIgnore;
   EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
                             &event, nullptr, &status);
   aState.mDefaultPrevented =
-    event.mFlags.mDefaultPrevented || status == nsEventStatus_eConsumeNoDefault;
-  aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent;
+    event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
+  aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
 }
 
 void
 EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
                                         WidgetWheelEvent* aEvent,
                                         EventState& aState,
                                         int32_t aPixelDelta,
                                         DeltaDirection aDeltaDirection)
@@ -2325,17 +2327,17 @@ EventStateManager::SendPixelScrollEvent(
     if (!targetContent)
       return;
   }
 
   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
     targetContent = targetContent->GetParent();
   }
 
-  WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted,
+  WidgetMouseScrollEvent event(aEvent->IsTrusted(),
                                eLegacyMousePixelScroll, aEvent->widget);
   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
   event.refPoint = aEvent->refPoint;
   event.widget = aEvent->widget;
   event.time = aEvent->time;
   event.timeStamp = aEvent->timeStamp;
   event.modifiers = aEvent->modifiers;
@@ -2343,18 +2345,18 @@ EventStateManager::SendPixelScrollEvent(
   event.isHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
   event.delta = aPixelDelta;
   event.inputSource = aEvent->inputSource;
 
   nsEventStatus status = nsEventStatus_eIgnore;
   EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
                             &event, nullptr, &status);
   aState.mDefaultPrevented =
-    event.mFlags.mDefaultPrevented || status == nsEventStatus_eConsumeNoDefault;
-  aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent;
+    event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
+  aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
 }
 
 nsIFrame*
 EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
                                        WidgetWheelEvent* aEvent,
                                        ComputeScrollTargetOptions aOptions)
 {
   return ComputeScrollTarget(aTargetFrame, aEvent->deltaX, aEvent->deltaY,
@@ -3126,31 +3128,31 @@ EventStateManager::PostHandleEvent(nsPre
       if (shell) {
         RefPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
         frameSelection->SetDragState(false);
       }
     }
     break;
   case eWheelOperationEnd:
     {
-      MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
+      MOZ_ASSERT(aEvent->IsTrusted());
       ScrollbarsForWheel::MayInactivate();
       WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
       nsIScrollableFrame* scrollTarget =
         do_QueryFrame(ComputeScrollTarget(aTargetFrame, wheelEvent,
                                           COMPUTE_DEFAULT_ACTION_TARGET));
       if (scrollTarget) {
         scrollTarget->ScrollSnap();
       }
     }
     break;
   case eWheel:
   case eWheelOperationStart:
     {
-      MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
+      MOZ_ASSERT(aEvent->IsTrusted());
 
       if (*aStatus == nsEventStatus_eConsumeNoDefault) {
         ScrollbarsForWheel::Inactivate();
         break;
       }
 
       WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
 
@@ -3173,17 +3175,17 @@ EventStateManager::PostHandleEvent(nsPre
         // If the target has scroll-snapping points then we want to handle
         // the wheel event on the main thread even if we have APZ enabled. Do
         // so and let the APZ know that it should ignore this event. However,
         // if the wheel event is synthesized from a Mac trackpad or other device
         // that can generate additional momentum events, then we should allow
         // APZ to handle it, because it will track the velocity and predicted
         // destination from the momentum.
         if (wheelEvent->mFlags.mHandledByAPZ) {
-          wheelEvent->mFlags.mDefaultPrevented = true;
+          wheelEvent->PreventDefault();
         }
         action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
       } else if (wheelEvent->mFlags.mHandledByAPZ) {
         action = WheelPrefs::ACTION_NONE;
       } else {
         action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
       }
       switch (action) {
@@ -3419,18 +3421,17 @@ EventStateManager::PostHandleEvent(nsPre
     {
       // now fire the dragdrop event, for compatibility with XUL
       if (mCurrentTarget && nsEventStatus_eConsumeNoDefault != *aStatus) {
         nsCOMPtr<nsIContent> targetContent;
         mCurrentTarget->GetContentForEvent(aEvent,
                                            getter_AddRefs(targetContent));
 
         nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
-        WidgetDragEvent event(aEvent->mFlags.mIsTrusted,
-                              eLegacyDragDrop, widget);
+        WidgetDragEvent event(aEvent->IsTrusted(), eLegacyDragDrop, widget);
 
         WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
         event.refPoint = mouseEvent->refPoint;
         if (mouseEvent->widget) {
           event.refPoint += mouseEvent->widget->WidgetToScreenOffset();
         }
         event.refPoint -= widget->WidgetToScreenOffset();
         event.modifiers = mouseEvent->modifiers;
@@ -3846,31 +3847,31 @@ CreateMouseOrPointerWidgetEvent(WidgetMo
 {
   WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
   if (sourcePointer) {
     PROFILER_LABEL("Input", "DispatchPointerEvent",
       js::ProfileEntry::Category::EVENTS);
 
     nsAutoPtr<WidgetPointerEvent> newPointerEvent;
     newPointerEvent =
-      new WidgetPointerEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
+      new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage,
                              aMouseEvent->widget);
     newPointerEvent->isPrimary = sourcePointer->isPrimary;
     newPointerEvent->pointerId = sourcePointer->pointerId;
     newPointerEvent->width = sourcePointer->width;
     newPointerEvent->height = sourcePointer->height;
     newPointerEvent->inputSource = sourcePointer->inputSource;
     newPointerEvent->relatedTarget =
       nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId)
         ? nullptr
         : aRelatedContent;
     aNewEvent = newPointerEvent.forget();
   } else {
     aNewEvent =
-      new WidgetMouseEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
+      new WidgetMouseEvent(aMouseEvent->IsTrusted(), aMessage,
                            aMouseEvent->widget, WidgetMouseEvent::eReal);
     aNewEvent->relatedTarget = aRelatedContent;
   }
   aNewEvent->refPoint = aMouseEvent->refPoint;
   aNewEvent->modifiers = aMouseEvent->modifiers;
   aNewEvent->button = aMouseEvent->button;
   aNewEvent->buttons = aMouseEvent->buttons;
   aNewEvent->pressure = aMouseEvent->pressure;
@@ -4228,17 +4229,17 @@ EventStateManager::GenerateMouseEnterExi
           // we've dispatched a synthetic mouse movement, so we can cancel it
           // in the other branch here.
           sSynthCenteringPoint = center;
           aMouseEvent->widget->SynthesizeNativeMouseMove(
             center + aMouseEvent->widget->WidgetToScreenOffset(), nullptr);
         } else if (aMouseEvent->refPoint == sSynthCenteringPoint) {
           // This is the "synthetic native" event we dispatched to re-center the
           // pointer. Cancel it so we don't expose the centering move to content.
-          aMouseEvent->mFlags.mPropagationStopped = true;
+          aMouseEvent->StopPropagation();
           // Clear sSynthCenteringPoint so we don't cancel other events
           // targeted at the center.
           sSynthCenteringPoint = kInvalidRefPoint;
         }
       } else if (sLastRefPoint == kInvalidRefPoint) {
         // We don't have a valid previous mousemove refPoint. This is either
         // the first move we've encountered, or the mouse has just re-entered
         // the application window. We should report (0,0) movement for this
@@ -4472,18 +4473,17 @@ void
 EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
                                        WidgetDragEvent* aDragEvent,
                                        EventMessage aMessage,
                                        nsIContent* aRelatedTarget,
                                        nsIContent* aTargetContent,
                                        nsWeakFrame& aTargetFrame)
 {
   nsEventStatus status = nsEventStatus_eIgnore;
-  WidgetDragEvent event(aDragEvent->mFlags.mIsTrusted, aMessage,
-                        aDragEvent->widget);
+  WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->widget);
   event.refPoint = aDragEvent->refPoint;
   event.modifiers = aDragEvent->modifiers;
   event.buttons = aDragEvent->buttons;
   event.relatedTarget = aRelatedTarget;
   event.inputSource = aDragEvent->inputSource;
 
   mCurrentTargetContent = aTargetContent;
 
@@ -4627,17 +4627,17 @@ EventStateManager::CheckForAndDispatchCl
     if (aEvent->widget && !aEvent->widget->IsEnabled()) {
       return ret;
     }
     //fire click
     bool notDispatchToContents =
      (aEvent->button == WidgetMouseEvent::eMiddleButton ||
       aEvent->button == WidgetMouseEvent::eRightButton);
 
-    WidgetMouseEvent event(aEvent->mFlags.mIsTrusted, eMouseClick,
+    WidgetMouseEvent event(aEvent->IsTrusted(), eMouseClick,
                            aEvent->widget, WidgetMouseEvent::eReal);
     event.refPoint = aEvent->refPoint;
     event.clickCount = aEvent->clickCount;
     event.modifiers = aEvent->modifiers;
     event.buttons = aEvent->buttons;
     event.time = aEvent->time;
     event.timeStamp = aEvent->timeStamp;
     event.mFlags.mNoContentDispatch = notDispatchToContents;
@@ -4661,17 +4661,17 @@ EventStateManager::CheckForAndDispatchCl
 
       // HandleEvent clears out mCurrentTarget which we might need again
       nsWeakFrame currentTarget = mCurrentTarget;
       ret = presShell->HandleEventWithTarget(&event, currentTarget,
                                              mouseContent, aStatus);
       if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2 &&
           mouseContent && mouseContent->IsInComposedDoc()) {
         //fire double click
-        WidgetMouseEvent event2(aEvent->mFlags.mIsTrusted, eMouseDoubleClick,
+        WidgetMouseEvent event2(aEvent->IsTrusted(), eMouseDoubleClick,
                                 aEvent->widget, WidgetMouseEvent::eReal);
         event2.refPoint = aEvent->refPoint;
         event2.clickCount = aEvent->clickCount;
         event2.modifiers = aEvent->modifiers;
         event2.buttons = aEvent->buttons;
         event2.mFlags.mNoContentDispatch = notDispatchToContents;
         event2.button = aEvent->button;
         event2.inputSource = aEvent->inputSource;
@@ -5889,17 +5889,17 @@ AutoHandlingUserInputStatePusher::AutoHa
   if (!aIsHandlingUserInput) {
     return;
   }
   EventStateManager::StartHandlingUserInput();
   if (mIsMouseDown) {
     nsIPresShell::SetCapturingContent(nullptr, 0);
     nsIPresShell::AllowMouseCapture(true);
   }
-  if (!aDocument || !aEvent || !aEvent->mFlags.mIsTrusted) {
+  if (!aDocument || !aEvent || !aEvent->IsTrusted()) {
     return;
   }
   mResetFMMouseButtonHandlingState =
     (aEvent->mMessage == eMouseDown || aEvent->mMessage == eMouseUp);
   if (mResetFMMouseButtonHandlingState) {
     nsFocusManager* fm = nsFocusManager::GetFocusManager();
     NS_ENSURE_TRUE_VOID(fm);
     // If it's in modal state, mouse button event handling may be nested.
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -751,18 +751,18 @@ IMEContentObserver::HandleQueryContentEv
 
 bool
 IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
                                        WidgetMouseEvent* aMouseEvent)
 {
   if (!mUpdatePreference.WantMouseButtonEventOnChar()) {
     return false;
   }
-  if (!aMouseEvent->mFlags.mIsTrusted ||
-      aMouseEvent->mFlags.mDefaultPrevented ||
+  if (!aMouseEvent->IsTrusted() ||
+      aMouseEvent->DefaultPrevented() ||
       !aMouseEvent->widget) {
     return false;
   }
   // Now, we need to notify only mouse down and mouse up event.
   switch (aMouseEvent->mMessage) {
     case eMouseUp:
     case eMouseDown:
       break;
@@ -818,17 +818,19 @@ IMEContentObserver::OnMouseButtonEvent(n
   notification.mMouseButtonEventData.mModifiers = aMouseEvent->modifiers;
 
   nsresult rv = IMEStateManager::NotifyIME(notification, mWidget);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
   bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
-  aMouseEvent->mFlags.mDefaultPrevented = consumed;
+  if (consumed) {
+    aMouseEvent->PreventDefault();
+  }
   return consumed;
 }
 
 void
 IMEContentObserver::CharacterDataWillChange(nsIDocument* aDocument,
                                             nsIContent* aContent,
                                             CharacterDataChangeInfo* aInfo)
 {
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -1159,18 +1159,18 @@ IMEStateManager::DispatchCompositionEven
      aCompositionEvent->widget.get(),
      aCompositionEvent->widget->GetNativeIMEContext().mRawNativeIMEContext,
      aCompositionEvent->widget->GetNativeIMEContext().mOriginProcessID,
      GetBoolName(aCompositionEvent->widget->Destroyed()),
      GetBoolName(aCompositionEvent->mFlags.mIsTrusted),
      GetBoolName(aCompositionEvent->mFlags.mPropagationStopped),
      GetBoolName(aIsSynthesized), tabParent.get()));
 
-  if (!aCompositionEvent->mFlags.mIsTrusted ||
-      aCompositionEvent->mFlags.mPropagationStopped) {
+  if (!aCompositionEvent->IsTrusted() ||
+      aCompositionEvent->PropagationStopped()) {
     return;
   }
 
   MOZ_ASSERT(aCompositionEvent->mMessage != eCompositionUpdate,
              "compositionupdate event shouldn't be dispatched manually");
 
   EnsureTextCompositionArray();
 
@@ -1256,17 +1256,17 @@ IMEStateManager::HandleSelectionEvent(ns
     ("ISM: IMEStateManager::HandleSelectionEvent(aPresContext=0x%p, "
      "aEventTargetContent=0x%p, aSelectionEvent={ mMessage=%s, "
      "mFlags={ mIsTrusted=%s } }), tabParent=%p",
      aPresContext, aEventTargetContent,
      ToChar(aSelectionEvent->mMessage),
      GetBoolName(aSelectionEvent->mFlags.mIsTrusted),
      tabParent.get()));
 
-  if (!aSelectionEvent->mFlags.mIsTrusted) {
+  if (!aSelectionEvent->IsTrusted()) {
     return;
   }
 
   RefPtr<TextComposition> composition = sTextCompositions ?
     sTextCompositions->GetCompositionFor(aSelectionEvent->widget) : nullptr;
   if (composition) {
     // When there is a composition, TextComposition should guarantee that the
     // selection event will be handled in same target as composition events.
@@ -1298,17 +1298,17 @@ IMEStateManager::OnCompositionEventDisca
      aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
      aCompositionEvent->mNativeIMEContext.mOriginProcessID,
      aCompositionEvent->widget.get(),
      aCompositionEvent->widget->GetNativeIMEContext().mRawNativeIMEContext,
      aCompositionEvent->widget->GetNativeIMEContext().mOriginProcessID,
      GetBoolName(aCompositionEvent->widget->Destroyed()),
      GetBoolName(aCompositionEvent->mFlags.mIsTrusted)));
 
-  if (!aCompositionEvent->mFlags.mIsTrusted) {
+  if (!aCompositionEvent->IsTrusted()) {
     return;
   }
 
   // Ignore compositionstart for now because sTextCompositions may not have
   // been created yet.
   if (aCompositionEvent->mMessage == eCompositionStart) {
     return;
   }
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -113,17 +113,17 @@ TextComposition::CloneAndDispatchAs(
                    nsEventStatus* aStatus,
                    EventDispatchingCallback* aCallBack)
 {
   MOZ_RELEASE_ASSERT(!mTabParent);
 
   MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->widget),
              "Should be called only when it's safe to dispatch an event");
 
-  WidgetCompositionEvent compositionEvent(aCompositionEvent->mFlags.mIsTrusted,
+  WidgetCompositionEvent compositionEvent(aCompositionEvent->IsTrusted(),
                                           aMessage, aCompositionEvent->widget);
   compositionEvent.time = aCompositionEvent->time;
   compositionEvent.timeStamp = aCompositionEvent->timeStamp;
   compositionEvent.mData = aCompositionEvent->mData;
   compositionEvent.mNativeIMEContext = aCompositionEvent->mNativeIMEContext;
   compositionEvent.mOriginalMessage = aCompositionEvent->mMessage;
   compositionEvent.mFlags.mIsSynthesizedForTests =
     aCompositionEvent->mFlags.mIsSynthesizedForTests;
@@ -154,17 +154,17 @@ TextComposition::DispatchEvent(WidgetCom
 
 void
 TextComposition::OnCompositionEventDiscarded(
                    WidgetCompositionEvent* aCompositionEvent)
 {
   // Note that this method is never called for synthesized events for emulating
   // commit or cancel composition.
 
-  MOZ_ASSERT(aCompositionEvent->mFlags.mIsTrusted,
+  MOZ_ASSERT(aCompositionEvent->IsTrusted(),
              "Shouldn't be called with untrusted event");
 
   if (mTabParent) {
     // The composition event should be discarded in the child process too.
     Unused << mTabParent->SendCompositionEvent(*aCompositionEvent);
   }
 
   // XXX If composition events are discarded, should we dispatch them with
@@ -238,17 +238,17 @@ TextComposition::DispatchCompositionEven
                    nsEventStatus* aStatus,
                    EventDispatchingCallback* aCallBack,
                    bool aIsSynthesized)
 {
   // If the content is a container of TabParent, composition should be in the
   // remote process.
   if (mTabParent) {
     Unused << mTabParent->SendCompositionEvent(*aCompositionEvent);
-    aCompositionEvent->mFlags.mPropagationStopped = true;
+    aCompositionEvent->StopPropagation();
     if (aCompositionEvent->CausesDOMTextEvent()) {
       mLastData = aCompositionEvent->mData;
       mLastRanges = aCompositionEvent->mRanges;
       // Although, the composition event hasn't been actually handled yet,
       // emulate an editor to be handling the composition event.
       EditorWillHandleCompositionChangeEvent(aCompositionEvent);
       EditorDidHandleCompositionChangeEvent();
     }
@@ -406,17 +406,17 @@ void
 TextComposition::HandleSelectionEvent(nsPresContext* aPresContext,
                                       TabParent* aTabParent,
                                       WidgetSelectionEvent* aSelectionEvent)
 {
   // If the content is a container of TabParent, composition should be in the
   // remote process.
   if (aTabParent) {
     Unused << aTabParent->SendSelectionEvent(*aSelectionEvent);
-    aSelectionEvent->mFlags.mPropagationStopped = true;
+    aSelectionEvent->StopPropagation();
     return;
   }
 
   ContentEventHandler handler(aPresContext);
   AutoRestore<bool> saveHandlingSelectionEvent(sHandlingSelectionEvent);
   sHandlingSelectionEvent = true;
   // XXX During setting selection, a selection listener may change selection
   //     again.  In such case, sHandlingSelectionEvent doesn't indicate if
--- a/dom/events/UIEvent.h
+++ b/dom/events/UIEvent.h
@@ -90,17 +90,17 @@ public:
   }
 
   already_AddRefed<nsINode> GetRangeParent();
 
   int32_t RangeOffset() const;
 
   bool CancelBubble() const
   {
-    return mEvent->mFlags.mPropagationStopped;
+    return mEvent->PropagationStopped();
   }
 
   bool IsChar() const;
 
 protected:
   ~UIEvent() {}
 
   // Internal helper functions
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -287,28 +287,28 @@ HTMLButtonElement::PostHandleEvent(Event
         {
           // For backwards compat, trigger buttons with space or enter
           // (bug 25300)
           WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
           if ((keyEvent->keyCode == NS_VK_RETURN &&
                eKeyPress == aVisitor.mEvent->mMessage) ||
               (keyEvent->keyCode == NS_VK_SPACE &&
                eKeyUp == aVisitor.mEvent->mMessage)) {
-            DispatchSimulatedClick(this, aVisitor.mEvent->mFlags.mIsTrusted,
+            DispatchSimulatedClick(this, aVisitor.mEvent->IsTrusted(),
                                    aVisitor.mPresContext);
             aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
           }
         }
         break;
 
       case eMouseDown:
         {
           WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
           if (mouseEvent->button == WidgetMouseEvent::eLeftButton) {
-            if (mouseEvent->mFlags.mIsTrusted) {
+            if (mouseEvent->IsTrusted()) {
               EventStateManager* esm =
                 aVisitor.mPresContext->EventStateManager();
               EventStateManager::SetActiveManager(
                 static_cast<EventStateManager*>(esm), this);
             }
             nsIFocusManager* fm = nsFocusManager::GetFocusManager();
             if (fm) {
               uint32_t flags = nsIFocusManager::FLAG_BYMOUSE |
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -520,17 +520,17 @@ HTMLFormElement::WillHandleEvent(EventCh
 {
   // If this is the bubble stage and there is a nested form below us which
   // received a submit event we do *not* want to handle the submit event
   // for this form too.
   if ((aVisitor.mEvent->mMessage == eFormSubmit ||
        aVisitor.mEvent->mMessage == eFormReset) &&
       aVisitor.mEvent->mFlags.mInBubblingPhase &&
       aVisitor.mEvent->originalTarget != static_cast<nsIContent*>(this)) {
-    aVisitor.mEvent->mFlags.mPropagationStopped = true;
+    aVisitor.mEvent->StopPropagation();
   }
   return NS_OK;
 }
 
 nsresult
 HTMLFormElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
   if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) {
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3333,18 +3333,17 @@ HTMLInputElement::PreHandleEvent(EventCh
     // Just as nsGenericHTMLFormElementWithState::PreHandleEvent calls
     // nsIFormControlFrame::SetFocus, we handle focus here.
     nsIFrame* frame = GetPrimaryFrame();
     if (frame) {
       frame->InvalidateFrameSubtree();
     }
   }
 
-  if (mType == NS_FORM_INPUT_NUMBER &&
-      aVisitor.mEvent->mFlags.mIsTrusted) {
+  if (mType == NS_FORM_INPUT_NUMBER && aVisitor.mEvent->IsTrusted()) {
     if (mNumberControlSpinnerIsSpinning) {
       // If the timer is running the user has depressed the mouse on one of the
       // spin buttons. If the mouse exits the button we either want to reverse
       // the direction of spin if it has moved over the other button, or else
       // we want to end the spin. We do this here (rather than in
       // PostHandleEvent) because we don't want to let content preventDefault()
       // the end of the spin.
       if (aVisitor.mEvent->mMessage == eMouseMove) {
@@ -3419,17 +3418,17 @@ HTMLInputElement::PreHandleEvent(EventCh
     }
   }
 
   nsresult rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
 
   // We do this after calling the base class' PreHandleEvent so that
   // nsIContent::PreHandleEvent doesn't reset any change we make to mCanHandle.
   if (mType == NS_FORM_INPUT_NUMBER &&
-      aVisitor.mEvent->mFlags.mIsTrusted  &&
+      aVisitor.mEvent->IsTrusted()  &&
       aVisitor.mEvent->originalTarget != this) {
     // <input type=number> has an anonymous <input type=text> descendant. If
     // 'input' or 'change' events are fired at that text control then we need
     // to do some special handling here.
     HTMLInputElement* textControl = nullptr;
     nsNumberControlFrame* numberControlFrame =
       do_QueryFrame(GetPrimaryFrame());
     if (numberControlFrame) {
@@ -3694,17 +3693,17 @@ HTMLInputElement::MaybeInitPickers(Event
 {
   // Open a file picker when we receive a click on a <input type='file'>, or
   // open a color picker when we receive a click on a <input type='color'>.
   // A click is handled in the following cases:
   // - preventDefault() has not been called (or something similar);
   // - it's the left mouse button.
   // We do not prevent non-trusted click because authors can already use
   // .click(). However, the pickers will follow the rules of popup-blocking.
-  if (aVisitor.mEvent->mFlags.mDefaultPrevented) {
+  if (aVisitor.mEvent->DefaultPrevented()) {
     return NS_OK;
   }
   WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
   if (!(mouseEvent && mouseEvent->IsLeftClickEvent())) {
     return NS_OK;
   }
   if (mType == NS_FORM_INPUT_FILE) {
     // If the user clicked on the "Choose folder..." button we open the
@@ -3868,34 +3867,34 @@ HTMLInputElement::PostHandleEvent(EventC
 #endif
     }
   }
 
   if (NS_SUCCEEDED(rv)) {
     WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
     if (mType ==  NS_FORM_INPUT_NUMBER &&
         keyEvent && keyEvent->mMessage == eKeyPress &&
-        aVisitor.mEvent->mFlags.mIsTrusted &&
+        aVisitor.mEvent->IsTrusted() &&
         (keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) &&
         !(keyEvent->IsShift() || keyEvent->IsControl() ||
           keyEvent->IsAlt() || keyEvent->IsMeta() ||
           keyEvent->IsAltGraph() || keyEvent->IsFn() ||
           keyEvent->IsOS())) {
       // We handle the up/down arrow keys specially for <input type=number>.
       // On some platforms the editor for the nested text control will
       // process these keys to send the cursor to the start/end of the text
       // control and as a result aVisitor.mEventStatus will already have been
       // set to nsEventStatus_eConsumeNoDefault. However, we know that
       // whenever the up/down arrow keys cause the value of the number
       // control to change the string in the text control will change, and
       // the cursor will be moved to the end of the text control, overwriting
       // the editor's handling of up/down keypress events. For that reason we
       // just ignore aVisitor.mEventStatus here and go ahead and handle the
       // event to increase/decrease the value of the number control.
-      if (!aVisitor.mEvent->mFlags.mDefaultPreventedByContent && IsMutable()) {
+      if (!aVisitor.mEvent->DefaultPreventedByContent() && IsMutable()) {
         StepNumberControlForUserEvent(keyEvent->keyCode == NS_VK_UP ? 1 : -1);
         aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
       }
     } else if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
       switch (aVisitor.mEvent->mMessage) {
         case eFocus: {
           // see if we should select the contents of the textbox. This happens
           // for text and password fields when the field was focused by the
@@ -3946,17 +3945,17 @@ HTMLInputElement::PostHandleEvent(EventC
                 MOZ_FALLTHROUGH;
               }
               case NS_FORM_INPUT_BUTTON:
               case NS_FORM_INPUT_RESET:
               case NS_FORM_INPUT_SUBMIT:
               case NS_FORM_INPUT_IMAGE: // Bug 34418
               case NS_FORM_INPUT_COLOR:
               {
-                DispatchSimulatedClick(this, aVisitor.mEvent->mFlags.mIsTrusted,
+                DispatchSimulatedClick(this, aVisitor.mEvent->IsTrusted(),
                                        aVisitor.mPresContext);
                 aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
               } // case
             } // switch
           }
           if (aVisitor.mEvent->mMessage == eKeyPress &&
               mType == NS_FORM_INPUT_RADIO && !keyEvent->IsAlt() &&
               !keyEvent->IsControl() && !keyEvent->IsMeta()) {
@@ -3975,17 +3974,17 @@ HTMLInputElement::PostHandleEvent(EventC
                 GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
                 RefPtr<HTMLInputElement> selectedRadioButton;
                 container->GetNextRadioButton(name, isMovingBack, this,
                                               getter_AddRefs(selectedRadioButton));
                 if (selectedRadioButton) {
                   rv = selectedRadioButton->Focus();
                   if (NS_SUCCEEDED(rv)) {
                     rv = DispatchSimulatedClick(selectedRadioButton,
-                                                aVisitor.mEvent->mFlags.mIsTrusted,
+                                                aVisitor.mEvent->IsTrusted(),
                                                 aVisitor.mPresContext);
                     if (NS_SUCCEEDED(rv)) {
                       aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
                     }
                   }
                 }
               }
             }
@@ -4087,18 +4086,17 @@ HTMLInputElement::PostHandleEvent(EventC
                 mType == NS_FORM_INPUT_SUBMIT) {
               if (aVisitor.mDOMEvent) {
                 aVisitor.mDOMEvent->StopPropagation();
               } else {
                 rv = NS_ERROR_FAILURE;
               }
             }
           }
-          if (mType == NS_FORM_INPUT_NUMBER &&
-              aVisitor.mEvent->mFlags.mIsTrusted) {
+          if (mType == NS_FORM_INPUT_NUMBER && aVisitor.mEvent->IsTrusted()) {
             if (mouseEvent->button == WidgetMouseEvent::eLeftButton &&
                 !(mouseEvent->IsShift() || mouseEvent->IsControl() ||
                   mouseEvent->IsAlt() || mouseEvent->IsMeta() ||
                   mouseEvent->IsAltGraph() || mouseEvent->IsFn() ||
                   mouseEvent->IsOS())) {
               nsNumberControlFrame* numberControlFrame =
                 do_QueryFrame(GetPrimaryFrame());
               if (numberControlFrame) {
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -207,17 +207,17 @@ HTMLObjectElement::HandlePluginInstantia
     OnFocusBlurPlugin(aElement, true);
   }
 }
 
 void
 HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
                                          WidgetEvent* aEvent)
 {
-  if (!aEvent->mFlags.mIsTrusted) {
+  if (!aEvent->IsTrusted()) {
     return;
   }
   switch (aEvent->mMessage) {
     case eFocus: {
       OnFocusBlurPlugin(aElement, true);
       break;
     }
     case eBlur: {
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -2269,17 +2269,17 @@ nsGenericHTMLFormElement::AfterSetAttr(i
 
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
                                             aValue, aNotify);
 }
 
 nsresult
 nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
 {
-  if (aVisitor.mEvent->mFlags.mIsTrusted) {
+  if (aVisitor.mEvent->IsTrusted()) {
     switch (aVisitor.mEvent->mMessage) {
       case eFocus: {
         // Check to see if focus has bubbled up from a form control's
         // child textfield or button.  If that's the case, don't focus
         // this parent file control -- leave focus on the child.
         nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
         if (formControlFrame &&
             aVisitor.mEvent->originalTarget == static_cast<nsINode*>(this))
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -40,19 +40,18 @@
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/APZChild.h"
-#include "mozilla/layers/CompositorChild.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/ImageBridgeChild.h"
-#include "mozilla/layers/PCompositorChild.h"
 #include "mozilla/layers/SharedBufferManagerChild.h"
 #include "mozilla/layout/RenderFrameChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/plugins/PluginInstanceParent.h"
 #include "mozilla/plugins/PluginModuleParent.h"
 #include "mozilla/widget/WidgetMessageUtils.h"
 #include "mozilla/media/MediaChild.h"
 #include "mozilla/BasePrincipal.h"
@@ -870,29 +869,36 @@ ContentChild::ProvideWindowCommon(TabChi
       }
 
       baseURI->GetSpec(baseURIString);
     }
 
     auto* opener = nsPIDOMWindowOuter::From(aParent);
     nsIDocShell* openerShell;
     RefPtr<nsDocShell> openerDocShell;
+    float fullZoom = 1.0f;
     if (opener && (openerShell = opener->GetDocShell())) {
       openerDocShell = static_cast<nsDocShell*>(openerShell);
+      nsCOMPtr<nsIContentViewer> cv;
+      openerDocShell->GetContentViewer(getter_AddRefs(cv));
+      if (cv) {
+        cv->GetFullZoom(&fullZoom);
+      }
     }
 
     nsresult rv;
     if (!SendCreateWindow(aTabOpener, newChild,
                           aChromeFlags, aCalledFromJS, aPositionSpecified,
                           aSizeSpecified, url,
                           name, features,
                           baseURIString,
                           openerDocShell
                             ? openerDocShell->GetOriginAttributes()
                             : DocShellOriginAttributes(),
+                          fullZoom,
                           &rv,
                           aWindowIsNew,
                           &frameScripts,
                           &urlToLoad)) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
     if (NS_FAILED(rv)) {
@@ -1279,21 +1285,21 @@ ContentChild::AllocPAPZChild(const TabId
 
 bool
 ContentChild::DeallocPAPZChild(PAPZChild* aActor)
 {
   delete aActor;
   return true;
 }
 
-PCompositorChild*
-ContentChild::AllocPCompositorChild(mozilla::ipc::Transport* aTransport,
-                                    base::ProcessId aOtherProcess)
+PCompositorBridgeChild*
+ContentChild::AllocPCompositorBridgeChild(mozilla::ipc::Transport* aTransport,
+                                          base::ProcessId aOtherProcess)
 {
-  return CompositorChild::Create(aTransport, aOtherProcess);
+  return CompositorBridgeChild::Create(aTransport, aOtherProcess);
 }
 
 PSharedBufferManagerChild*
 ContentChild::AllocPSharedBufferManagerChild(mozilla::ipc::Transport* aTransport,
                                               base::ProcessId aOtherProcess)
 {
   return SharedBufferManagerChild::StartUpInChildProcess(aTransport, aOtherProcess);
 }
@@ -2561,18 +2567,18 @@ ContentChild::RecvCycleCollect()
 }
 
 #ifdef MOZ_NUWA_PROCESS
 static void
 OnFinishNuwaPreparation()
 {
   // We want to ensure that the PBackground actor gets cloned in the Nuwa
   // process before we freeze. Also, we have to do this to avoid deadlock.
-  // Protocols that are "opened" (e.g. PBackground, PCompositor) block the
-  // main thread to wait for the IPC thread during the open operation.
+  // Protocols that are "opened" (e.g. PBackground, PCompositorBridge) block
+  // the main thread to wait for the IPC thread during the open operation.
   // NuwaSpawnWait() blocks the IPC thread to wait for the main thread when
   // the Nuwa process is forked. Unless we ensure that the two cannot happen
   // at the same time then we risk deadlock. Spinning the event loop here
   // guarantees the ordering is safe for PBackground.
   while (!BackgroundChild::GetForCurrentThread()) {
     if (NS_WARN_IF(!NS_ProcessNextEvent())) {
       return;
     }
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -31,17 +31,17 @@ class RemoteSpellcheckEngineChild;
 
 namespace ipc {
 class OptionalURIParams;
 class PFileDescriptorSetChild;
 class URIParams;
 }// namespace ipc
 
 namespace layers {
-class PCompositorChild;
+class PCompositorBridgeChild;
 } // namespace layers
 
 namespace dom {
 
 class AlertObserver;
 class ConsoleListener;
 class PStorageChild;
 class ClonedMessageData;
@@ -144,19 +144,19 @@ public:
   AllocPGMPServiceChild(mozilla::ipc::Transport* transport,
                         base::ProcessId otherProcess) override;
 
   PAPZChild*
   AllocPAPZChild(const TabId& aTabId) override;
   bool
   DeallocPAPZChild(PAPZChild* aActor) override;
 
-  PCompositorChild*
-  AllocPCompositorChild(mozilla::ipc::Transport* aTransport,
-                        base::ProcessId aOtherProcess) override;
+  PCompositorBridgeChild*
+  AllocPCompositorBridgeChild(mozilla::ipc::Transport* aTransport,
+                              base::ProcessId aOtherProcess) override;
 
   PSharedBufferManagerChild*
   AllocPSharedBufferManagerChild(mozilla::ipc::Transport* aTransport,
                                   base::ProcessId aOtherProcess) override;
 
   PImageBridgeChild*
   AllocPImageBridgeChild(mozilla::ipc::Transport* aTransport,
                          base::ProcessId aOtherProcess) override;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -80,17 +80,17 @@
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/PFileDescriptorSetParent.h"
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/PAPZParent.h"
-#include "mozilla/layers/CompositorParent.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/SharedBufferManagerParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/media/MediaParent.h"
 #include "mozilla/Move.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/Preferences.h"
@@ -1916,27 +1916,27 @@ ContentParent::AllocateLayerTreeId(TabPa
 }
 
 /* static */
 bool
 ContentParent::AllocateLayerTreeId(ContentParent* aContent,
                                    TabParent* aTopLevel, const TabId& aTabId,
                                    uint64_t* aId)
 {
-  *aId = CompositorParent::AllocateLayerTreeId();
+  *aId = CompositorBridgeParent::AllocateLayerTreeId();
 
   if (!gfxPlatform::AsyncPanZoomEnabled()) {
     return true;
   }
 
   if (!aContent || !aTopLevel) {
     return false;
   }
 
-  return CompositorParent::UpdateRemoteContentController(*aId, aContent,
+  return CompositorBridgeParent::UpdateRemoteContentController(*aId, aContent,
                                                          aTabId, aTopLevel);
 }
 
 bool
 ContentParent::RecvAllocateLayerTreeId(const ContentParentId& aCpId,
                                        const TabId& aTabId, uint64_t* aId)
 {
   // Protect against spoofing by a compromised child. aCpId must either
@@ -1974,17 +1974,17 @@ ContentParent::RecvAllocateLayerTreeId(c
 }
 
 bool
 ContentParent::RecvDeallocateLayerTreeId(const uint64_t& aId)
 {
   auto iter = NestedBrowserLayerIds().find(this);
   if (iter != NestedBrowserLayerIds().end() &&
     iter->second.find(aId) != iter->second.end()) {
-    CompositorParent::DeallocateLayerTreeId(aId);
+    CompositorBridgeParent::DeallocateLayerTreeId(aId);
   } else {
     // You can't deallocate layer tree ids that you didn't allocate
     KillHard("DeallocateLayerTreeId");
   }
   return true;
 }
 
 namespace {
@@ -2538,26 +2538,26 @@ ContentParent::InitInternal(ProcessPrior
   // from this process.
   //
   // This call can cause us to send IPC messages to the child process, so it
   // must come after the Open() call above.
   ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
 
   if (aSetupOffMainThreadCompositing) {
     // NB: internally, this will send an IPC message to the child
-    // process to get it to create the CompositorChild.  This
+    // process to get it to create the CompositorBridgeChild.  This
     // message goes through the regular IPC queue for this
     // channel, so delivery will happen-before any other messages
-    // we send.  The CompositorChild must be created before any
+    // we send.  The CompositorBridgeChild must be created before any
     // PBrowsers are created, because they rely on the Compositor
     // already being around.  (Creation is async, so can't happen
     // on demand.)
-    bool useOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
+    bool useOffMainThreadCompositing = !!CompositorBridgeParent::CompositorLoop();
     if (useOffMainThreadCompositing) {
-      DebugOnly<bool> opened = PCompositor::Open(this);
+      DebugOnly<bool> opened = PCompositorBridge::Open(this);
       MOZ_ASSERT(opened);
 
       opened = PImageBridge::Open(this);
       MOZ_ASSERT(opened);
 
       opened = gfx::PVRManager::Open(this);
       MOZ_ASSERT(opened);
     }
@@ -3328,21 +3328,21 @@ ContentParent::AllocPAPZParent(const Tab
 }
 
 bool
 ContentParent::DeallocPAPZParent(PAPZParent* aActor)
 {
   return true;
 }
 
-PCompositorParent*
-ContentParent::AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
-                                      base::ProcessId aOtherProcess)
-{
-  return CompositorParent::Create(aTransport, aOtherProcess);
+PCompositorBridgeParent*
+ContentParent::AllocPCompositorBridgeParent(mozilla::ipc::Transport* aTransport,
+                                            base::ProcessId aOtherProcess)
+{
+  return CompositorBridgeParent::Create(aTransport, aOtherProcess);
 }
 
 gfx::PVRManagerParent*
 ContentParent::AllocPVRManagerParent(Transport* aTransport,
                                      ProcessId aOtherProcess)
 {
   return gfx::VRManagerParent::CreateCrossProcess(aTransport, aOtherProcess);
 }
@@ -5328,16 +5328,17 @@ ContentParent::RecvCreateWindow(PBrowser
                                 const bool& aCalledFromJS,
                                 const bool& aPositionSpecified,
                                 const bool& aSizeSpecified,
                                 const nsCString& aURI,
                                 const nsString& aName,
                                 const nsCString& aFeatures,
                                 const nsCString& aBaseURI,
                                 const DocShellOriginAttributes& aOpenerOriginAttributes,
+                                const float& aFullZoom,
                                 nsresult* aResult,
                                 bool* aWindowIsNew,
                                 InfallibleTArray<FrameScriptInfo>* aFrameScripts,
                                 nsCString* aURLToLoad)
 {
   // We always expect to open a new window here. If we don't, it's an error.
   *aWindowIsNew = true;
 
@@ -5485,17 +5486,17 @@ ContentParent::RecvCreateWindow(PBrowser
   // nsString (since primitives are not nullable). If we detect the voided
   // nsString, we know that we need to send OpenWindow2 a nullptr for the URI.
   const char* uri = aURI.IsVoid() ? nullptr : finalURIString.get();
   const char* name = aName.IsVoid() ? nullptr : NS_ConvertUTF16toUTF8(aName).get();
   const char* features = aFeatures.IsVoid() ? nullptr : aFeatures.get();
 
   *aResult = pwwatch->OpenWindow2(parent, uri, name, features, aCalledFromJS,
                                   false, false, thisTabParent, nullptr,
-                                  getter_AddRefs(window));
+                                  aFullZoom, 1, getter_AddRefs(window));
 
   if (NS_WARN_IF(!window)) {
     return true;
   }
 
   *aResult = NS_ERROR_FAILURE;
   auto* pwindow = nsPIDOMWindowOuter::From(window);
   nsCOMPtr<nsIDocShell> windowDocShell = pwindow->GetDocShell();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -56,17 +56,17 @@ class URIParams;
 class TestShellParent;
 } // namespace ipc
 
 namespace jsipc {
 class PJavaScriptParent;
 } // namespace jsipc
 
 namespace layers {
-class PCompositorParent;
+class PCompositorBridgeParent;
 class PSharedBufferManagerParent;
 } // namespace layers
 
 namespace dom {
 
 class Element;
 class TabParent;
 class PStorageParent;
@@ -501,16 +501,17 @@ public:
                                 const bool& aCalledFromJS,
                                 const bool& aPositionSpecified,
                                 const bool& aSizeSpecified,
                                 const nsCString& aURI,
                                 const nsString& aName,
                                 const nsCString& aFeatures,
                                 const nsCString& aBaseURI,
                                 const DocShellOriginAttributes& aOpenerOriginAttributes,
+                                const float& aFullZoom,
                                 nsresult* aResult,
                                 bool* aWindowIsNew,
                                 InfallibleTArray<FrameScriptInfo>* aFrameScripts,
                                 nsCString* aURLToLoad) override;
 
   static bool AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId);
 
 protected:
@@ -665,19 +666,19 @@ private:
   AllocPGMPServiceParent(mozilla::ipc::Transport* aTransport,
                          base::ProcessId aOtherProcess) override;
 
   PAPZParent*
   AllocPAPZParent(const TabId& aTabId) override;
   bool
   DeallocPAPZParent(PAPZParent* aActor) override;
 
-  PCompositorParent*
-  AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
-                         base::ProcessId aOtherProcess) override;
+  PCompositorBridgeParent*
+  AllocPCompositorBridgeParent(mozilla::ipc::Transport* aTransport,
+                               base::ProcessId aOtherProcess) override;
 
   PImageBridgeParent*
   AllocPImageBridgeParent(mozilla::ipc::Transport* aTransport,
                           base::ProcessId aOtherProcess) override;
 
   PSharedBufferManagerParent*
   AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTranport,
                                    base::ProcessId aOtherProcess) override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PAPZ;
 include protocol PBackground;
 include protocol PBlob;
 include protocol PBluetooth;
 include protocol PBrowser;
 include protocol PCellBroadcast;
-include protocol PCompositor;
+include protocol PCompositorBridge;
 include protocol PContentBridge;
 include protocol PContentPermissionRequest;
 include protocol PCycleCollectWithLogs;
 include protocol PCrashReporter;
 include protocol PPSMContentDownloader;
 include protocol PExternalHelperApp;
 include protocol PHandlerService;
 include protocol PDeviceStorageRequest;
@@ -456,17 +456,17 @@ struct AndroidSystemInfo
     uint32_t sdk_version;
     bool     isTablet;
 };
 
 prio(normal upto urgent) sync protocol PContent
 {
     parent spawns PPluginModule;
 
-    parent opens PCompositor;
+    parent opens PCompositorBridge;
     parent opens PProcessHangMonitor;
     parent opens PSharedBufferManager;
     parent opens PImageBridge;
     parent opens PGMPService;
     parent opens PVRManager;
     child opens PBackground;
 
     manages PAPZ;
@@ -1170,17 +1170,18 @@ parent:
                       uint32_t aChromeFlags,
                       bool aCalledFromJS,
                       bool aPositionSpecified,
                       bool aSizeSpecified,
                       nsCString aURI,
                       nsString aName,
                       nsCString aFeatures,
                       nsCString aBaseURI,
-                      DocShellOriginAttributes aOpenerOriginAttributes)
+                      DocShellOriginAttributes aOpenerOriginAttributes,
+                      float aFullZoom)
       returns (nsresult rv,
                bool windowOpened,
                FrameScriptInfo[] frameScripts,
                nsCString urlToLoad);
 
     sync GetDeviceStorageLocation(nsString type)
         returns (nsString path);
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -28,17 +28,17 @@
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZEventState.h"
-#include "mozilla/layers/CompositorChild.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/DoubleTapToZoom.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "mozilla/layout/RenderFrameChild.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
@@ -1209,17 +1209,17 @@ TabChild::ActorDestroy(ActorDestroyReaso
   if (mTabChildGlobal) {
     // The messageManager relays messages via the TabChild which
     // no longer exists.
     static_cast<nsFrameMessageManager*>
       (mTabChildGlobal->mMessageManager.get())->Disconnect();
     mTabChildGlobal->mMessageManager = nullptr;
   }
 
-  CompositorChild* compositorChild = static_cast<CompositorChild*>(CompositorChild::Get());
+  CompositorBridgeChild* compositorChild = static_cast<CompositorBridgeChild*>(CompositorBridgeChild::Get());
   compositorChild->CancelNotifyAfterRemotePaint(this);
 
   if (GetTabId() != 0) {
     NestedTabChildMap().erase(GetTabId());
   }
 }
 
 TabChild::~TabChild()
@@ -2532,19 +2532,19 @@ TabChild::InitRenderingState(const Textu
         return false;
     }
 
     MOZ_ASSERT(aLayersId != 0);
     mTextureFactoryIdentifier = aTextureFactoryIdentifier;
 
     // Pushing layers transactions directly to a separate
     // compositor context.
-    PCompositorChild* compositorChild = CompositorChild::Get();
+    PCompositorBridgeChild* compositorChild = CompositorBridgeChild::Get();
     if (!compositorChild) {
-      NS_WARNING("failed to get CompositorChild instance");
+      NS_WARNING("failed to get CompositorBridgeChild instance");
       PRenderFrameChild::Send__delete__(remoteFrame);
       return false;
     }
     nsTArray<LayersBackend> backends;
     backends.AppendElement(mTextureFactoryIdentifier.mParentBackend);
     bool success;
     PLayerTransactionChild* shadowManager =
         compositorChild->SendPLayerTransactionConstructor(backends,
@@ -2640,35 +2640,35 @@ TabChild::NotifyPainted()
         mRemoteFrame->SendNotifyCompositorTransaction();
         mNotified = true;
     }
 }
 
 void
 TabChild::MakeVisible()
 {
-  CompositorChild* compositor = CompositorChild::Get();
+  CompositorBridgeChild* compositor = CompositorBridgeChild::Get();
   if (UsingCompositorLRU()) {
     compositor->SendNotifyVisible(mLayersId);
   }
 
   if (mPuppetWidget) {
     mPuppetWidget->Show(true);
   }
 }
 
 void
 TabChild::MakeHidden()
 {
-  CompositorChild* compositor = CompositorChild::Get();
+  CompositorBridgeChild* compositor = CompositorBridgeChild::Get();
   if (UsingCompositorLRU()) {
     compositor->SendNotifyHidden(mLayersId);
   } else {
     // Clear cached resources directly. This avoids one extra IPC
-    // round-trip from CompositorChild to CompositorParent when
+    // round-trip from CompositorBridgeChild to CompositorBridgeParent when
     // CompositorLRU is not used.
     compositor->RecvClearCachedResources(mLayersId);
   }
 
   if (mPuppetWidget) {
     mPuppetWidget->Show(false);
   }
 }
@@ -2812,17 +2812,17 @@ TabChild::DidComposite(uint64_t aTransac
                        const TimeStamp& aCompositeStart,
                        const TimeStamp& aCompositeEnd)
 {
   MOZ_ASSERT(mPuppetWidget);
   MOZ_ASSERT(mPuppetWidget->GetLayerManager());
   MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() ==
                LayersBackend::LAYERS_CLIENT);
 
-  ClientLayerManager *manager = mPuppetWidget->GetLayerManager()->AsClientLayerManager();
+  RefPtr<ClientLayerManager> manager = mPuppetWidget->GetLayerManager()->AsClientLayerManager();
 
   manager->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
 }
 
 void
 TabChild::DidRequestComposite(const TimeStamp& aCompositeReqStart,
                               const TimeStamp& aCompositeReqEnd)
 {
@@ -2892,20 +2892,20 @@ TabChild::OnHideTooltip()
 {
     SendHideTooltip();
     return NS_OK;
 }
 
 bool
 TabChild::RecvRequestNotifyAfterRemotePaint()
 {
-  // Get the CompositorChild instance for this content thread.
-  CompositorChild* compositor = CompositorChild::Get();
-
-  // Tell the CompositorChild that, when it gets a RemotePaintIsReady
+  // Get the CompositorBridgeChild instance for this content thread.
+  CompositorBridgeChild* compositor = CompositorBridgeChild::Get();
+
+  // Tell the CompositorBridgeChild that, when it gets a RemotePaintIsReady
   // message that it should forward it us so that we can bounce it to our
   // RenderFrameParent.
   compositor->RequestNotifyAfterRemotePaint(this);
   return true;
 }
 
 bool
 TabChild::RecvUIResolutionChanged(const float& aDpi, const double& aScale)
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -24,17 +24,17 @@
 #include "mozilla/plugins/PluginWidgetParent.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/Hal.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/ipc/DocumentRendererParent.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/AsyncDragMetrics.h"
-#include "mozilla/layers/CompositorParent.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
@@ -2103,19 +2103,18 @@ TabParent::GetChildProcessOffset()
 }
 
 bool
 TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& event)
 {
   NS_ENSURE_TRUE(mFrameElement, true);
 
   WidgetKeyboardEvent localEvent(event);
-  // Set mNoCrossProcessBoundaryForwarding to avoid this event from
-  // being infinitely redispatched and forwarded to the child again.
-  localEvent.mFlags.mNoCrossProcessBoundaryForwarding = true;
+  // Mark the event as not to be dispatched to remote process again.
+  localEvent.StopCrossProcessForwarding();
 
   // Here we convert the WidgetEvent that we received to an nsIDOMEvent
   // to be able to dispatch it to the <browser> element as the target element.
   nsIDocument* doc = mFrameElement->OwnerDoc();
   nsIPresShell* presShell = doc->GetShell();
   NS_ENSURE_TRUE(presShell, true);
   nsPresContext* presContext = presShell->GetPresContext();
   NS_ENSURE_TRUE(presContext, true);
@@ -2135,17 +2134,17 @@ TabParent::RecvDispatchAfterKeyboardEven
   nsIDocument* doc = mFrameElement->OwnerDoc();
   nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
   NS_ENSURE_TRUE(presShell, true);
 
   if (mFrameElement &&
       PresShell::BeforeAfterKeyboardEventEnabled() &&
       localEvent.mMessage != eKeyPress) {
     presShell->DispatchAfterKeyboardEvent(mFrameElement, localEvent,
-                                          aEvent.mFlags.mDefaultPrevented);
+                                          aEvent.DefaultPrevented());
   }
 
   return true;
 }
 
 bool
 TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent)
 {
@@ -2910,32 +2909,34 @@ class LayerTreeUpdateObserver : public C
 
 bool
 TabParent::RequestNotifyLayerTreeReady()
 {
   RenderFrameParent* frame = GetRenderFrame();
   if (!frame) {
     mNeedLayerTreeReadyNotification = true;
   } else {
-    CompositorParent::RequestNotifyLayerTreeReady(frame->GetLayersId(),
-                                                  new LayerTreeUpdateObserver());
+    CompositorBridgeParent::RequestNotifyLayerTreeReady(
+      frame->GetLayersId(),
+      new LayerTreeUpdateObserver());
   }
   return true;
 }
 
 bool
 TabParent::RequestNotifyLayerTreeCleared()
 {
   RenderFrameParent* frame = GetRenderFrame();
   if (!frame) {
     return false;
   }
 
-  CompositorParent::RequestNotifyLayerTreeCleared(frame->GetLayersId(),
-                                                  new LayerTreeUpdateObserver());
+  CompositorBridgeParent::RequestNotifyLayerTreeCleared(
+    frame->GetLayersId(),
+    new LayerTreeUpdateObserver());
   return true;
 }
 
 bool
 TabParent::LayerTreeUpdate(bool aActive)
 {
   nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(mFrameElement);
   if (!target) {
@@ -2960,22 +2961,23 @@ void
 TabParent::SwapLayerTreeObservers(TabParent* aOther)
 {
   if (IsDestroyed() || aOther->IsDestroyed()) {
     return;
   }
 
   RenderFrameParent* rfp = GetRenderFrame();
   RenderFrameParent* otherRfp = aOther->GetRenderFrame();
-  if(!rfp || !otherRfp) {
+  if (!rfp || !otherRfp) {
     return;
   }
 
-  CompositorParent::SwapLayerTreeObservers(rfp->GetLayersId(),
-                                           otherRfp->GetLayersId());
+  CompositorBridgeParent::SwapLayerTreeObservers(
+    rfp->GetLayersId(),
+    otherRfp->GetLayersId());
 }
 
 bool
 TabParent::RecvRemotePaintIsReady()
 {
   nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(mFrameElement);
   if (!target) {
     NS_WARNING("Could not locate target for MozAfterRemotePaint message.");
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -826,16 +826,21 @@ MediaDecoderStateMachine::OnNotDecoded(M
   }
   switch (mState) {
     case DECODER_STATE_BUFFERING:
     case DECODER_STATE_DECODING: {
       if (MaybeFinishDecodeFirstFrame()) {
         return;
       }
       CheckIfDecodeComplete();
+
+      // Schedule next cycle to see if we can leave buffering state.
+      if (mState == DECODER_STATE_BUFFERING) {
+        ScheduleStateMachine();
+      }
       return;
     }
     case DECODER_STATE_SEEKING: {
       if (!mCurrentSeek.Exists()) {
         // We've received a sample from a previous decode. Discard it.
         return;
       }
 
--- a/dom/media/directshow/DirectShowReader.cpp
+++ b/dom/media/directshow/DirectShowReader.cpp
@@ -28,18 +28,17 @@ GetDirectShowLog() {
 DirectShowReader::DirectShowReader(AbstractMediaDecoder* aDecoder)
   : MediaDecoderReader(aDecoder),
     mMP3FrameParser(aDecoder->GetResource()->GetLength()),
 #ifdef DIRECTSHOW_REGISTER_GRAPH
     mRotRegister(0),
 #endif
     mNumChannels(0),
     mAudioRate(0),
-    mBytesPerSample(0),
-    mDuration(0)
+    mBytesPerSample(0)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   MOZ_COUNT_CTOR(DirectShowReader);
 }
 
 DirectShowReader::~DirectShowReader()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
@@ -357,48 +356,9 @@ DirectShowReader::SeekInternal(int64_t a
   NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
 
   hr = mControl->Run();
   NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
-void
-DirectShowReader::NotifyDataArrivedInternal()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  if (!mMP3FrameParser.NeedsData()) {
-    return;
-  }
-
-  AutoPinned<MediaResource> resource(mDecoder->GetResource());
-  MediaByteRangeSet byteRanges;
-  nsresult rv = resource->GetCachedRanges(byteRanges);
-
-  if (NS_FAILED(rv)) {
-    return;
-  }
-
-  if (byteRanges == mLastCachedRanges) {
-    return;
-  }
-  MediaByteRangeSet intervals = byteRanges - mLastCachedRanges;
-  mLastCachedRanges = byteRanges;
-
-  for (const auto& interval : intervals) {
-    RefPtr<MediaByteBuffer> bytes =
-      resource->MediaReadAt(interval.mStart, interval.Length());
-    NS_ENSURE_TRUE_VOID(bytes);
-    mMP3FrameParser.Parse(bytes->Elements(), interval.Length(), interval.mStart);
-    if (!mMP3FrameParser.IsMP3()) {
-      return;
-    }
-  }
-  int64_t duration = mMP3FrameParser.GetDuration();
-  if (duration != mDuration) {
-    MOZ_ASSERT(mDecoder);
-    mDuration = duration;
-    mDecoder->DispatchUpdateEstimatedMediaDuration(mDuration);
-  }
-}
-
 } // namespace mozilla
--- a/dom/media/directshow/DirectShowReader.h
+++ b/dom/media/directshow/DirectShowReader.h
@@ -55,19 +55,16 @@ public:
                         int64_t aTimeThreshold) override;
 
   nsresult ReadMetadata(MediaInfo* aInfo,
                         MetadataTags** aTags) override;
 
   RefPtr<SeekPromise>
   Seek(SeekTarget aTarget, int64_t aEndTime) override;
 
-protected:
-  void NotifyDataArrivedInternal() override;
-
 private:
   // Notifies the filter graph that playback is complete. aStatus is
   // the code to send to the filter graph. Always returns false, so
   // that we can just "return Finish()" from DecodeAudioData().
   bool Finish(HRESULT aStatus);
 
   nsresult SeekInternal(int64_t aTime);
 
@@ -99,18 +96,13 @@ private:
   // Number of channels in the audio stream.
   uint32_t mNumChannels;
 
   // Samples per second in the audio stream.
   uint32_t mAudioRate;
 
   // Number of bytes per sample. Can be either 1 or 2.
   uint32_t mBytesPerSample;
-
-  // Duration of the stream, in microseconds.
-  int64_t mDuration;
-
-  MediaByteRangeSet mLastCachedRanges;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/mediasink/DecodedStream.cpp
+++ b/dom/media/mediasink/DecodedStream.cpp
@@ -447,18 +447,17 @@ void
 DecodedStream::SetPreservesPitch(bool aPreservesPitch)
 {
   AssertOwnerThread();
   mParams.mPreservesPitch = aPreservesPitch;
 }
 
 static void
 SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
-                MediaData* aData, AudioSegment* aOutput,
-                uint32_t aRate, double aVolume)
+                MediaData* aData, AudioSegment* aOutput, uint32_t aRate)
 {
   // The amount of audio frames that is used to fuzz rounding errors.
   static const int64_t AUDIO_FUZZ_FRAMES = 1;
 
   MOZ_ASSERT(aData);
   AudioData* audio = aData->As<AudioData>();
   // This logic has to mimic AudioSink closely to make sure we write
   // the exact same silences
@@ -489,17 +488,16 @@ SendStreamAudio(DecodedStreamData* aStre
   RefPtr<SharedBuffer> buffer = audio->mAudioBuffer;
   AudioDataValue* bufferData = static_cast<AudioDataValue*>(buffer->Data());
   AutoTArray<const AudioDataValue*, 2> channels;
   for (uint32_t i = 0; i < audio->mChannels; ++i) {
     channels.AppendElement(bufferData + i * audio->mFrames);
   }
   aOutput->AppendFrames(buffer.forget(), channels, audio->mFrames);
   aStream->mAudioFramesWritten += audio->mFrames;
-  aOutput->ApplyVolume(aVolume);
 
   aStream->mNextAudioTime = audio->GetEndTime();
 }
 
 void
 DecodedStream::SendAudio(double aVolume, bool aIsSameOrigin)
 {
   AssertOwnerThread();
@@ -513,19 +511,21 @@ DecodedStream::SendAudio(double aVolume,
   AutoTArray<RefPtr<MediaData>,10> audio;
   TrackID audioTrackId = mInfo.mAudio.mTrackId;
   SourceMediaStream* sourceStream = mData->mStream;
 
   // It's OK to hold references to the AudioData because AudioData
   // is ref-counted.
   mAudioQueue.GetElementsAfter(mData->mNextAudioTime, &audio);
   for (uint32_t i = 0; i < audio.Length(); ++i) {
-    SendStreamAudio(mData.get(), mStartTime.ref(), audio[i], &output, rate, aVolume);
+    SendStreamAudio(mData.get(), mStartTime.ref(), audio[i], &output, rate);
   }
 
+  output.ApplyVolume(aVolume);
+
   if (!aIsSameOrigin) {
     output.ReplaceWithDisabled();
   }
 
   // |mNextAudioTime| is updated as we process each audio sample in
   // SendStreamAudio(). This is consistent with how |mNextVideoTime|
   // is updated for video samples.
   if (output.GetDuration() > 0) {
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -290,18 +290,16 @@ SourceBuffer::SourceBuffer(MediaSource* 
   : DOMEventTargetHelper(aMediaSource->GetParentObject())
   , mMediaSource(aMediaSource)
   , mUpdating(false)
   , mActive(false)
   , mType(aType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aMediaSource);
-  mEvictionThreshold = Preferences::GetUint("media.mediasource.eviction_threshold",
-                                            100 * (1 << 20));
   bool generateTimestamps = false;
   if (aType.LowerCaseEqualsLiteral("audio/mpeg") ||
       aType.LowerCaseEqualsLiteral("audio/aac")) {
     generateTimestamps = true;
   }
   mAttributes = new SourceBufferAttributes(generateTimestamps);
 
   mContentManager =
@@ -519,34 +517,33 @@ SourceBuffer::PrepareAppend(const uint8_
   // evict data before that range across all SourceBuffers it knows
   // about.
   // TODO: Make the eviction threshold smaller for audio-only streams.
   // TODO: Drive evictions off memory pressure notifications.
   // TODO: Consider a global eviction threshold  rather than per TrackBuffer.
   TimeUnit newBufferStartTime;
   // Attempt to evict the amount of data we are about to add by lowering the
   // threshold.
-  uint32_t toEvict =
-    (mEvictionThreshold > aLength) ? mEvictionThreshold - aLength : aLength;
   Result evicted =
     mContentManager->EvictData(TimeUnit::FromSeconds(mMediaSource->GetDecoder()->GetCurrentTime()),
-                               toEvict, &newBufferStartTime);
+                               aLength, &newBufferStartTime);
   if (evicted == Result::DATA_EVICTED) {
     MSE_DEBUG("AppendData Evict; current buffered start=%f",
               GetBufferedStart());
 
     // We notify that we've evicted from the time range 0 through to
     // the current start point.
     mMediaSource->NotifyEvicted(0.0, newBufferStartTime.ToSeconds());
   }
 
   // See if we have enough free space to append our new data.
   // As we can only evict once we have playable data, we must give a chance
   // to the DASH player to provide a complete media segment.
-  if (aLength > mEvictionThreshold || evicted == Result::BUFFER_FULL) {
+  if (aLength > mContentManager->EvictionThreshold() ||
+      evicted == Result::BUFFER_FULL) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
   }
 
   RefPtr<MediaByteBuffer> data = new MediaByteBuffer();
   if (!data->AppendElements(aData, aLength, fallible)) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -248,18 +248,16 @@ private:
                                                   uint32_t aLength,
                                                   ErrorResult& aRv);
 
   void AppendDataCompletedWithSuccess(bool aHasActiveTracks);
   void AppendDataErrored(nsresult aError);
 
   RefPtr<MediaSource> mMediaSource;
 
-  uint32_t mEvictionThreshold;
-
   RefPtr<SourceBufferContentManager> mContentManager;
   RefPtr<SourceBufferAttributes> mAttributes;
 
   bool mUpdating;
 
   mozilla::Atomic<bool> mActive;
 
   MozPromiseRequestHolder<SourceBufferContentManager::AppendPromise> mPendingAppend;
--- a/dom/media/mediasource/SourceBufferContentManager.h
+++ b/dom/media/mediasource/SourceBufferContentManager.h
@@ -65,17 +65,17 @@ public:
   };
 
   // Evicts data up to aPlaybackTime. aThreshold is used to
   // bound the data being evicted. It will not evict more than aThreshold
   // bytes. aBufferStartTime contains the new start time of the data after the
   // eviction.
   virtual EvictDataResult
   EvictData(media::TimeUnit aPlaybackTime,
-            uint32_t aThreshold,
+            int64_t aThreshold,
             media::TimeUnit* aBufferStartTime) = 0;
 
   // Evicts data up to aTime.
   virtual void EvictBefore(media::TimeUnit aTime) = 0;
 
   // Returns the buffered range currently managed.
   // This may be called on any thread.
   // Buffered must conform to http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
@@ -102,16 +102,17 @@ public:
   virtual AppendState GetAppendState()
   {
     return AppendState::WAITING_FOR_SEGMENT;
   }
 
   virtual void SetGroupStartTimestamp(const media::TimeUnit& aGroupStartTimestamp) {}
   virtual void RestartGroupStartTimestamp() {}
   virtual media::TimeUnit GroupEndTimestamp() = 0;
+  virtual int64_t EvictionThreshold() const = 0;
 
 protected:
   virtual ~SourceBufferContentManager() { }
 };
 
 } // namespace mozilla
 
 #endif /* MOZILLA_SOURCEBUFFERCONTENTMANAGER_H_ */
--- a/dom/media/mediasource/SourceBufferResource.cpp
+++ b/dom/media/mediasource/SourceBufferResource.cpp
@@ -129,17 +129,17 @@ SourceBufferResource::ReadFromCache(char
   mOffset = oldOffset; // ReadFromCache isn't supposed to affect the seek position.
   NS_ENSURE_SUCCESS(rv, rv);
 
   // ReadFromCache return failure if not all the data is cached.
   return bytesRead == aCount ? NS_OK : NS_ERROR_FAILURE;
 }
 
 uint32_t
-SourceBufferResource::EvictData(uint64_t aPlaybackOffset, uint32_t aThreshold,
+SourceBufferResource::EvictData(uint64_t aPlaybackOffset, int64_t aThreshold,
                                 ErrorResult& aRv)
 {
   SBR_DEBUG("EvictData(aPlaybackOffset=%llu,"
             "aThreshold=%u)", aPlaybackOffset, aThreshold);
   ReentrantMonitorAutoEnter mon(mMonitor);
   uint32_t result = mInputBuffer.Evict(aPlaybackOffset, aThreshold, aRv);
   if (result > 0) {
     // Wake up any waiting threads in case a ReadInternal call
--- a/dom/media/mediasource/SourceBufferResource.h
+++ b/dom/media/mediasource/SourceBufferResource.h
@@ -106,19 +106,19 @@ public:
   // Used by SourceBuffer.
   void AppendData(MediaByteBuffer* aData);
   void Ended();
   bool IsEnded()
   {
     ReentrantMonitorAutoEnter mon(mMonitor);
     return mEnded;
   }
-  // Remove data from resource if it holds more than the threshold
-  // number of bytes. Returns amount evicted.
-  uint32_t EvictData(uint64_t aPlaybackOffset, uint32_t aThreshold,
+  // Remove data from resource if it holds more than the threshold reduced by
+  // the given number of bytes. Returns amount evicted.
+  uint32_t EvictData(uint64_t aPlaybackOffset, int64_t aThresholdReduct,
                      ErrorResult& aRv);
 
   // Remove data from resource before the given offset.
   void EvictBefore(uint64_t aOffset, ErrorResult& aRv);
 
   // Remove all data from the resource
   uint32_t EvictAll();
 
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -94,18 +94,20 @@ TrackBuffersManager::TrackBuffersManager
   , mNewMediaSegmentStarted(false)
   , mActiveTrack(false)
   , mType(aType)
   , mParser(ContainerParser::CreateForMIMEType(aType))
   , mProcessedInput(0)
   , mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue())
   , mSourceBufferAttributes(aAttributes)
   , mParentDecoder(new nsMainThreadPtrHolder<MediaSourceDecoder>(aParentDecoder, false /* strict */))
-  , mEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold",
-                                            100 * (1 << 20)))
+  , mVideoEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold.video",
+                                                 100 * 1024 * 1024))
+  , mAudioEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold.audio",
+                                                 15 * 1024 * 1024))
   , mEvictionOccurred(false)
   , mMonitor("TrackBuffersManager")
   , mAppendRunning(false)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread");
 }
 
 TrackBuffersManager::~TrackBuffersManager()
@@ -193,23 +195,27 @@ TrackBuffersManager::RangeRemoval(TimeUn
 
   return InvokeAsync(GetTaskQueue(), this, __func__,
                      &TrackBuffersManager::CodedFrameRemovalWithPromise,
                      TimeInterval(aStart, aEnd));
 }
 
 TrackBuffersManager::EvictDataResult
 TrackBuffersManager::EvictData(TimeUnit aPlaybackTime,
-                               uint32_t aThreshold,
+                               int64_t aThresholdReduct,
                                TimeUnit* aBufferStartTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MSE_DEBUG("");
+
+  const int64_t toEvict = GetSize() -
+    std::max(EvictionThreshold() - aThresholdReduct, aThresholdReduct);
 
-  int64_t toEvict = GetSize() - aThreshold;
+  MSE_DEBUG("buffered=%lldkb, eviction threshold=%ukb, evict=%lldkb",
+            GetSize() / 1024, EvictionThreshold() / 1024, toEvict / 1024);
+
   if (toEvict <= 0) {
     return EvictDataResult::NO_DATA_EVICTED;
   }
   if (toEvict <= 512*1024) {
     // Don't bother evicting less than 512KB.
     return EvictDataResult::CANT_EVICT;
   }
 
@@ -297,16 +303,23 @@ TrackBuffersManager::Detach()
 }
 
 void
 TrackBuffersManager::CompleteResetParserState()
 {
   MOZ_ASSERT(OnTaskQueue());
   MSE_DEBUG("");
 
+  // We shouldn't change mInputDemuxer while a demuxer init/reset request is
+  // being processed. See bug 1239983.
+  NS_ASSERTION(!mDemuxerInitRequest.Exists(), "Previous AppendBuffer didn't complete");
+  if (mDemuxerInitRequest.Exists()) {
+    mDemuxerInitRequest.Disconnect();
+  }
+
   for (auto& track : GetTracksList()) {
     // 2. Unset the last decode timestamp on all track buffers.
     // 3. Unset the last frame duration on all track buffers.
     // 4. Unset the highest end timestamp on all track buffers.
     // 5. Set the need random access point flag on all track buffers to true.
     track->ResetAppendState();
 
     // if we have been aborted, we may have pending frames that we are going
@@ -346,58 +359,66 @@ TrackBuffersManager::CompleteResetParser
 
   // 8. Set append state to WAITING_FOR_SEGMENT.
   SetAppendState(AppendState::WAITING_FOR_SEGMENT);
 
   // Reject our promise immediately.
   mAppendPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
 }
 
+int64_t
+TrackBuffersManager::EvictionThreshold() const
+{
+  if (HasVideo()) {
+    return mVideoEvictionThreshold;
+  }
+  return mAudioEvictionThreshold;
+}
+
 void
 TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime,
-                                 uint32_t aSizeToEvict)
+                                 int64_t aSizeToEvict)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Video is what takes the most space, only evict there if we have video.
   const auto& track = HasVideo() ? mVideoTracks : mAudioTracks;
   const auto& buffer = track.mBuffers.LastElement();
   // Remove any data we've already played, or before the next sample to be
   // demuxed whichever is lowest.
   TimeUnit lowerLimit = std::min(track.mNextSampleTime, aPlaybackTime);
   uint32_t lastKeyFrameIndex = 0;
   int64_t toEvict = aSizeToEvict;
-  uint32_t partialEvict = 0;
+  int64_t partialEvict = 0;
   for (uint32_t i = 0; i < buffer.Length(); i++) {
     const auto& frame = buffer[i];
     if (frame->mKeyframe) {
       lastKeyFrameIndex = i;
       toEvict -= partialEvict;
       if (toEvict < 0) {
         break;
       }
       partialEvict = 0;
     }
     if (frame->mTime >= lowerLimit.ToMicroseconds()) {
       break;
     }
     partialEvict += frame->ComputedSizeOfIncludingThis();
   }
 
-  int64_t finalSize = mSizeSourceBuffer - aSizeToEvict;
-
   if (lastKeyFrameIndex > 0) {
-    MSE_DEBUG("Step1. Evicting %u bytes prior currentTime",
+    MSE_DEBUG("Step1. Evicting %lld bytes prior currentTime",
               aSizeToEvict - toEvict);
     CodedFrameRemoval(
       TimeInterval(TimeUnit::FromMicroseconds(0),
                    TimeUnit::FromMicroseconds(buffer[lastKeyFrameIndex]->mTime - 1)));
   }
 
-  if (mSizeSourceBuffer <= finalSize) {
+  const int64_t finalSize = mSizeSourceBuffer - aSizeToEvict;
+  if (mSizeSourceBuffer <= finalSize || !buffer.Length()) {
     return;
   }
 
   toEvict = mSizeSourceBuffer - finalSize;
 
   // Still some to remove. Remove data starting from the end, up to 30s ahead
   // of the later of the playback time or the next sample to be demuxed.
   // 30s is a value chosen as it appears to work with YouTube.
@@ -410,18 +431,18 @@ TrackBuffersManager::DoEvictData(const T
       // We've reached a frame that shouldn't be evicted -> Evict after it -> i+1.
       // Or the previous loop reached the eviction threshold -> Evict from it -> i+1.
       evictedFramesStartIndex = i + 1;
       break;
     }
     toEvict -= frame->ComputedSizeOfIncludingThis();
   }
   if (evictedFramesStartIndex < buffer.Length()) {
-    MSE_DEBUG("Step2. Evicting %u bytes from trailing data",
-              mSizeSourceBuffer - finalSize);
+    MSE_DEBUG("Step2. Evicting %lld bytes from trailing data",
+              mSizeSourceBuffer - finalSize - toEvict);
     CodedFrameRemoval(
       TimeInterval(TimeUnit::FromMicroseconds(buffer[evictedFramesStartIndex]->mTime),
                    TimeUnit::FromInfinity()));
   }
 }
 
 RefPtr<TrackBuffersManager::RangeRemovalPromise>
 TrackBuffersManager::CodedFrameRemovalWithPromise(TimeInterval aInterval)
@@ -497,17 +518,17 @@ TrackBuffersManager::CodedFrameRemoval(T
   }
 
   UpdateBufferedRanges();
 
   // Update our reported total size.
   mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer;
 
   // 4. If buffer full flag equals true and this object is ready to accept more bytes, then set the buffer full flag to false.
-  if (mBufferFull && mSizeSourceBuffer < mEvictionThreshold) {
+  if (mBufferFull && mSizeSourceBuffer < EvictionThreshold()) {
     mBufferFull = false;
   }
   mEvictionOccurred = true;
 
   return dataRemoved;
 }
 
 void
@@ -860,19 +881,22 @@ TrackBuffersManager::InitializationSegme
 }
 
 void
 TrackBuffersManager::OnDemuxerInitDone(nsresult)
 {
   MOZ_ASSERT(OnTaskQueue());
   mDemuxerInitRequest.Complete();
 
-  // mInputDemuxer shouldn't have been destroyed while a demuxer init/reset
-  // request was being processed. See bug 1239983.
-  MOZ_DIAGNOSTIC_ASSERT(mInputDemuxer);
+  if (!mInputDemuxer) {
+    // mInputDemuxer shouldn't have been destroyed while a demuxer init/reset
+    // request was being processed. See bug 1239983.
+    NS_ASSERTION(false, "mInputDemuxer has been destroyed");
+    RejectAppend(NS_ERROR_ABORT, __func__);
+  }
 
   MediaInfo info;
 
   uint32_t numVideos = mInputDemuxer->GetNumberTracks(TrackInfo::kVideoTrack);
   if (numVideos) {
     // We currently only handle the first video track.
     mVideoTracks.mDemuxer = mInputDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
     MOZ_ASSERT(mVideoTracks.mDemuxer);
@@ -1233,17 +1257,17 @@ TrackBuffersManager::CompleteCodedFrameP
 
   UpdateBufferedRanges();
 
   // Update our reported total size.
   mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer;
 
   // Return to step 6.4 of Segment Parser Loop algorithm
   // 4. If this SourceBuffer is full and cannot accept more media data, then set the buffer full flag to true.
-  if (mSizeSourceBuffer >= mEvictionThreshold) {
+  if (mSizeSourceBuffer >= EvictionThreshold()) {
     mBufferFull = true;
     mEvictionOccurred = false;
   }
 
   // 5. If the input buffer does not contain a complete media segment, then jump to the need more data step below.
   if (mParser->MediaSegmentRange().IsEmpty()) {
     ResolveProcessing(true, __func__);
     return;
@@ -1625,17 +1649,17 @@ TrackBuffersManager::InsertFrames(TrackB
 
 void
 TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals,
                                   TrackData& aTrackData,
                                   uint32_t aStartIndex)
 {
   TrackBuffer& data = aTrackData.mBuffers.LastElement();
   Maybe<uint32_t> firstRemovedIndex;
-  uint32_t lastRemovedIndex;
+  uint32_t lastRemovedIndex = 0;
 
   // We loop from aStartIndex to avoid removing frames that we inserted earlier
   // and part of the current coded frame group. This is allows to handle step
   // 14 of the coded frame processing algorithm without having to check the value
   // of highest end timestamp:
   // "Remove existing coded frames in track buffer:
   //  If highest end timestamp for track buffer is not set:
   //   Remove all coded frames from track buffer that have a presentation timestamp greater than or equal to presentation timestamp and less than frame end timestamp.
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -51,17 +51,17 @@ public:
 
   void ResetParserState() override;
 
   RefPtr<RangeRemovalPromise> RangeRemoval(media::TimeUnit aStart,
                                              media::TimeUnit aEnd) override;
 
   EvictDataResult
   EvictData(media::TimeUnit aPlaybackTime,
-            uint32_t aThreshold,
+            int64_t aThresholdReduct,
             media::TimeUnit* aBufferStartTime) override;
 
   void EvictBefore(media::TimeUnit aTime) override;
 
   media::TimeIntervals Buffered() override;
 
   int64_t GetSize() override;
 
@@ -72,16 +72,17 @@ public:
   AppendState GetAppendState() override
   {
     return mAppendState;
   }
 
   void SetGroupStartTimestamp(const media::TimeUnit& aGroupStartTimestamp) override;
   void RestartGroupStartTimestamp() override;
   media::TimeUnit GroupEndTimestamp() override;
+  int64_t EvictionThreshold() const override;
 
   // Interface for MediaSourceDemuxer
   MediaInfo GetMetadata();
   const TrackBuffer& GetTrackBuffer(TrackInfo::TrackType aTrack);
   const media::TimeIntervals& Buffered(TrackInfo::TrackType);
   media::TimeIntervals SafeBuffered(TrackInfo::TrackType) const;
   bool IsEnded() const
   {
@@ -195,17 +196,17 @@ private:
   void DoDemuxAudio();
   void OnAudioDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);
   void OnAudioDemuxFailed(DemuxerFailureReason aFailure)
   {
     mAudioTracks.mDemuxRequest.Complete();
     OnDemuxFailed(TrackType::kAudioTrack, aFailure);
   }
 
-  void DoEvictData(const media::TimeUnit& aPlaybackTime, uint32_t aThreshold);
+  void DoEvictData(const media::TimeUnit& aPlaybackTime, int64_t aThreshold);
 
   struct TrackData {
     TrackData()
       : mNumTracks(0)
       , mNeedRandomAccessPoint(true)
       , mSizeBuffer(0)
     {}
     uint32_t mNumTracks;
@@ -339,17 +340,18 @@ private:
   RefPtr<dom::SourceBufferAttributes> mSourceBufferAttributes;
   nsMainThreadPtrHandle<MediaSourceDecoder> mParentDecoder;
 
   // Set to true if mediasource state changed to ended.
   Atomic<bool> mEnded;
 
   // Global size of this source buffer content.
   Atomic<int64_t> mSizeSourceBuffer;
-  uint32_t mEvictionThreshold;
+  const int64_t mVideoEvictionThreshold;
+  const int64_t mAudioEvictionThreshold;
   Atomic<bool> mEvictionOccurred;
 
   // Monitor to protect following objects accessed across multipple threads.
   // mMonitor is also notified if the value of mAppendRunning becomes false.
   mutable Monitor mMonitor;
   // Set to true while a BufferAppend is running or is pending.
   Atomic<bool> mAppendRunning;
   // Stable audio and video track time ranges.
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -596,16 +596,23 @@ D3D11DXVA2Manager::GetDXVADeviceManager(
   return mDXGIDeviceManager;
 }
 
 HRESULT
 D3D11DXVA2Manager::Init(nsACString& aFailureReason)
 {
   HRESULT hr;
 
+  gfx::D3D11VideoCrashGuard crashGuard;
+  if (crashGuard.Crashed()) {
+    NS_WARNING("DXVA2D3D11 crash detected");
+    aFailureReason.AssignLiteral("DXVA2D3D11 crashes detected in the past");
+    return E_FAIL;
+  }
+
   mDevice = gfxWindowsPlatform::GetPlatform()->CreateD3D11DecoderDevice();
   if (!mDevice) {
     aFailureReason.AssignLiteral("Failed to create D3D11 device for decoder");
     return E_FAIL;
   }
 
   mDevice->GetImmediateContext(getter_AddRefs(mContext));
   if (!mContext) {
--- a/dom/media/systemservices/MediaSystemResourceService.cpp
+++ b/dom/media/systemservices/MediaSystemResourceService.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "MediaSystemResourceManagerParent.h"
-#include "mozilla/layers/CompositorParent.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/unused.h"
 
 #include "MediaSystemResourceService.h"
 
 using namespace mozilla::layers;
 
 namespace mozilla {
 
@@ -41,17 +41,17 @@ MediaSystemResourceService::Shutdown()
     sSingleton->Destroy();
     sSingleton = nullptr;
   }
 }
 
 MediaSystemResourceService::MediaSystemResourceService()
   : mDestroyed(false)
 {
-  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
 #ifdef MOZ_WIDGET_GONK
   // The maximum number of hardware resoureces available.
   // XXX need to hange to a dynamic way.
   enum
   {
     VIDEO_DECODER_COUNT = 1,
     VIDEO_ENCODER_COUNT = 1
   };
@@ -77,17 +77,17 @@ MediaSystemResourceService::Destroy()
 }
 
 void
 MediaSystemResourceService::Acquire(media::MediaSystemResourceManagerParent* aParent,
                                     uint32_t aId,
                                     MediaSystemResourceType aResourceType,
                                     bool aWillWait)
 {
-  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
   MOZ_ASSERT(aParent);
 
   if (mDestroyed) {
     return;
   }
 
   MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
 
@@ -118,17 +118,17 @@ MediaSystemResourceService::Acquire(medi
     MediaSystemResourceRequest(aParent, aId));
 }
 
 void
 MediaSystemResourceService::ReleaseResource(media::MediaSystemResourceManagerParent* aParent,
                                             uint32_t aId,
                                             MediaSystemResourceType aResourceType)
 {
-  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
   MOZ_ASSERT(aParent);
 
   if (mDestroyed) {
     return;
   }
 
   MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
 
new file mode 100644
--- /dev/null
+++ b/dom/media/test/external/docs/.hgignore
@@ -0,0 +1,3 @@
+_build
+_static
+_templates
new file mode 100644
--- /dev/null
+++ b/dom/media/test/external/docs/Makefile
@@ -0,0 +1,216 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  applehelp  to make an Apple Help Book"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  xml        to make Docutils-native XML files"
+	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+	@echo "  coverage   to run coverage check of the documentation (if enabled)"
+
+.PHONY: clean
+clean:
+	rm -rf $(BUILDDIR)/*
+
+.PHONY: html
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+.PHONY: dirhtml
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+.PHONY: singlehtml
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+.PHONY: pickle
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+.PHONY: json
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+.PHONY: htmlhelp
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+.PHONY: qthelp
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ExternalMediaTests.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ExternalMediaTests.qhc"
+
+.PHONY: applehelp
+applehelp:
+	$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
+	@echo
+	@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
+	@echo "N.B. You won't be able to view it unless you put it in" \
+	      "~/Library/Documentation/Help or install it in your application" \
+	      "bundle."
+
+.PHONY: devhelp
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/ExternalMediaTests"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ExternalMediaTests"
+	@echo "# devhelp"
+
+.PHONY: epub
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+.PHONY: latex
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+.PHONY: latexpdf
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: latexpdfja
+latexpdfja:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through platex and dvipdfmx..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: text
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+.PHONY: man
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+.PHONY: texinfo
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+.PHONY: info
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+.PHONY: gettext
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+.PHONY: changes
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+.PHONY: linkcheck
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+.PHONY: doctest
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
+
+.PHONY: coverage
+coverage:
+	$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
+	@echo "Testing of coverage in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/coverage/python.txt."
+
+.PHONY: xml
+xml:
+	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+	@echo
+	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+.PHONY: pseudoxml
+pseudoxml:
+	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+	@echo
+	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
new file mode 100644
--- /dev/null
+++ b/dom/media/test/external/docs/conf.py
@@ -0,0 +1,297 @@
+# -*- coding: utf-8 -*-
+#
+# External Media Tests documentation build configuration file, created by
+# sphinx-quickstart on Tue Mar 15 15:58:18 2016.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.viewcode',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'External Media Tests'
+copyright = u'2015-2016, Mozilla, Inc.'
+author = u'Syd Polk and Maja Frydrychowicz'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = u'0.1'
+# The full version, including alpha/beta/rc tags.
+release = u'0.1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
+
+if not on_rtd:
+    try:
+        import sphinx_rtd_theme
+        html_theme = 'sphinx_rtd_theme'
+        html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
+    except ImportError:
+        pass
+
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (relative to this directory) to use as a favicon of
+# the docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+#   'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
+#   'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
+#html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# Now only 'ja' uses this config value
+#html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'ExternalMediaTestsdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+
+# Latex figure (float) alignment
+#'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (master_doc, 'ExternalMediaTests.tex', u'External Media Tests Documentation',
+     u'Syd Polk and Maja Frydrychowicz', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (master_doc, 'externalmediatests', u'External Media Tests Documentation',
+     [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (master_doc, 'ExternalMediaTests', u'External Media Tests Documentation',
+     author, 'ExternalMediaTests', 'One line description of project.',
+     'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
new file mode 100644
--- /dev/null
+++ b/dom/media/test/external/docs/external_media_harness.rst
@@ -0,0 +1,19 @@
+external_media_harness package
+==============================
+
+Test case classes for use in video tests
+
+external_media_harness.testcase module
+--------------------------------------
+
+.. autoclass:: external_media_harness.testcase.MediaTestCase
+    :members:
+    :show-inheritance:
+
+.. autoclass:: external_media_harness.testcase.NetworkBandwidthTestCase
+    :members:
+    :show-inheritance:
+
+.. autoclass:: external_media_harness.testcase.VideoPlaybackTestsMixin
+    :members:
+    :show-inheritance:
new file mode 100644
--- /dev/null
+++ b/dom/media/test/external/docs/external_media_tests.media_tests.video_puppeteer.rst
@@ -0,0 +1,27 @@
+VideoPuppeteer
+==============
+
+
+video_puppeteer.VideoPuppeteer
+------------------------------
+
+.. autoclass:: external_media_tests.media_utils.video_puppeteer.VideoPuppeteer
+    :members:
+    :show-inheritance:
+
+video_puppeteer.VideoException
+------------------------------
+
+.. autoexception:: external_media_tests.media_utils.video_puppeteer.VideoException
+
+video_puppeteer.playback_started
+--------------------------------
+
+.. autofunction:: external_media_tests.media_utils.video_puppeteer.playback_started
+
+video_puppeteer.playback_done
+-----------------------------
+
+.. autofunction:: external_media_tests.media_utils.video_puppeteer.playback_done
+
+
new file mode 100644
--- /dev/null
+++ b/dom/media/test/external/docs/external_media_tests.media_tests.youtube_puppeteer.rst
@@ -0,0 +1,26 @@
+YoutubePuppeteer
+================
+
+youtube_puppeteer.YouTubePuppeteer
+----------------------------------
+
+.. autoclass:: external_media_tests.media_utils.youtube_puppeteer.YouTubePuppeteer
+    :members:
+    :show-inheritance:
+
+youtube_puppeteer.playback_started
+----------------------------------
+
+.. autofunction:: external_media_tests.media_utils.youtube_puppeteer.playback_started
+
+youtube_puppeteer.playback_done
+-------------------------------
+
+.. autofunction:: external_media_tests.media_utils.youtube_puppeteer.playback_done
+
+youtbue_puppeteer.wait_for_almost_done
+--------------------------------------
+
+.. autofunction:: external_media_tests.media_utils.youtube_puppeteer.wait_for_almost_done
+
+
new file mode 100644
--- /dev/null
+++ b/dom/media/test/external/docs/external_media_tests.rst
@@ -0,0 +1,26 @@
+
+external_media_tests package
+============================
+
+This document highlights the utility classes for tests. In general, the indvidiual tests are not documented here.
+
+Test pacakges
+-------------
+
+.. toctree::
+
+    external_media_tests.media_tests.video_puppeteer
+    external_media_tests.media_tests.youtube_puppeteer
+
+
+external_media_tests.utils.verbose_until
+----------------------------------------
+
+.. autofunction:: external_media_tests.utils.verbose_until
+
+external_media_tests.utils.save_memory_report
+---------------------------------------------
+
+.. autofunction:: external_media_tests.utils.save_memory_report
+
+
new file mode 100644
--- /dev/null
+++ b/dom/media/test/external/docs/index.rst
@@ -0,0 +1,33 @@
+.. py:currentmodule:: external_media_tests
+
+External Media Tests
+====================
+
+External Media Tests is a library built on top of `Firefox Puppeter`_ and the `Marionette python client`_. It is designed to test playback of video elements embedded in web pages, independent of vendor. Using this library, you can write tests which play, pause, and stop videos, as well as inspect properties such as currentTime().
+
+.. _Marionette python client: http://marionette-client.readthedocs.org/en/latest
+.. _Firefox Puppeter: http://firefox-puppeteer.readthedocs.org/en/latest/
+
+Installation
+------------
+
+External Media Tests lives in `External Media Tests Source`_. Documentation for installation and usage lives on `External Media Tests`_; this documentation is API documentation for the various pieces of the test library.
+
+.. _External Media Tests Source: https://hg.mozilla.org/dom/media/test/external
+.. _External Media Tests: https://developer.mozilla.org/en-US/docs/Mozilla/QA/external-media-tests
+
+Contents
+--------
+
+.. toctree::
+
+    external_media_harness
+    external_media_tests
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
new file mode 100644
--- /dev/null
+++ b/dom/media/test/external/docs/make.bat
@@ -0,0 +1,263 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+	set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^<target^>` where ^<target^> is one of
+	echo.  html       to make standalone HTML files
+	echo.  dirhtml    to make HTML files named index.html in directories
+	echo.  singlehtml to make a single large HTML file
+	echo.  pickle     to make pickle files
+	echo.  json       to make JSON files
+	echo.  htmlhelp   to make HTML files and a HTML help project
+	echo.  qthelp     to make HTML files and a qthelp project
+	echo.  devhelp    to make HTML files and a Devhelp project
+	echo.  epub       to make an epub
+	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  texinfo    to make Texinfo files
+	echo.  gettext    to make PO message catalogs
+	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  xml        to make Docutils-native XML files
+	echo.  pseudoxml  to make pseudoxml-XML files for display purposes
+	echo.  linkcheck  to check all external links for integrity
+	echo.  doctest    to run all doctests embedded in the documentation if enabled
+	echo.  coverage   to run coverage check of the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+
+REM Check if sphinx-build is available and fallback to Python version if any
+%SPHINXBUILD% 1>NUL 2>NUL
+if errorlevel 9009 goto sphinx_python
+goto sphinx_ok
+
+:sphinx_python
+
+set SPHINXBUILD=python -m sphinx.__init__
+%SPHINXBUILD% 2> nul
+if errorlevel 9009 (
+	echo.
+	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+	echo.installed, then set the SPHINXBUILD environment variable to point
+	echo.to the full path of the 'sphinx-build' executable. Alternatively you
+	echo.may add the Sphinx directory to PATH.
+	echo.
+	echo.If you don't have Sphinx installed, grab it from
+	echo.http://sphinx-doc.org/
+	exit /b 1
+)
+
+:sphinx_ok
+
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ExternalMediaTests.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ExternalMediaTests.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "latexpdf" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	cd %BUILDDIR%/latex
+	make all-pdf
+	cd %~dp0
+	echo.
+	echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "latexpdfja" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	cd %BUILDDIR%/latex
+	make all-pdf-ja
+	cd %~dp0
+	echo.
+	echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "texinfo" (
+	%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+	goto end
+)
+
+if "%1" == "gettext" (
+	%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+if "%1" == "coverage" (
+	%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of coverage in the sources finished, look at the ^
+results in %BUILDDIR%/coverage/python.txt.
+	goto end
+)
+
+if "%1" == "xml" (
+	%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The XML files are in %BUILDDIR%/xml.
+	goto end
+)
+
+if "%1" == "pseudoxml" (
+	%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
+	goto end
+)
+
+:end
--- a/dom/media/test/external/external_media_harness/testcase.py
+++ b/dom/media/test/external/external_media_harness/testcase.py
@@ -12,54 +12,79 @@ from marionette.marionette_test import S
 from firefox_puppeteer.testcases import FirefoxTestCase
 from external_media_tests.utils import (timestamp_now, verbose_until)
 from external_media_tests.media_utils.video_puppeteer import (playback_done, playback_started,
                                          VideoException, VideoPuppeteer as VP)
 
 
 class MediaTestCase(FirefoxTestCase):
 
+    """
+    Necessary methods for MSE playback
+
+    :param video_urls: Urls you are going to play as part of the tests.
+    """
+
     def __init__(self, *args, **kwargs):
         self.video_urls = kwargs.pop('video_urls', False)
         FirefoxTestCase.__init__(self, *args, **kwargs)
 
     def save_screenshot(self):
+        """
+        Make a screenshot of the window that is currently playing the video
+        element.
+        """
         screenshot_dir = os.path.join(self.marionette.instance.workspace or '',
                                       'screenshots')
         filename = ''.join([self.id().replace(' ', '-'),
                             '_',
                             str(timestamp_now()),
                             '.png'])
         path = os.path.join(screenshot_dir, filename)
         if not os.path.exists(screenshot_dir):
             os.makedirs(screenshot_dir)
         with self.marionette.using_context('content'):
             img_data = self.marionette.screenshot()
         with open(path, 'wb') as f:
             f.write(img_data.decode('base64'))
         self.marionette.log('Screenshot saved in %s' % os.path.abspath(path))
 
     def log_video_debug_lines(self):
+        """
+        Log the debugging information that Firefox provides for video elements.
+        """
         with self.marionette.using_context('chrome'):
             debug_lines = self.marionette.execute_script(VP._debug_script)
             if debug_lines:
                 self.marionette.log('\n'.join(debug_lines))
 
     def run_playback(self, video):
+        """
+        Play the video all of the way through, or for the requested duration,
+        whichever comes first. Raises if the video stalls for too long.
+
+        :param video: VideoPuppeteer instance to play.
+        """
         with self.marionette.using_context('content'):
             self.logger.info(video.test_url)
             try:
                 verbose_until(Wait(video, interval=video.interval,
                                    timeout=video.expected_duration * 1.3 +
                                    video.stall_wait_time),
                               video, playback_done)
             except VideoException as e:
                 raise self.failureException(e)
 
     def check_playback_starts(self, video):
+        """
+        Check to see if a given video will start. Raises if the video does not
+        start.
+
+        :param video: VideoPuppeteer instance to play.
+        """
         with self.marionette.using_context('content'):
             self.logger.info(video.test_url)
             try:
                 verbose_until(Wait(video, timeout=video.timeout),
                               video, playback_started)
             except TimeoutException as e:
                 raise self.failureException(e)
 
@@ -69,54 +94,67 @@ class MediaTestCase(FirefoxTestCase):
 
         Skip with marionette.marionette_test import SkipTest so that it
         gets recognized a skip in marionette.marionette_test.CommonTestCase.run
         """
         raise SkipTest(reason)
 
 
 class NetworkBandwidthTestCase(MediaTestCase):
+    """
+    Test MSE playback while network bandwidth is limited. Uses browsermobproxy
+    (https://bmp.lightbody.net/). Please see
+    https://developer.mozilla.org/en-US/docs/Mozilla/QA/external-media-tests
+    for more information on setting up browsermob_proxy.
+    """
 
     def __init__(self, *args, **kwargs):
         MediaTestCase.__init__(self, *args, **kwargs)
         BrowserMobProxyTestCaseMixin.__init__(self, *args, **kwargs)
         self.proxy = None
 
     def setUp(self):
         MediaTestCase.setUp(self)
         BrowserMobProxyTestCaseMixin.setUp(self)
         self.proxy = self.create_browsermob_proxy()
 
     def tearDown(self):
         MediaTestCase.tearDown(self)
         BrowserMobProxyTestCaseMixin.tearDown(self)
         self.proxy = None
 
-
     def run_videos(self):
+        """
+        Run each of the videos in the video list. Raises if something goes
+        wrong in playback.
+        """
         with self.marionette.using_context('content'):
             for url in self.video_urls:
                 video = VP(self.marionette, url,
                                        stall_wait_time=60,
                                        set_duration=60)
                 self.run_playback(video)
 
 
 class VideoPlaybackTestsMixin(object):
 
     """ Test MSE playback in HTML5 video element.
 
     These tests should pass on any site where a single video element plays
     upon loading and is uninterrupted (by ads, for example).
 
-    This test both starting videos and performing partial playback at one
+    This tests both starting videos and performing partial playback at one
     minute each, and is the test that should be run frequently in automation.
     """
 
     def test_playback_starts(self):
+        """
+        Test to make sure that playback of the video element starts for each
+        video.
+        """
         with self.marionette.using_context('content'):
             for url in self.video_urls:
                 try:
                     video = VP(self.marionette, url, timeout=60)
                     # Second playback_started check in case video._start_time
                     # is not 0
                     self.check_playback_starts(video)
                     video.pause()
@@ -124,15 +162,17 @@ class VideoPlaybackTestsMixin(object):
                     if not src.startswith('mediasource'):
                         self.marionette.log('video is not '
                                             'mediasource: %s' % src,
                                             level='WARNING')
                 except TimeoutException as e:
                     raise self.failureException(e)
 
     def test_video_playback_partial(self):
-        """ First 60 seconds of video play well. """
+        """
+        Test to make sure that playback of 60 seconds works for each video.
+        """
         with self.marionette.using_context('content'):
             for url in self.video_urls:
                 video = VP(self.marionette, url,
                            stall_wait_time=10,
                            set_duration=60)
                 self.run_playback(video)
--- a/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
+++ b/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
@@ -37,29 +37,28 @@ class VideoPuppeteer(object):
     Wrapper to control and introspect HTML5 video elements.
 
     A note about properties like current_time and duration:
     These describe whatever stream is playing when the property is called.
     It is possible that many different streams are dynamically spliced
     together, so the video stream that is currently playing might be the main
     video or it might be something else, like an ad, for example.
 
-    Inputs:
-        marionette - The marionette instance this runs in.
-        url - the URL of the page containing the video element.
-        video_selector - the selector of the element that we want to
-            watch. This is set by default to 'video', which is what most
-            sites use, but others should work.
-        interval - The polling interval that is used to check progress.
-        set_duration - When set to >0, the polling and checking will stop
-            at the number of seconds specified. Otherwise, this will stop
-            at the end of the video.
-        stall_wait_time - The amount of time to wait to see if a stall has
-            cleared. If 0, do not check for stalls.
-        timeout - The amount of time to wait until the video starts.
+    :param marionette: The marionette instance this runs in.
+    :param url: the URL of the page containing the video element.
+    :param video_selector: the selector of the element that we want to watch.
+     This is set by default to 'video', which is what most sites use, but
+     others should work.
+    :param interval: The polling interval that is used to check progress.
+    :param set_duration: When set to >0, the polling and checking will stop at
+     the number of seconds specified. Otherwise, this will stop at the end
+     of the video.
+    :param stall_wait_time: The amount of time to wait to see if a stall has
+     cleared. If 0, do not check for stalls.
+    :param timeout: The amount of time to wait until the video starts.
     """
     def __init__(self, marionette, url, video_selector='video', interval=1,
                  set_duration=0, stall_wait_time=0, timeout=60):
         self.marionette = marionette
         self.test_url = url
         self.interval = interval
         self.stall_wait_time = stall_wait_time
         self.timeout = timeout
@@ -115,92 +114,133 @@ class VideoPuppeteer(object):
         if self._set_duration and self._start_time:
             set_duration += self._start_time
         if 0 < set_duration < video_duration:
             self.expected_duration = set_duration
         else:
             self.expected_duration = video_duration
 
     def get_debug_lines(self):
+        """
+        Get Firefox internal debugging for the video element.
+
+        :return: A text string that has Firefox-internal debugging information.
+        """
         with self.marionette.using_context('chrome'):
             debug_lines = self.marionette.execute_script(debug_script)
         return debug_lines
 
     def play(self):
+        """
+        Tell the video element to Play.
+        """
         self.execute_video_script('arguments[0].wrappedJSObject.play();')
 
     def pause(self):
+        """
+        Tell the video element to Pause.
+        """
         self.execute_video_script('arguments[0].wrappedJSObject.pause();')
 
     @property
     def duration(self):
         """
-        Return duration in seconds of whatever stream is playing right now.
+        :return: Duration in seconds of whatever stream is playing right now.
         """
         return self.execute_video_script('return arguments[0].'
                                          'wrappedJSObject.duration;') or 0
 
     @property
     def current_time(self):
         """
-        Return current time of whatever stream is playing right now.
+        :return: Current time of whatever stream is playing right now.
         """
+        # Note that self.current_time could temporarily refer to a
+        # spliced-in ad.
+
         return self.execute_video_script(
             'return arguments[0].wrappedJSObject.currentTime;') or 0
 
     @property
     def remaining_time(self):
-        # Note that self.current_time could temporarily refer to a
-        # spliced-in ad
+        """
+        :return: How much time is remaining given the duration of the video
+            and the duration that has been set.
+        """
         return self.expected_duration - self.current_time
 
     @property
     def video_src(self):
+        """
+        :return: The url of the actual video file, as opposed to the url
+            of the page with the video element.
+        """
         with self.marionette.using_context('content'):
             return self.video.get_attribute('src')
 
     @property
     def total_frames(self):
+        """
+        :return: Number of video frames created and dropped since the creation
+            of this video element.
+        """
         return self.execute_video_script("""
             return arguments[0].getVideoPlaybackQuality()["totalVideoFrames"];
             """)
 
     @property
     def dropped_frames(self):
+        """
+        :return: Number of video frames created and dropped since the creation
+            of this video element.
+        """
         return self.execute_video_script("""return
             arguments[0].getVideoPlaybackQuality()["droppedVideoFrames"];
             """) or 0
 
     @property
     def corrupted_frames(self):
+        """
+        :return: Number of video frames corrupted since the creation of this
+            video element. A corrupted frame may be created or dropped.
+        """
         return self.execute_video_script("""return
             arguments[0].getVideoPlaybackQuality()["corruptedVideoFrames"];
             """) or 0
 
     @property
     def video_url(self):
+        """
+        :return: The URL of the video that this element is playing.
+        """
         return self.execute_video_script('return arguments[0].baseURI;')
 
     @property
     def lag(self):
+        """
+        :return: The difference in time between where the video is currently
+            playing and where it should be playing given the time we started
+            the video.
+        """
         # Note that self.current_time could temporarily refer to a
         # spliced-in ad
         elapsed_current_time = self.current_time - self._start_time
         elapsed_wall_time = clock() - self._start_wall_time
         return elapsed_wall_time - elapsed_current_time
 
     def measure_progress(self):
         initial = self.current_time
         sleep(1)
         return self.current_time - initial
 
     def execute_video_script(self, script):
-        """ Execute JS script in 'content' context with access to video element.
+        """
+        Execute JS script in 'content' context with access to video element.
+
         :param script: script to be executed
-        `arguments[0]` in script refers to video element.
         :return: value returned by script
         """
         with self.marionette.using_context('content'):
             return self.marionette.execute_script(script,
                                                   script_args=[self.video])
 
     def __str__(self):
         messages = ['%s - test url: %s: {' % (type(self).__name__,
@@ -220,31 +260,48 @@ class VideoPuppeteer(object):
             ]
         else:
             messages += ['\tvideo: None']
         messages.append('}')
         return '\n'.join(messages)
 
 
 class VideoException(Exception):
+    """
+    Exception class to use for video-specific error processing.
+    """
     pass
 
 
 def playback_started(video):
+    """
+    Determine if video has started
+
+    :param video: The VideoPuppeteer instance that we are interested in.
+
+    :return: True if is playing; False otherwise
+    """
     try:
         return video.current_time > video._start_time
     except Exception as e:
         print ('Got exception %s' % e)
         return False
 
 
 def playback_done(video):
-    # If we are near the end and there is still a video element, then
-    # we are essentially done. If this happens to be last time we are polled
-    # before the video ends, we won't get another chance.
+    """
+    If we are near the end and there is still a video element, then
+    we are essentially done. If this happens to be last time we are polled
+    before the video ends, we won't get another chance.
+
+    :param video: The VideoPuppeteer instance that we are interested in.
+
+    :return: True if we are close enough to the end of playback; False
+        otherwise.
+    """
     remaining_time = video.remaining_time
     if abs(remaining_time) < video.interval:
         return True
 
     # Check to see if the video has stalled. Accumulate the amount of lag
     # since the video started, and if it is too high, then raise.
     if video.stall_wait_time and (video.lag > video.stall_wait_time):
         raise VideoException('Video %s stalled.\n%s' % (video.video_url,
--- a/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py
+++ b/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py
@@ -9,19 +9,21 @@ from json import loads
 from marionette_driver import By, expected, Wait
 from marionette_driver.errors import TimeoutException, NoSuchElementException
 from video_puppeteer import VideoPuppeteer, VideoException
 from external_media_tests.utils import verbose_until
 
 
 class YouTubePuppeteer(VideoPuppeteer):
     """
-    Wrapper around a YouTube #movie_player element
+    Wrapper around a YouTube #movie_player element.
 
-    Partial reference: https://developers.google.com/youtube/js_api_reference
+    Partial reference: https://developers.google.com/youtube/js_api_reference.
+    This reference is useful for site-specific features such as interacting
+    with ads, or accessing YouTube's debug data.
     """
 
     _yt_player_state = {
         'UNSTARTED': -1,
         'ENDED': 0,
         'PLAYING': 1,
         'PAUSED': 2,
         'BUFFERING': 3,
@@ -50,130 +52,202 @@ class YouTubePuppeteer(VideoPuppeteer):
             sleep(1)
             self.process_ad()
             if (self.ad_inactive and self.duration and not
                     self.player_buffering):
                 break
         self.update_expected_duration()
 
     def player_play(self):
-        """ Play via YouTube API. """
+        """
+        Play via YouTube API.
+        """
         self.execute_yt_script('arguments[1].wrappedJSObject.playVideo();')
 
     def player_pause(self):
-        """ Pause via YouTube API. """
+        """
+        Pause via YouTube API.
+        """
         self.execute_yt_script('arguments[1].wrappedJSObject.pauseVideo();')
 
     @property
     def player_duration(self):
-        """ Duration in seconds via YouTube API.
+        """
+
+        :return: Duration in seconds via YouTube API.
         """
         return self.execute_yt_script('return arguments[1].'
                                       'wrappedJSObject.getDuration();')
 
     @property
     def player_current_time(self):
-        """ Current time in seconds via YouTube API.
+        """
+
+        :return: Current time in seconds via YouTube API.
         """
         return self.execute_yt_script('return arguments[1].'
                                       'wrappedJSObject.getCurrentTime();')
 
     @property
     def player_remaining_time(self):
-        """ Remaining time in seconds via YouTube API.
+        """
+
+        :return: Remaining time in seconds via YouTube API.
         """
         return self.expected_duration - self.player_current_time
 
     def player_measure_progress(self):
-        """ Playback progress in seconds via YouTube API.
+        """
+
+        :return: Playback progress in seconds via YouTube API.
         """
         initial = self.player_current_time
         sleep(1)
         return self.player_current_time - initial
 
     def _get_player_debug_dict(self):
         text = self.execute_yt_script('return arguments[1].'
                                       'wrappedJSObject.getDebugText();')
         if text:
             try:
                 return loads(text)
             except ValueError:
                 self.marionette.log('Error loading json: DebugText',
                                     level='DEBUG')
 
     def execute_yt_script(self, script):
-        """ Execute JS script in 'content' context with access to video element and
+        """
+        Execute JS script in 'content' context with access to video element and
         YouTube #movie_player element.
+
         :param script: script to be executed.
-        `arguments[0]` in script refers to video element, `arguments[1]` refers
-        to #movie_player element (YouTube).
+
         :return: value returned by script
         """
         with self.marionette.using_context('content'):
             return self.marionette.execute_script(script,
                                                   script_args=[self.video,
                                                                self.player])
 
     @property
     def playback_quality(self):
+        """
+        Please see https://developers.google.com/youtube/js_api_reference#Playback_quality
+        for valid values.
+
+        :return: A string with a valid value returned via YouTube.
+        """
         return self.execute_yt_script('return arguments[1].'
                                       'wrappedJSObject.getPlaybackQuality();')
 
     @property
     def movie_id(self):
+        """
+
+        :return: The string that is the YouTube identifier.
+        """
         return self.execute_yt_script('return arguments[1].'
                                       'wrappedJSObject.'
                                       'getVideoData()["video_id"];')
 
     @property
     def movie_title(self):
+        """
+
+        :return: The title of the movie.
+        """
         title = self.execute_yt_script('return arguments[1].'
                                        'wrappedJSObject.'
                                        'getVideoData()["title"];')
         # title may include non-ascii characters; replace them to avoid
         # UnicodeEncodeError in string formatting for log messages
         return title.encode('ascii', 'replace')
 
     @property
     def player_url(self):
+        """
+
+        :return: The YouTube URL for the currently playing video.
+        """
         return self.execute_yt_script('return arguments[1].'
                                       'wrappedJSObject.getVideoUrl();')
 
     @property
     def player_state(self):
+        """
+
+        :return: The YouTube state of the video. See
+         https://developers.google.com/youtube/js_api_reference#getPlayerState
+         for valid values.
+        """
         state = self.execute_yt_script('return arguments[1].'
                                        'wrappedJSObject.getPlayerState();')
         return state
 
     @property
     def player_unstarted(self):
+        """
+        This and the following properties are based on the
+        player.getPlayerState() call
+        (https://developers.google.com/youtube/js_api_reference#Playback_status)
+
+        :return: True if the video has not yet started.
+        """
         return self.player_state == self._yt_player_state['UNSTARTED']
 
     @property
     def player_ended(self):
+        """
+
+        :return: True if the video playback has ended.
+        """
         return self.player_state == self._yt_player_state['ENDED']
 
     @property
     def player_playing(self):
+        """
+
+        :return: True if the video is playing.
+        """
         return self.player_state == self._yt_player_state['PLAYING']
 
     @property
     def player_paused(self):
+        """
+
+        :return: True if the video is paused.
+        """
         return self.player_state == self._yt_player_state['PAUSED']
 
     @property
     def player_buffering(self):
+        """
+
+        :return: True if the video is currently buffering.
+        """
         return self.player_state == self._yt_player_state['BUFFERING']
 
     @property
     def player_cued(self):
+        """
+
+        :return: True if the video is cued.
+        """
         return self.player_state == self._yt_player_state['CUED']
 
     @property
     def ad_state(self):
+        """
+        Get state of current ad.
+
+        :return: Returns one of the constants listed in
+         https://developers.google.com/youtube/js_api_reference#Playback_status
+         for an ad.
+
+        """
         # Note: ad_state is sometimes not accurate, due to some sort of lag?
         return self.execute_yt_script('return arguments[1].'
                                       'wrappedJSObject.getAdState();')
 
     @property
     def ad_format(self):
         """
         When ad is not playing, ad_format is False.
@@ -186,16 +260,20 @@ class YouTubePuppeteer(VideoPuppeteer):
             with self.marionette.using_context('content'):
                 ad_format = self.marionette.execute_script("""
                     return arguments[0].adFormat;""",
                     script_args=[state])
         return ad_format
 
     @property
     def ad_skippable(self):
+        """
+
+        :return: True if the current ad is skippable.
+        """
         state = self.get_ad_displaystate()
         skippable = False
         if state:
             with self.marionette.using_context('content'):
                 skippable = self.marionette.execute_script("""
                     return arguments[0].skippable;""",
                     script_args=[state])
         return skippable
@@ -204,55 +282,71 @@ class YouTubePuppeteer(VideoPuppeteer):
         # may return None
         return self.execute_yt_script('return arguments[1].'
                                       'wrappedJSObject.'
                                       'getOption("ad", "displaystate");')
 
     @property
     def breaks_count(self):
         """
-        Number of upcoming ad breaks.
+
+        :return: Number of upcoming ad breaks.
         """
         breaks = self.execute_yt_script('return arguments[1].'
                                         'wrappedJSObject.'
                                         'getOption("ad", "breakscount")')
         # if video is not associated with any ads, breaks will be null
         return breaks or 0
 
     @property
     def ad_inactive(self):
+        """
+
+        :return: True if the current ad is inactive.
+        """
         return (self.ad_ended or
                 self.ad_state == self._yt_player_state['UNSTARTED'])
 
     @property
     def ad_playing(self):
+        """
+
+        :return: True if an ad is playing.
+        """
         return self.ad_state == self._yt_player_state['PLAYING']
 
     @property
     def ad_ended(self):
+        """
+
+        :return: True if the current ad has ended.
+        """
         return self.ad_state == self._yt_player_state['ENDED']
 
     def process_ad(self):
+        """
+        Try to skip this ad. If not, wait for this ad to finish.
+        """
         if self.attempt_ad_skip() or self.ad_inactive:
             return
         ad_timeout = (self.search_ad_duration() or 30) + 5
         wait = Wait(self, timeout=ad_timeout, interval=1)
         try:
             self.marionette.log('process_ad: waiting %s s for ad' % ad_timeout)
             verbose_until(wait, self, lambda y: y.ad_ended, "Check if ad ended")
         except TimeoutException:
             self.marionette.log('Waiting for ad to end timed out',
                                 level='WARNING')
 
     def attempt_ad_skip(self):
         """
         Attempt to skip ad by clicking on skip-add button.
-        Return True if clicking of ad-skip button occurred.
+
+        :return: True if clicking of ad-skip button occurred.
         """
-        # Wait for ad to load and become skippable
         if self.ad_playing:
             self.marionette.log('Waiting while ad plays')
             sleep(10)
         else:
             # no ad playing
             return False
         if self.ad_skippable:
             selector = '#movie_player .videoAdUiSkipContainer'
@@ -269,16 +363,17 @@ class YouTubePuppeteer(VideoPuppeteer):
             except (TimeoutException, NoSuchElementException):
                 self.marionette.log('Could not obtain '
                                     'element: %s' % selector,
                                     level='WARNING')
         return False
 
     def search_ad_duration(self):
         """
+
         :return: ad duration in seconds, if currently displayed in player
         """
         if not (self.ad_playing or self.player_measure_progress() == 0):
             return None
         # If the ad is not Flash...
         if (self.ad_playing and self.video_src.startswith('mediasource') and
                 self.duration):
             return self.duration
@@ -299,22 +394,22 @@ class YouTubePuppeteer(VideoPuppeteer):
             self.marionette.log('Could not obtain '
                                 'element: %s' % selector,
                                 level='WARNING')
         return None
 
     @property
     def player_stalled(self):
         """
-        :return True if playback is not making progress for 4-9 seconds. This
-        excludes ad breaks.
 
-        Note that the player might just be busy with buffering due to a slow
-        network.
+        :return: True if playback is not making progress for 4-9 seconds. This
+         excludes ad breaks. Note that the player might just be busy with
+         buffering due to a slow network.
         """
+
         # `current_time` stands still while ad is playing
         def condition():
             # no ad is playing and current_time stands still
             return (not self.ad_playing and
                     self.measure_progress() < 0.1 and
                     self.player_measure_progress() < 0.1 and
                     (self.player_playing or self.player_buffering))
 
@@ -323,17 +418,19 @@ class YouTubePuppeteer(VideoPuppeteer):
             if self.player_buffering:
                 sleep(5)
             return condition()
         else:
             return False
 
     def deactivate_autoplay(self):
         """
-        Attempt to turn off autoplay. Return True if successful.
+        Attempt to turn off autoplay.
+
+        :return: True if successful.
         """
         element_id = 'autoplay-checkbox'
         mn = self.marionette
         wait = Wait(mn, timeout=10)
 
         def get_status(el):
             script = 'return arguments[0].wrappedJSObject.checked'
             return mn.execute_script(script, script_args=[el])
@@ -379,31 +476,33 @@ class YouTubePuppeteer(VideoPuppeteer):
         else:
             messages += ['\t#movie_player: None']
         return '\n'.join(messages)
 
 
 def playback_started(yt):
     """
     Check whether playback has started.
+
     :param yt: YouTubePuppeteer
     """
     # usually, ad is playing during initial buffering
     if (yt.player_state in
             [yt._yt_player_state['PLAYING'],
              yt._yt_player_state['BUFFERING']]):
         return True
     if yt.current_time > 0 or yt.player_current_time > 0:
         return True
     return False
 
 
 def playback_done(yt):
     """
     Check whether playback is done, skipping ads if possible.
+
     :param yt: YouTubePuppeteer
     """
     # in case ad plays at end of video
     if yt.ad_state == yt._yt_player_state['PLAYING']:
         yt.attempt_ad_skip()
         return False
     return yt.player_ended or yt.player_remaining_time < 1
 
--- a/dom/media/test/external/external_media_tests/utils.py
+++ b/dom/media/test/external/external_media_tests/utils.py
@@ -38,16 +38,18 @@ def verbose_until(wait, target, conditio
 
     return wait.until(condition, message=err_message)
 
 
 
 def save_memory_report(marionette):
     """
     Saves memory report (like about:memory) to current working directory.
+
+    :param marionette: Marionette instance to use for executing.
     """
     with marionette.using_context('chrome'):
         marionette.execute_async_script("""
             Components.utils.import("resource://gre/modules/Services.jsm");
             let Cc = Components.classes;
             let Ci = Components.interfaces;
             let dumper = Cc["@mozilla.org/memory-info-dumper;1"].
                         getService(Ci.nsIMemoryInfoDumper);
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1682,17 +1682,17 @@ nsresult nsPluginInstanceOwner::Dispatch
   if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
     // continue only for cases without child window
     return aFocusEvent->PreventDefault(); // consume event
   }
 #endif
 
   WidgetEvent* theEvent = aFocusEvent->WidgetEventPtr();
   if (theEvent) {
-    WidgetGUIEvent focusEvent(theEvent->mFlags.mIsTrusted, theEvent->mMessage,
+    WidgetGUIEvent focusEvent(theEvent->IsTrusted(), theEvent->mMessage,
                               nullptr);
     nsEventStatus rv = ProcessEvent(focusEvent);
     if (nsEventStatus_eConsumeNoDefault == rv) {
       aFocusEvent->PreventDefault();
       aFocusEvent->StopPropagation();
     }
   }
 
@@ -2041,17 +2041,17 @@ nsPluginInstanceOwner::HandleEvent(nsIDO
       eventType.EqualsLiteral("compositionend") ||
       eventType.EqualsLiteral("text")) {
     return DispatchCompositionToPlugin(aEvent);
   }
 
   nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aEvent));
   if (dragEvent && mInstance) {
     WidgetEvent* ievent = aEvent->WidgetEventPtr();
-    if (ievent && ievent->mFlags.mIsTrusted &&
+    if (ievent && ievent->IsTrusted() &&
         ievent->mMessage != eDragEnter && ievent->mMessage != eDragOver) {
       aEvent->PreventDefault();
     }
 
     // Let the plugin handle drag events.
     aEvent->StopPropagation();
   }
   return NS_OK;
--- a/dom/promise/tests/chrome.ini
+++ b/dom/promise/tests/chrome.ini
@@ -1,8 +1,7 @@
 [DEFAULT]
 skip-if = buildapp == 'b2g'
 
-[test_dependentPromises.html]
 [test_on_new_promise.html]
 [test_on_promise_settled.html]
 [test_on_promise_settled_duplicates.html]
 [test_promise_xrays.html]
--- a/dom/webidl/Animatable.webidl
+++ b/dom/webidl/Animatable.webidl
@@ -9,17 +9,21 @@
  * Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 dictionary KeyframeAnimationOptions : KeyframeEffectOptions {
   DOMString id = "";
 };
 
+dictionary AnimationFilter {
+  boolean subtree = false;
+};
+
 [NoInterfaceObject]
 interface Animatable {
   [Func="nsDocument::IsWebAnimationsEnabled", Throws]
   Animation animate(object? frames,
                     optional (unrestricted double or KeyframeAnimationOptions)
                       options);
   [Func="nsDocument::IsWebAnimationsEnabled"]
-  sequence<Animation> getAnimations();
+  sequence<Animation> getAnimations(optional AnimationFilter filter);
 };
--- a/dom/webidl/AnimationEffectTiming.webidl
+++ b/dom/webidl/AnimationEffectTiming.webidl
@@ -7,24 +7,21 @@
  * https://w3c.github.io/web-animations/#animationeffecttiming
  *
  * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [Func="nsDocument::IsWebAnimationsEnabled"]
 interface AnimationEffectTiming : AnimationEffectTimingReadOnly {
-  //Bug 1244633 - implement AnimationEffectTiming delay
-  //inherit attribute double                             delay;
+  inherit attribute double                             delay;
   inherit attribute double                             endDelay;
-  //Bug 1244637 - implement AnimationEffectTiming fill
-  //inherit attribute FillMode                           fill;
+  inherit attribute FillMode                           fill;
   [SetterThrows]
   inherit attribute double                             iterationStart;
-  //Bug 1244640 - implement AnimationEffectTiming iterations
-  //inherit attribute unrestricted double                iterations;
+  [SetterThrows]
+  inherit attribute unrestricted double                iterations;
   [SetterThrows]
   inherit attribute (unrestricted double or DOMString) duration;
-  //Bug 1244642 - implement AnimationEffectTiming direction
-  //inherit attribute PlaybackDirection                  direction;
-  //Bug 1244643 - implement AnimationEffectTiming easing
-  //inherit attribute DOMString                          easing;
+  inherit attribute PlaybackDirection                  direction;
+  [SetterThrows]
+  inherit attribute DOMString                          easing;
 };
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -1634,25 +1634,27 @@ CacheScriptLoader::ResolvedCallback(JSCo
 }
 
 NS_IMETHODIMP
 CacheScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
                                     nsresult aStatus, uint32_t aStringLen,
                                     const uint8_t* aString)
 {
   AssertIsOnMainThread();
-  MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::ReadingFromCache);
 
   mPump = nullptr;
 
   if (NS_FAILED(aStatus)) {
+    MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::ReadingFromCache ||
+               mLoadInfo.mCacheStatus == ScriptLoadInfo::Cancel);
     Fail(aStatus);
     return NS_OK;
   }
 
+  MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::ReadingFromCache);
   mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached;
 
   MOZ_ASSERT(mPrincipalInfo);
   mRunnable->DataReceivedFromCache(mIndex, aString, aStringLen, mChannelInfo,
                                    Move(mPrincipalInfo));
   return NS_OK;
 }
 
--- a/dom/workers/ServiceWorkerClients.cpp
+++ b/dom/workers/ServiceWorkerClients.cpp
@@ -596,17 +596,17 @@ private:
       nsCString spec;
       uri->GetSpec(spec);
 
       nsCOMPtr<mozIDOMWindowProxy> newWindow;
       pwwatch->OpenWindow2(nullptr,
                            spec.get(),
                            nullptr,
                            nullptr,
-                           false, false, true, nullptr, nullptr,
+                           false, false, true, nullptr, nullptr, 1.0f, 0,
                            getter_AddRefs(newWindow));
       nsCOMPtr<nsPIDOMWindowOuter> pwindow = nsPIDOMWindowOuter::From(newWindow);
       pwindow.forget(aWindow);
       return NS_OK;
     }
 
     // Find the most recent browser window and open a new tab in it.
     nsCOMPtr<nsPIDOMWindowOuter> browserWindow =
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -423,20 +423,20 @@ ExtractErrorValues(JSContext* aCx, JS::H
       }
       aMessageOut.Assign(report->mErrorMsg);
     }
 
     // Next, try to unwrap the rejection value as a DOMException.
     else if(NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException))) {
 
       nsAutoString filename;
-      domException->GetFilename(filename);
+      domException->GetFilename(aCx, filename);
       if (!filename.IsEmpty()) {
         CopyUTF16toUTF8(filename, aSourceSpecOut);
-        *aLineOut = domException->LineNumber();
+        *aLineOut = domException->LineNumber(aCx);
         *aColumnOut = domException->ColumnNumber();
       }
 
       domException->GetName(aMessageOut);
       aMessageOut.AppendLiteral(": ");
 
       nsAutoString message;
       domException->GetMessageMoz(message);
--- a/dom/xbl/nsXBLEventHandler.cpp
+++ b/dom/xbl/nsXBLEventHandler.cpp
@@ -92,17 +92,17 @@ nsXBLKeyEventHandler::ExecuteMatchedHand
 {
   WidgetEvent* event = aKeyEvent->AsEvent()->WidgetEventPtr();
   nsCOMPtr<EventTarget> target = aKeyEvent->AsEvent()->InternalDOMEvent()->GetCurrentTarget();
 
   bool executed = false;
   for (uint32_t i = 0; i < mProtoHandlers.Length(); ++i) {
     nsXBLPrototypeHandler* handler = mProtoHandlers[i];
     bool hasAllowUntrustedAttr = handler->HasAllowUntrustedAttr();
-    if ((event->mFlags.mIsTrusted ||
+    if ((event->IsTrusted() ||
         (hasAllowUntrustedAttr && handler->AllowUntrustedEvents()) ||
         (!hasAllowUntrustedAttr && !mIsBoundToChrome && !mUsingContentXBLScope)) &&
         handler->KeyEventMatched(aKeyEvent, aCharCode, aIgnoreModifierState)) {
       handler->ExecuteHandler(target, aKeyEvent->AsEvent());
       executed = true;
     }
   }
 #ifdef XP_WIN
@@ -135,28 +135,31 @@ nsXBLKeyEventHandler::HandleEvent(nsIDOM
     if (eventPhase != nsIDOMEvent::AT_TARGET)
       return NS_OK;
   }
 
   nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aEvent));
   if (!key)
     return NS_OK;
 
-  AutoTArray<nsShortcutCandidate, 10> accessKeys;
-  nsContentUtils::GetAccelKeyCandidates(key, accessKeys);
+  WidgetKeyboardEvent* nativeKeyboardEvent =
+    aEvent->WidgetEventPtr()->AsKeyboardEvent();
+  MOZ_ASSERT(nativeKeyboardEvent);
+  AutoShortcutKeyCandidateArray shortcutKeys;
+  nativeKeyboardEvent->GetShortcutKeyCandidates(shortcutKeys);
 
-  if (accessKeys.IsEmpty()) {
+  if (shortcutKeys.IsEmpty()) {
     ExecuteMatchedHandlers(key, 0, IgnoreModifierState());
     return NS_OK;
   }
 
-  for (uint32_t i = 0; i < accessKeys.Length(); ++i) {
+  for (uint32_t i = 0; i < shortcutKeys.Length(); ++i) {
     IgnoreModifierState ignoreModifierState;
-    ignoreModifierState.mShift = accessKeys[i].mIgnoreShift;
-    if (ExecuteMatchedHandlers(key, accessKeys[i].mCharCode,
+    ignoreModifierState.mShift = shortcutKeys[i].mIgnoreShift;
+    if (ExecuteMatchedHandlers(key, shortcutKeys[i].mCharCode,
                                ignoreModifierState)) {
       return NS_OK;
     }
   }
   return NS_OK;
 }
 
 ///////////////////////////////////////////////////////////////////////////////////
--- a/dom/xbl/nsXBLPrototypeHandler.h
+++ b/dom/xbl/nsXBLPrototypeHandler.h
@@ -85,38 +85,33 @@ public:
   // This constructor is used only by XUL key handlers (e.g., <key>)
   explicit nsXBLPrototypeHandler(nsIContent* aKeyElement);
 
   // This constructor is used for handlers loaded from the cache
   explicit nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding);
 
   ~nsXBLPrototypeHandler();
 
+  bool EventTypeEquals(nsIAtom* aEventType) const
+  {
+    return mEventName == aEventType;
+  }
+
   // if aCharCode is not zero, it is used instead of the charCode of aKeyEvent.
   bool KeyEventMatched(nsIDOMKeyEvent* aKeyEvent,
                        uint32_t aCharCode,
                        const IgnoreModifierState& aIgnoreModifierState);
-  inline bool KeyEventMatched(nsIAtom* aEventType,
-                              nsIDOMKeyEvent* aEvent,
-                              uint32_t aCharCode,
-                              const IgnoreModifierState& aIgnoreModifierState)
-  {
-    if (aEventType != mEventName)
-      return false;
-
-    return KeyEventMatched(aEvent, aCharCode, aIgnoreModifierState);
-  }
 
   bool MouseEventMatched(nsIDOMMouseEvent* aMouseEvent);
   inline bool MouseEventMatched(nsIAtom* aEventType,
                                   nsIDOMMouseEvent* aEvent)
   {
-    if (aEventType != mEventName)
+    if (!EventTypeEquals(aEventType)) {
       return false;
-
+    }
     return MouseEventMatched(aEvent);
   }
 
   already_AddRefed<nsIContent> GetHandlerElement();
 
   void AppendHandlerText(const nsAString& aText);
 
   uint8_t GetPhase() { return mPhase; }
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -412,17 +412,17 @@ nsXBLWindowKeyHandler::HandleEventOnCapt
     return;
   }
 
   bool isReserved = false;
   if (HasHandlerForEvent(aEvent, &isReserved) && isReserved) {
     // For reserved commands (such as Open New Tab), we don't to wait for
     // the content to answer (so mWantReplyFromContentProcess remains false),
     // neither to give a chance for content to override its behavior.
-    widgetKeyboardEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
+    widgetKeyboardEvent->StopCrossProcessForwarding();
     // If the key combination is reserved by chrome, we shouldn't expose the
     // keyboard event to web contents because such keyboard events shouldn't be
     // cancelable.  So, it's not good behavior to fire keyboard events but
     // to ignore the defaultPrevented attribute value in chrome.
     widgetKeyboardEvent->mFlags.mOnlySystemGroupDispatchInContent = true;
   }
 }
 
@@ -454,33 +454,16 @@ nsXBLWindowKeyHandler::HandleEventOnCapt
   // If this event hadn't been marked as mNoCrossProcessBoundaryForwarding
   // yet, it means it wasn't processed by content. We'll not call any
   // of the handlers at this moment, and will wait for the event to be
   // redispatched with mNoCrossProcessBoundaryForwarding = 1 to process it.
   // XXX Why not StopImmediatePropagation()?
   aEvent->AsEvent()->StopPropagation();
 }
 
-//
-// EventMatched
-//
-// See if the given handler cares about this particular key event
-//
-bool
-nsXBLWindowKeyHandler::EventMatched(
-                         nsXBLPrototypeHandler* aHandler,
-                         nsIAtom* aEventType,
-                         nsIDOMKeyEvent* aEvent,
-                         uint32_t aCharCode,
-                         const IgnoreModifierState& aIgnoreModifierState)
-{
-  return aHandler->KeyEventMatched(aEventType, aEvent, aCharCode,
-                                   aIgnoreModifierState);
-}
-
 bool
 nsXBLWindowKeyHandler::IsHTMLEditableFieldFocused()
 {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (!fm)
     return false;
 
   nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
@@ -538,146 +521,159 @@ nsXBLWindowKeyHandler::IsHTMLEditableFie
 //
 bool
 nsXBLWindowKeyHandler::WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
                                             nsIAtom* aEventType, 
                                             nsXBLPrototypeHandler* aHandler,
                                             bool aExecute,
                                             bool* aOutReservedForChrome)
 {
-  AutoTArray<nsShortcutCandidate, 10> accessKeys;
-  nsContentUtils::GetAccelKeyCandidates(aKeyEvent, accessKeys);
+  WidgetKeyboardEvent* nativeKeyboardEvent =
+    aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
+  MOZ_ASSERT(nativeKeyboardEvent);
 
-  if (accessKeys.IsEmpty()) {
+  AutoShortcutKeyCandidateArray shortcutKeys;
+  nativeKeyboardEvent->GetShortcutKeyCandidates(shortcutKeys);
+
+  if (shortcutKeys.IsEmpty()) {
     return WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
                                   0, IgnoreModifierState(),
                                   aExecute, aOutReservedForChrome);
   }
 
-  for (uint32_t i = 0; i < accessKeys.Length(); ++i) {
-    nsShortcutCandidate &key = accessKeys[i];
+  for (uint32_t i = 0; i < shortcutKeys.Length(); ++i) {
+    ShortcutKeyCandidate& key = shortcutKeys[i];
     IgnoreModifierState ignoreModifierState;
     ignoreModifierState.mShift = key.mIgnoreShift;
     if (WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
                                key.mCharCode, ignoreModifierState,
                                aExecute, aOutReservedForChrome)) {
       return true;
     }
   }
   return false;
 }
 
 bool
 nsXBLWindowKeyHandler::WalkHandlersAndExecute(
                          nsIDOMKeyEvent* aKeyEvent,
                          nsIAtom* aEventType,
-                         nsXBLPrototypeHandler* aHandler,
+                         nsXBLPrototypeHandler* aFirstHandler,
                          uint32_t aCharCode,
                          const IgnoreModifierState& aIgnoreModifierState,
                          bool aExecute,
                          bool* aOutReservedForChrome)
 {
-  nsresult rv;
-
   // Try all of the handlers until we find one that matches the event.
-  for (nsXBLPrototypeHandler *currHandler = aHandler; currHandler;
-       currHandler = currHandler->GetNextHandler()) {
+  for (nsXBLPrototypeHandler* handler = aFirstHandler;
+       handler;
+       handler = handler->GetNextHandler()) {
     bool stopped = aKeyEvent->AsEvent()->IsDispatchStopped();
     if (stopped) {
       // The event is finished, don't execute any more handlers
       return false;
     }
 
-    if (!EventMatched(currHandler, aEventType, aKeyEvent,
-                      aCharCode, aIgnoreModifierState)) {
+    if (aExecute) {
+      // If it's executing matched handlers, the event type should exactly be
+      // matched.
+      if (!handler->EventTypeEquals(aEventType)) {
+        continue;
+      }
+    } else {
+      if (handler->EventTypeEquals(nsGkAtoms::keypress)) {
+        // If the handler is a keypress event handler, we also need to check
+        // if coming keydown event is a preceding event of reserved key
+        // combination because if default action of a keydown event is
+        // prevented, following keypress event won't be fired.  However, if
+        // following keypress event is reserved, we shouldn't allow web
+        // contents to prevent the default of the preceding keydown event.
+        if (aEventType != nsGkAtoms::keydown &&
+            aEventType != nsGkAtoms::keypress) {
+          continue;
+        }
+      } else if (!handler->EventTypeEquals(aEventType)) {
+        // Otherwise, aEventType should exactly be matched.
+        continue;
+      }
+    }
+
+    // Check if the keyboard event *may* execute the handler.
+    if (!handler->KeyEventMatched(aKeyEvent, aCharCode, aIgnoreModifierState)) {
       continue;  // try the next one
     }
 
     // Before executing this handler, check that it's not disabled,
     // and that it has something to do (oncommand of the <key> or its
     // <command> is non-empty).
-    nsCOMPtr<nsIContent> elt = currHandler->GetHandlerElement();
-    nsCOMPtr<Element> commandElt;
+    nsCOMPtr<Element> commandElement;
+    if (!GetElementForHandler(handler, getter_AddRefs(commandElement))) {
+      continue;
+    }
 
-    // See if we're in a XUL doc.
-    nsCOMPtr<Element> el = GetElement();
-    if (el && elt) {
-      // We are.  Obtain our command attribute.
-      nsAutoString command;
-      elt->GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
-      if (!command.IsEmpty()) {
-        // Locate the command element in question.  Note that we
-        // know "elt" is in a doc if we're dealing with it here.
-        NS_ASSERTION(elt->IsInDoc(), "elt must be in document");
-        nsIDocument *doc = elt->GetCurrentDoc();
-        if (doc)
-          commandElt = do_QueryInterface(doc->GetElementById(command));
+    bool isReserved = false;
+    if (commandElement) {
+      if (!IsExecutableElement(commandElement)) {
+        continue;
+      }
 
-        if (!commandElt) {
-          NS_ERROR("A XUL <key> is observing a command that doesn't exist. Unable to execute key binding!");
-          continue;
-        }
+      isReserved =
+        commandElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::reserved,
+                                    nsGkAtoms::_true, eCaseMatters);
+      if (aOutReservedForChrome) {
+        *aOutReservedForChrome = isReserved;
       }
     }
 
-    if (!commandElt) {
-      commandElt = do_QueryInterface(elt);
+    if (!aExecute) {
+      if (handler->EventTypeEquals(aEventType)) {
+        return true;
+      }
+      // If the command is reserved and the event is keydown, check also if
+      // the handler is for keypress because if following keypress event is
+      // reserved, we shouldn't dispatch the event into web contents.
+      if (isReserved &&
+          aEventType == nsGkAtoms::keydown &&
+          handler->EventTypeEquals(nsGkAtoms::keypress)) {
+        return true;
+      }
+      // Otherwise, we've not found a handler for the event yet.
+      continue;
     }
 
-    if (commandElt) {
-      nsAutoString value;
-      commandElt->GetAttribute(NS_LITERAL_STRING("disabled"), value);
-      if (value.EqualsLiteral("true")) {
-        continue;  // this handler is disabled, try the next one
-      }
-
-      // Check that there is an oncommand handler
-      commandElt->GetAttribute(NS_LITERAL_STRING("oncommand"), value);
-      if (value.IsEmpty()) {
-        continue;  // nothing to do
-      }
-
-      if (aOutReservedForChrome) {
-        // The caller wants to know if this is a reserved command
-        commandElt->GetAttribute(NS_LITERAL_STRING("reserved"), value);
-        *aOutReservedForChrome = value.EqualsLiteral("true");
-      }
+    nsCOMPtr<EventTarget> target;
+    nsCOMPtr<Element> chromeHandlerElement = GetElement();
+    if (chromeHandlerElement) {
+      // XXX commandElement may be nullptr...
+      target = commandElement;
+    } else {
+      target = mTarget;
     }
 
-    nsCOMPtr<EventTarget> piTarget;
-    nsCOMPtr<Element> element = GetElement();
-    if (element) {
-      piTarget = commandElt;
-    } else {
-      piTarget = mTarget;
-    }
-
-    if (!aExecute) {
-      return true;
-    }
-
-    rv = currHandler->ExecuteHandler(piTarget, aKeyEvent->AsEvent());
+    // XXX Do we execute only one handler even if the handler neither stops
+    //     propagation nor prevents default of the event?
+    nsresult rv = handler->ExecuteHandler(target, aKeyEvent->AsEvent());
     if (NS_SUCCEEDED(rv)) {
       return true;
     }
   }
 
 #ifdef XP_WIN
   // Windows native applications ignore Windows-Logo key state when checking
   // shortcut keys even if the key is pressed.  Therefore, if there is no
   // shortcut key which exactly matches current modifier state, we should
   // retry to look for a shortcut key without the Windows-Logo key press.
   if (!aIgnoreModifierState.mOS) {
     WidgetKeyboardEvent* keyEvent =
       aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
     if (keyEvent && keyEvent->IsOS()) {
       IgnoreModifierState ignoreModifierState(aIgnoreModifierState);
       ignoreModifierState.mOS = true;
-      return WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler, aCharCode,
-                                    ignoreModifierState, aExecute);
+      return WalkHandlersAndExecute(aKeyEvent, aEventType, aFirstHandler,
+                                    aCharCode, ignoreModifierState, aExecute);
     }
   }
 #endif
 
   return false;
 }
 
 bool
@@ -712,16 +708,86 @@ nsXBLWindowKeyHandler::GetElement(bool* 
   nsCOMPtr<Element> element = do_QueryReferent(mWeakPtrForElement);
   if (element && aIsDisabled) {
     *aIsDisabled = element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
                                         nsGkAtoms::_true, eCaseMatters);
   }
   return element.forget();
 }
 
+bool
+nsXBLWindowKeyHandler::GetElementForHandler(nsXBLPrototypeHandler* aHandler,
+                                            Element** aElementForHandler)
+{
+  MOZ_ASSERT(aElementForHandler);
+  *aElementForHandler = nullptr;
+
+  nsCOMPtr<nsIContent> keyContent = aHandler->GetHandlerElement();
+  if (!keyContent) {
+    return true; // XXX Even though no key element?
+  }
+
+  nsCOMPtr<Element> chromeHandlerElement = GetElement();
+  if (!chromeHandlerElement) {
+    NS_WARN_IF(!keyContent->IsInDoc());
+    nsCOMPtr<Element> keyElement = do_QueryInterface(keyContent);
+    keyElement.swap(*aElementForHandler);
+    return true;
+  }
+
+  // We are in a XUL doc.  Obtain our command attribute.
+  nsAutoString command;
+  keyContent->GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
+  if (command.IsEmpty()) {
+    // There is no command element associated with the key element.
+    NS_WARN_IF(!keyContent->IsInDoc());
+    nsCOMPtr<Element> keyElement = do_QueryInterface(keyContent);
+    keyElement.swap(*aElementForHandler);
+    return true;
+  }
+
+  // XXX Shouldn't we check this earlier?
+  nsIDocument* doc = keyContent->GetCurrentDoc();
+  if (NS_WARN_IF(!doc)) {
+    return false;
+  }
+
+  nsCOMPtr<Element> commandElement =
+    do_QueryInterface(doc->GetElementById(command));
+  if (!commandElement) {
+    NS_ERROR("A XUL <key> is observing a command that doesn't exist. "
+             "Unable to execute key binding!");
+    return false;
+  }
+
+  commandElement.swap(*aElementForHandler);
+  return true;
+}
+
+bool
+nsXBLWindowKeyHandler::IsExecutableElement(Element* aElement) const
+{
+  if (!aElement) {
+    return false;
+  }
+
+  nsAutoString value;
+  aElement->GetAttribute(NS_LITERAL_STRING("disabled"), value);
+  if (value.EqualsLiteral("true")) {
+    return false;
+  }
+
+  aElement->GetAttribute(NS_LITERAL_STRING("oncommand"), value);
+  if (value.IsEmpty()) {
+    return false;
+  }
+
+  return true;
+}
+
 ///////////////////////////////////////////////////////////////////////////////////
 
 already_AddRefed<nsXBLWindowKeyHandler>
 NS_NewXBLWindowKeyHandler(nsIDOMElement* aElement, EventTarget* aTarget)
 {
   RefPtr<nsXBLWindowKeyHandler> result =
     new nsXBLWindowKeyHandler(aElement, aTarget);
   return result.forget();
--- a/dom/xbl/nsXBLWindowKeyHandler.h
+++ b/dom/xbl/nsXBLWindowKeyHandler.h
@@ -72,29 +72,43 @@ protected:
   // attribute.
   bool HasHandlerForEvent(nsIDOMKeyEvent* aEvent,
                           bool* aOutReservedForChrome = nullptr);
 
   // lazily load the handlers. Overridden to handle being attached
   // to a particular element rather than the document
   nsresult EnsureHandlers();
 
-  // check if the given handler cares about the given key event
-  bool EventMatched(nsXBLPrototypeHandler* aHandler, nsIAtom* aEventType,
-                    nsIDOMKeyEvent* aEvent, uint32_t aCharCode,
-                    const IgnoreModifierState& aIgnoreModifierState);
-
   // Is an HTML editable element focused
   bool IsHTMLEditableFieldFocused();
 
   // Returns the element which was passed as a parameter to the constructor,
   // unless the element has been removed from the document. Optionally returns
   // whether the disabled attribute is set on the element (assuming the element
   // is non-null).
   already_AddRefed<mozilla::dom::Element> GetElement(bool* aIsDisabled = nullptr);
+
+  /**
+   * GetElementForHandler() retrieves an element for the handler.  The element
+   * may be a command element or a key element.
+   *
+   * @param aHandler           The handler.
+   * @param aElementForHandler Must not be nullptr.  The element is returned to
+   *                           this.
+   * @return                   true if the handler is valid.  Otherwise, false.
+   */
+  bool GetElementForHandler(nsXBLPrototypeHandler* aHandler,
+                            mozilla::dom::Element** aElementForHandler);
+
+  /**
+   * IsExecutableElement() returns true if aElement is executable.
+   * Otherwise, false. aElement should be a command element or a key element.
+   */
+  bool IsExecutableElement(mozilla::dom::Element* aElement) const;
+
   // Using weak pointer to the DOM Element.
   nsWeakPtr              mWeakPtrForElement;
   mozilla::dom::EventTarget* mTarget; // weak ref
 
   // these are not owning references; the prototype handlers are owned
   // by the prototype bindings which are owned by the docinfo.
   nsXBLPrototypeHandler* mHandler;     // platform bindings
   nsXBLPrototypeHandler* mUserHandler; // user-specific bindings
--- a/dom/xslt/moz.build
+++ b/dom/xslt/moz.build
@@ -1,16 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
-    'nsIXSLTException.idl',
     'nsIXSLTProcessor.idl',
     'nsIXSLTProcessorPrivate.idl',
     'txIEXSLTRegExFunctions.idl',
     'txIFunctionEvaluationContext.idl',
     'txINodeSet.idl',
     'txIXPathObject.idl',
 ]
 
deleted file mode 100644
--- a/dom/xslt/nsIXSLTException.idl
+++ /dev/null
@@ -1,21 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* 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 "nsIException.idl"
-
-interface nsIDOMNode;
-
-[scriptable, uuid(e06dfaea-92d5-47f7-a800-c5f5404d8771)]
-interface nsIXSLTException : nsIException {
-    /**
-     * The node in the stylesheet that triggered the exception.
-     */
-    readonly attribute nsIDOMNode styleNode;
-
-    /**
-     * The context node, may be null
-     */
-    readonly attribute nsIDOMNode sourceNode;
-};
--- a/dom/xslt/nsIXSLTProcessor.idl
+++ b/dom/xslt/nsIXSLTProcessor.idl
@@ -15,43 +15,37 @@ interface nsIXSLTProcessor : nsISupports
      *
      * @param style The root-node of a XSLT stylesheet. This can be either
      *              a document node or an element node. If a document node
      *              then the document can contain either a XSLT stylesheet
      *              or a LRE stylesheet.
      *              If the argument is an element node it must be the
      *              xsl:stylesheet (or xsl:transform) element of an XSLT
      *              stylesheet.
-     *
-     * @exception nsIXSLTException
      */
     void importStylesheet(in nsIDOMNode style);
 
     /**
      * Transforms the node source applying the stylesheet given by
      * the importStylesheet() function. The owner document of the output node
      * owns the returned document fragment.
      *
      * @param source The node to be transformed
      * @param output This document is used to generate the output
      * @return DocumentFragment The result of the transformation
-     *
-     * @exception nsIXSLTException
      */
     nsIDOMDocumentFragment transformToFragment(in nsIDOMNode source,
                                                in nsIDOMDocument output);
 
     /**
      * Transforms the node source applying the stylesheet given by the
      * importStylesheet() function.
      *
      * @param source The node to be transformed
      * @return Document The result of the transformation
-     *
-     * @exception nsIXSLTException
      */
     nsIDOMDocument transformToDocument(in nsIDOMNode source);
 
     /**
      * Sets a parameter to be used in subsequent transformations with this
      * nsIXSLTProcessor. If the parameter doesn't exist in the stylesheet the
      * parameter will be ignored.
      *
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1327,17 +1327,17 @@ nsXULElement::PreHandleEvent(EventChainP
                     } else {
                         domEvent = nullptr;
                     }
                 }
 
                 WidgetInputEvent* orig = aVisitor.mEvent->AsInputEvent();
                 nsContentUtils::DispatchXULCommand(
                   commandContent,
-                  aVisitor.mEvent->mFlags.mIsTrusted,
+                  aVisitor.mEvent->IsTrusted(),
                   aVisitor.mDOMEvent,
                   nullptr,
                   orig->IsControl(),
                   orig->IsAlt(),
                   orig->IsShift(),
                   orig->IsMeta());
             } else {
                 NS_WARNING("A XUL element is attached to a command that doesn't exist!\n");
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -5097,17 +5097,17 @@ nsEditor::IsAcceptableInputEvent(nsIDOME
       break;
   }
   if (needsWidget &&
       (!widgetGUIEvent || !widgetGUIEvent->widget)) {
     return false;
   }
 
   // Accept all trusted events.
-  if (widgetEvent->mFlags.mIsTrusted) {
+  if (widgetEvent->IsTrusted()) {
     return true;
   }
 
   // Ignore untrusted mouse event.
   // XXX Why are we handling other untrusted input events?
   if (widgetEvent->AsMouseEventBase()) {
     return false;
   }
--- a/embedding/components/windowwatcher/nsPIWindowWatcher.idl
+++ b/embedding/components/windowwatcher/nsPIWindowWatcher.idl
@@ -53,33 +53,38 @@ interface nsPIWindowWatcher : nsISupport
       @param aCalledFromScript true if we were called from script.
       @param aDialog use dialog defaults (see nsIDOMWindow::openDialog)
       @param aNavigate true if we should navigate the new window to the
              specified URL.
       @param aOpeningTab the nsITabParent that is opening the new window. The
                          nsITabParent is a remote tab belonging to aParent. Can
                          be nullptr if this window is not being opened from a tab.
       @param aArgs Window argument
+      @param aOpenerFullZoom the full zoom multiplier for the opener window.
+                             this can be null in the single process case where
+                             the opener full zoom is obtained from aParent.
       @return the new window
 
       @note This method may examine the JS context stack for purposes of
             determining the security context to use for the search for a given
             window named aName.
       @note This method should try to set the default charset for the new
             window to the default charset of the document in the calling window
             (which is determined based on the JS stack and the value of
             aParent).  This is not guaranteed, however.
   */
+  [optional_argc]
   mozIDOMWindowProxy openWindow2(in mozIDOMWindowProxy aParent, in string aUrl,
                                  in string aName, in string aFeatures,
                                  in boolean aCalledFromScript,
                                  in boolean aDialog,
                                  in boolean aNavigate,
                                  in nsITabParent aOpeningTab,
-                                 in nsISupports aArgs);
+                                 in nsISupports aArgs,
+                                 [optional] in float aOpenerFullZoom);
 
   /**
    * Find a named docshell tree item amongst all windows registered
    * with the window watcher.  This may be a subframe in some window,
    * for example.
    *
    * @param aName the name of the window.  Must not be null.
    * @param aRequestor the tree item immediately making the request.
--- a/embedding/components/windowwatcher/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp
@@ -363,17 +363,18 @@ nsWindowWatcher::OpenWindow(mozIDOMWindo
   uint32_t argc = 0;
   if (argv) {
     argv->GetLength(&argc);
   }
   bool dialog = (argc != 0);
 
   return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
                             /* calledFromJS = */ false, dialog,
-                            /* navigate = */ true, nullptr, argv, aResult);
+                            /* navigate = */ true, nullptr, argv,
+                            /* openerFullZoom = */ nullptr, aResult);
 }
 
 struct SizeSpec
 {
   SizeSpec()
     : mLeftSpecified(false)
     , mTopSpecified(false)
     , mOuterWidthSpecified(false)
@@ -421,16 +422,18 @@ nsWindowWatcher::OpenWindow2(mozIDOMWind
                              const char* aUrl,
                              const char* aName,
                              const char* aFeatures,
                              bool aCalledFromScript,
                              bool aDialog,
                              bool aNavigate,
                              nsITabParent* aOpeningTab,
                              nsISupports* aArguments,
+                             float aOpenerFullZoom,
+                             uint8_t aOptionalArgc,
                              mozIDOMWindowProxy** aResult)
 {
   nsCOMPtr<nsIArray> argv = ConvertArgsToArray(aArguments);
 
   uint32_t argc = 0;
   if (argv) {
     argv->GetLength(&argc);
   }
@@ -440,17 +443,19 @@ nsWindowWatcher::OpenWindow2(mozIDOMWind
   // called from script.  Fixing this is bug 779939.
   bool dialog = aDialog;
   if (!aCalledFromScript) {
     dialog = argc > 0;
   }
 
   return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
                             aCalledFromScript, dialog,
-                            aNavigate, aOpeningTab, argv, aResult);
+                            aNavigate, aOpeningTab, argv,
+                            aOptionalArgc >= 1 ? &aOpenerFullZoom : nullptr,
+                            aResult);
 }
 
 // This static function checks if the aDocShell uses an UserContextId equal to
 // nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID or equal to the
 // userContextId of subjectPrincipal, if not null.
 static bool
 CheckUserContextCompatibility(nsIDocShell* aDocShell)
 {
@@ -483,16 +488,17 @@ nsWindowWatcher::OpenWindowInternal(mozI
                                     const char* aUrl,
                                     const char* aName,
                                     const char* aFeatures,
                                     bool aCalledFromJS,
                                     bool aDialog,
                                     bool aNavigate,
                                     nsITabParent* aOpeningTab,
                                     nsIArray* aArgv,
+                                    float* aOpenerFullZoom,
                                     mozIDOMWindowProxy** aResult)
 {
   nsresult rv = NS_OK;
   bool isNewToplevelWindow = false;
   bool windowIsNew = false;
   bool windowNeedsName = false;
   bool windowIsModal = false;
   bool uriToLoadIsChrome = false;
@@ -1070,17 +1076,18 @@ nsWindowWatcher::OpenWindowInternal(mozI
                                        getter_AddRefs(storage));
       if (storage) {
         newStorageManager->CloneStorage(storage);
       }
     }
   }
 
   if (isNewToplevelWindow) {
-    SizeOpenedDocShellItem(newDocShellItem, aParent, isCallerChrome, sizeSpec);
+    SizeOpenedDocShellItem(newDocShellItem, aParent, isCallerChrome, sizeSpec,
+                           aOpenerFullZoom);
   }
 
   // XXXbz isn't windowIsModal always true when windowIsModalContentDialog?
   if (windowIsModal || windowIsModalContentDialog) {
     nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
     newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
     nsCOMPtr<nsIWebBrowserChrome> newChrome(do_GetInterface(newTreeOwner));
 
@@ -2050,35 +2057,36 @@ nsWindowWatcher::CalcSizeSpec(const char
    is assumed to be called after the window has already been given
    a default position and size; thus its current position and size are
    accurate defaults. The new window is made visible at method end.
 */
 void
 nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem* aDocShellItem,
                                         mozIDOMWindowProxy* aParent,
                                         bool aIsCallerChrome,
-                                        const SizeSpec& aSizeSpec)
+                                        const SizeSpec& aSizeSpec,
+                                        float* aOpenerFullZoom)
 {
   // position and size of window
   int32_t left = 0, top = 0, width = 100, height = 100;
   // difference between chrome and content size
   int32_t chromeWidth = 0, chromeHeight = 0;
   // whether the window size spec refers to chrome or content
   bool sizeChromeWidth = true, sizeChromeHeight = true;
 
   // get various interfaces for aDocShellItem, used throughout this method
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
   aDocShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(treeOwner));
   if (!treeOwnerAsWin) { // we'll need this to actually size the docshell
     return;
   }
 
-  double openerZoom = 1.0;
-  if (aParent) {
+  double openerZoom = aOpenerFullZoom ? *aOpenerFullZoom : 1.0;
+  if (aParent && !aOpenerFullZoom) {
     nsCOMPtr<nsPIDOMWindowOuter> piWindow = nsPIDOMWindowOuter::From(aParent);
     if (nsIDocument* doc = piWindow->GetDoc()) {
       if (nsIPresShell* shell = doc->GetShell()) {
         if (nsPresContext* presContext = shell->GetPresContext()) {
           openerZoom = presContext->GetFullZoom();
         }
       }
     }
--- a/embedding/components/windowwatcher/nsWindowWatcher.h
+++ b/embedding/components/windowwatcher/nsWindowWatcher.h
@@ -79,16 +79,17 @@ protected:
                               const char* aUrl,
                               const char* aName,
                               const char* aFeatures,
                               bool aCalledFromJS,
                               bool aDialog,
                               bool aNavigate,
                               nsITabParent* aOpeningTab,
                               nsIArray* aArgv,
+                              float* aOpenerFullZoom,
                               mozIDOMWindowProxy** aResult);
 
   static nsresult URIfromURL(const char* aURL,
                              mozIDOMWindowProxy* aParent,
                              nsIURI** aURI);
 
   static uint32_t CalculateChromeFlags(mozIDOMWindowProxy* aParent,
                                        const char* aFeatures,
@@ -104,17 +105,18 @@ protected:
   static void CalcSizeSpec(const char* aFeatures, SizeSpec& aResult);
   static nsresult ReadyOpenedDocShellItem(nsIDocShellTreeItem* aOpenedItem,
                                           nsPIDOMWindowOuter* aParent,
                                           bool aWindowIsNew,
                                           mozIDOMWindowProxy** aOpenedWindow);
   static void SizeOpenedDocShellItem(nsIDocShellTreeItem* aDocShellItem,
                                      mozIDOMWindowProxy* aParent,
                                      bool aIsCallerChrome,
-                                     const SizeSpec& aSizeSpec);
+                                     const SizeSpec& aSizeSpec,
+                                     float* aOpenerFullZoom);
   static void GetWindowTreeItem(mozIDOMWindowProxy* aWindow,
                                 nsIDocShellTreeItem** aResult);
   static void GetWindowTreeOwner(nsPIDOMWindowOuter* aWindow,
                                  nsIDocShellTreeOwner** aResult);
 
   nsTArray<nsWatcherWindowEnumerator*> mEnumeratorList;
   nsWatcherWindowEntry* mOldestWindow;
   mozilla::Mutex mListLock;
--- a/embedding/test/mochitest.ini
+++ b/embedding/test/mochitest.ini
@@ -7,9 +7,9 @@ support-files =
 skip-if = (toolkit == "cocoa" && e10s) # bug 1252223
 [test_bug499115.html]
 [test_nsFind.html]
 [test_private_window_from_content.html]
 # Next two tests are disabled in e10s because of bug 989501.
 [test_window_open_position_constraint.html]
 skip-if = toolkit == 'android' || buildapp == 'mulet'
 [test_window_open_units.html]
-skip-if = toolkit == 'android' || e10s || buildapp == 'mulet'
+skip-if = toolkit == 'android' || buildapp == 'mulet'
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -951,16 +951,25 @@ public:
    * @param aOptions Drawing options
    */
   virtual void MaskSurface(const Pattern &aSource,
                            SourceSurface *aMask,
                            Point aOffset,
                            const DrawOptions &aOptions = DrawOptions()) = 0;
 
   /**
+   * Draw aSurface using the 3D transform aMatrix. The DrawTarget's transform
+   * and clip are applied after the 3D transform.
+   *
+   * If the transform fails (i.e. because aMatrix is singular), false is returned and nothing is drawn.
+   */
+  virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
+                                        const Matrix4x4& aMatrix);
+
+  /**
    * Push a clip to the DrawTarget.
    *
    * @param aPath The path to clip to
    */
   virtual void PushClip(const Path *aPath) = 0;
 
   /**
    * Push an axis-aligned rectangular clip to the DrawTarget. This rectangle
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -34,16 +34,19 @@
 #include "cairo-xlib.h"
 #include "cairo-xlib-xrender.h"
 #endif
 
 #ifdef CAIRO_HAS_WIN32_SURFACE
 #include "cairo-win32.h"
 #endif
 
+#define PIXMAN_DONT_DEFINE_STDINT
+#include "pixman.h"
+
 #include <algorithm>
 
 // 2^23
 #define CAIRO_COORD_MAX (Float(0x7fffff))
 
 namespace mozilla {
 
 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCairoSurface, cairo_surface_t, cairo_surface_destroy);
@@ -1850,16 +1853,254 @@ DrawTargetCairo::CreateShadowDrawTarget(
 
   RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
   if (target->InitAlreadyReferenced(tee, aSize)) {
     return target.forget();
   }
   return nullptr;
 }
 
+static inline pixman_format_code_t
+GfxFormatToPixmanFormat(SurfaceFormat aFormat)
+{
+  switch (aFormat) {
+  case SurfaceFormat::A8R8G8B8_UINT32:
+    return PIXMAN_a8r8g8b8;
+  case SurfaceFormat::X8R8G8B8_UINT32:
+    return PIXMAN_x8r8g8b8;
+  case SurfaceFormat::R5G6B5_UINT16:
+    return PIXMAN_r5g6b5;
+  case SurfaceFormat::A8:
+    return PIXMAN_a8;
+  default:
+    // Allow both BGRA and ARGB formats to be passed through unmodified,
+    // even though even though we are actually rendering to A8R8G8B8_UINT32.
+    if (aFormat == SurfaceFormat::B8G8R8A8 ||
+        aFormat == SurfaceFormat::A8R8G8B8) {
+      return PIXMAN_a8r8g8b8;
+    }
+    return (pixman_format_code_t)0;
+  }
+}
+
+static inline bool
+GfxMatrixToPixmanTransform(const Matrix4x4 &aMatrix, pixman_transform* aResult)
+{
+  pixman_f_transform fTransform = {{
+    { aMatrix._11, aMatrix._21, aMatrix._41 },
+    { aMatrix._12, aMatrix._22, aMatrix._42 },
+    { aMatrix._14, aMatrix._24, aMatrix._44 }
+  }};
+  return pixman_transform_from_pixman_f_transform(aResult, &fTransform);
+}
+
+#ifndef USE_SKIA
+bool
+DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
+{
+  // Composite the 3D transform with the DT's transform.
+  Matrix4x4 fullMat = aMatrix * Matrix4x4::From2D(mTransform);
+  // Transform the surface bounds and clip to this DT.
+  IntRect xformBounds =
+    RoundedOut(
+      fullMat.TransformAndClipBounds(Rect(Point(0, 0), Size(aSurface->GetSize())),
+                                     Rect(Point(0, 0), Size(GetSize()))));
+  if (xformBounds.IsEmpty()) {
+    return true;
+  }
+  // Offset the matrix by the transformed origin.
+  fullMat.PostTranslate(-xformBounds.x, -xformBounds.y, 0);
+  // Invert the matrix into a pattern matrix for pixman.
+  if (!fullMat.Invert()) {
+    return false;
+  }
+  pixman_transform xform;
+  if (!GfxMatrixToPixmanTransform(fullMat, &xform)) {
+    return false;
+  }
+
+  // Read in the source data.
+  RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
+  pixman_format_code_t srcFormat = GfxFormatToPixmanFormat(srcSurf->GetFormat());
+  if (!srcFormat) {
+    return false;
+  }
+  DataSourceSurface::ScopedMap srcMap(srcSurf, DataSourceSurface::READ);
+  if (!srcMap.IsMapped()) {
+    return false;
+  }
+
+  // Set up an intermediate destination surface only the size of the transformed bounds.
+  // Try to pass through the source's format unmodified in both the BGRA and ARGB cases.
+  RefPtr<DataSourceSurface> dstSurf =
+    Factory::CreateDataSourceSurface(xformBounds.Size(),
+                                     srcFormat == PIXMAN_a8r8g8b8 ?
+                                       srcSurf->GetFormat() : SurfaceFormat::A8R8G8B8_UINT32);
+  if (!dstSurf) {
+    return false;
+  }
+
+  // Wrap the surfaces in pixman images and do the transform.
+  pixman_image_t* dst =
+    pixman_image_create_bits(PIXMAN_a8r8g8b8,
+                             xformBounds.width, xformBounds.height,
+                             (uint32_t*)dstSurf->GetData(), dstSurf->Stride());
+  pixman_image_t* src =
+    pixman_image_create_bits(srcFormat,
+                             srcSurf->GetSize().width, srcSurf->GetSize().height,
+                             (uint32_t*)srcMap.GetData(), srcMap.GetStride());
+  MOZ_ASSERT(src && dst, "Failed to create pixman images?");
+
+  pixman_image_set_filter(src, PIXMAN_FILTER_BILINEAR, nullptr, 0);
+  pixman_image_set_transform(src, &xform);
+
+  pixman_image_composite32(PIXMAN_OP_SRC,
+                           src, nullptr, dst,
+                           0, 0, 0, 0, 0, 0,
+                           xformBounds.width, xformBounds.height);
+
+  pixman_image_unref(dst);
+  pixman_image_unref(src);
+
+  // Temporarily reset the DT's transform, since it has already been composed above.
+  Matrix origTransform = mTransform;
+  SetTransform(Matrix());
+
+  // Draw the transformed surface within the transformed bounds.
+  DrawSurface(dstSurf, Rect(xformBounds), Rect(Point(0, 0), Size(xformBounds.Size())));
+
+  SetTransform(origTransform);
+
+  return true;
+}
+#endif
+
+#ifdef CAIRO_HAS_XLIB_SURFACE
+static bool gXRenderInitialized = false;
+static bool gXRenderHasTransform = false;
+
+static bool
+SupportsXRender(cairo_surface_t* surface)
+{
+  if (!surface ||
+      cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_XLIB ||
+      !cairo_xlib_surface_get_xrender_format(surface)) {
+    return false;
+  }
+
+  if (gXRenderInitialized) {
+    return true;
+  }
+  gXRenderInitialized = true;
+
+  cairo_device_t* device = cairo_surface_get_device(surface);
+  if (cairo_device_acquire(device) != CAIRO_STATUS_SUCCESS) {
+    return false;
+  }
+
+  Display* display = cairo_xlib_surface_get_display(surface);
+  int major, minor;
+  if (XRenderQueryVersion(display, &major, &minor)) {
+    if (major > 0 || (major == 0 && minor >= 6)) {
+      gXRenderHasTransform = true;
+    }
+  }
+
+  cairo_device_release(device);
+
+  return true;
+}
+#endif
+
+bool
+DrawTargetCairo::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
+{
+#if CAIRO_HAS_XLIB_SURFACE
+  cairo_surface_t* srcSurf =
+    aSurface->GetType() == SurfaceType::CAIRO ?
+      static_cast<SourceSurfaceCairo*>(aSurface)->GetSurface() : nullptr;
+  if (!SupportsXRender(srcSurf) || !gXRenderHasTransform) {
+    return DrawTarget::Draw3DTransformedSurface(aSurface, aMatrix);
+  }
+
+  Matrix4x4 fullMat = aMatrix * Matrix4x4::From2D(mTransform);
+  IntRect xformBounds =
+    RoundedOut(
+      fullMat.TransformAndClipBounds(Rect(Point(0, 0), Size(aSurface->GetSize())),
+                                     Rect(Point(0, 0), Size(GetSize()))));
+  if (xformBounds.IsEmpty()) {
+    return true;
+  }
+  fullMat.PostTranslate(-xformBounds.x, -xformBounds.y, 0);
+  if (!fullMat.Invert()) {
+    return false;
+  }
+  pixman_transform xform;
+  if (!GfxMatrixToPixmanTransform(fullMat, &xform)) {
+    return false;
+  }
+
+  cairo_surface_t* xformSurf =
+    cairo_surface_create_similar(srcSurf, CAIRO_CONTENT_COLOR_ALPHA,
+                                 xformBounds.width, xformBounds.height);
+  if (!SupportsXRender(xformSurf)) {
+    cairo_surface_destroy(xformSurf);
+    return false;
+  }
+  cairo_device_t* device = cairo_surface_get_device(xformSurf);
+  if (cairo_device_acquire(device) != CAIRO_STATUS_SUCCESS) {
+    cairo_surface_destroy(xformSurf);
+    return false;
+  }
+
+  Display* display = cairo_xlib_surface_get_display(xformSurf);
+
+  Picture srcPict = XRenderCreatePicture(display,
+                                         cairo_xlib_surface_get_drawable(srcSurf),
+                                         cairo_xlib_surface_get_xrender_format(srcSurf),
+                                         0, nullptr);
+  XRenderSetPictureFilter(display, srcPict, FilterBilinear, nullptr, 0);
+  XRenderSetPictureTransform(display, srcPict, (XTransform*)&xform);
+
+  Picture dstPict = XRenderCreatePicture(display,
+                                         cairo_xlib_surface_get_drawable(xformSurf),
+                                         cairo_xlib_surface_get_xrender_format(xformSurf),
+                                         0, nullptr);
+
+  XRenderComposite(display, PictOpSrc,
+                   srcPict, None, dstPict,
+                   0, 0, 0, 0, 0, 0,
+                   xformBounds.width, xformBounds.height);
+
+  XRenderFreePicture(display, srcPict);
+  XRenderFreePicture(display, dstPict);
+
+  cairo_device_release(device);
+  cairo_surface_mark_dirty(xformSurf);
+
+  AutoPrepareForDrawing(this, mContext);
+
+  cairo_identity_matrix(mContext);
+
+  cairo_set_operator(mContext, CAIRO_OPERATOR_OVER);
+  cairo_set_antialias(mContext, CAIRO_ANTIALIAS_DEFAULT);
+  cairo_set_source_surface(mContext, xformSurf, xformBounds.x, xformBounds.y);
+
+  cairo_new_path(mContext);
+  cairo_rectangle(mContext, xformBounds.x, xformBounds.y, xformBounds.width, xformBounds.height);
+  cairo_fill(mContext);
+
+  cairo_surface_destroy(xformSurf);
+
+  return true;
+#else
+  return DrawTarget::Draw3DTransformedSurface(aSurface, aMatrix);
+#endif
+}
+
 bool
 DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat)
 {
   cairo_surface_reference(aSurface);
   return InitAlreadyReferenced(aSurface, aSize, aFormat);
 }
 
 bool
--- a/gfx/2d/DrawTargetCairo.h
+++ b/gfx/2d/DrawTargetCairo.h
@@ -129,16 +129,19 @@ public:
   virtual void Mask(const Pattern &aSource,
                     const Pattern &aMask,
                     const DrawOptions &aOptions = DrawOptions()) override;
   virtual void MaskSurface(const Pattern &aSource,
                            SourceSurface *aMask,
                            Point aOffset,
                            const DrawOptions &aOptions = DrawOptions()) override;
 
+  virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
+                                        const Matrix4x4& aMatrix) override;
+
   virtual void PushClip(const Path *aPath) override;
   virtual void PushClipRect(const Rect &aRect) override;
   virtual void PopClip() override;
   virtual void PushLayer(bool aOpaque, Float aOpacity,
                          SourceSurface* aMask,
                          const Matrix& aMaskTransform,
                          const IntRect& aBounds = IntRect(),
                          bool aCopyBackground = false) override;
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -670,16 +670,112 @@ DrawTargetSkia::MaskSurface(const Patter
     transform.setTranslate(PointToSkPoint(-aOffset));
     SkShader* matrixShader = paint.mPaint.getShader()->newWithLocalMatrix(transform);
     SkSafeUnref(paint.mPaint.setShader(matrixShader));
   }
 
   mCanvas->drawBitmap(bitmap, aOffset.x, aOffset.y, &paint.mPaint);
 }
 
+bool
+DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
+{
+  // Composite the 3D transform with the DT's transform.
+  Matrix4x4 fullMat = aMatrix * Matrix4x4::From2D(mTransform);
+  if (fullMat.IsSingular()) {
+    return false;
+  }
+  // Transform the surface bounds and clip to this DT.
+  IntRect xformBounds =
+    RoundedOut(
+      fullMat.TransformAndClipBounds(Rect(Point(0, 0), Size(aSurface->GetSize())),
+                                     Rect(Point(0, 0), Size(GetSize()))));
+  if (xformBounds.IsEmpty()) {
+    return true;
+  }
+  // Offset the matrix by the transformed origin.
+  fullMat.PostTranslate(-xformBounds.x, -xformBounds.y, 0);
+
+  // Read in the source data.
+  SkBitmap srcBitmap = GetBitmapForSurface(aSurface);
+
+  // Set up an intermediate destination surface only the size of the transformed bounds.
+  // Try to pass through the source's format unmodified in both the BGRA and ARGB cases.
+  RefPtr<DataSourceSurface> dstSurf =
+    Factory::CreateDataSourceSurface(xformBounds.Size(),
+                                     srcBitmap.alphaType() == kPremul_SkAlphaType ?
+                                       aSurface->GetFormat() : SurfaceFormat::A8R8G8B8_UINT32,
+                                     true);
+  if (!dstSurf) {
+    return false;
+  }
+  SkAutoTUnref<SkCanvas> dstCanvas(
+    SkCanvas::NewRasterDirect(
+      SkImageInfo::Make(xformBounds.width, xformBounds.height,
+                        srcBitmap.alphaType() == kPremul_SkAlphaType ?
+                          srcBitmap.colorType() : kBGRA_8888_SkColorType,
+                        kPremul_SkAlphaType),
+      dstSurf->GetData(), dstSurf->Stride()));
+  if (!dstCanvas) {
+    return false;
+  }
+
+  // Do the transform.
+  SkPaint paint;
+  paint.setAntiAlias(true);
+  paint.setFilterQuality(kLow_SkFilterQuality);
+  paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+
+  SkMatrix xform;
+  GfxMatrixToSkiaMatrix(fullMat, xform);
+  dstCanvas->setMatrix(xform);
+
+  dstCanvas->drawBitmap(srcBitmap, 0, 0, &paint);
+  dstCanvas->flush();
+
+  // Temporarily reset the DT's transform, since it has already been composed above.
+  Matrix origTransform = mTransform;
+  SetTransform(Matrix());
+
+  // Draw the transformed surface within the transformed bounds.
+  DrawSurface(dstSurf, Rect(xformBounds), Rect(Point(0, 0), Size(xformBounds.Size())));
+
+  SetTransform(origTransform);
+
+  return true;
+}
+
+bool
+DrawTargetSkia::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
+{
+  if (aMatrix.IsSingular()) {
+    return false;
+  }
+
+  MarkChanged();
+
+  SkBitmap bitmap = GetBitmapForSurface(aSurface);
+
+  mCanvas->save();
+
+  SkPaint paint;
+  paint.setAntiAlias(true);
+  paint.setFilterQuality(kLow_SkFilterQuality);
+
+  SkMatrix xform;
+  GfxMatrixToSkiaMatrix(aMatrix, xform);
+  mCanvas->concat(xform);
+
+  mCanvas->drawBitmap(bitmap, 0, 0, &paint);
+
+  mCanvas->restore();
+
+  return true;
+}
+
 already_AddRefed<SourceSurface>
 DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData,
                                             const IntSize &aSize,
                                             int32_t aStride,
                                             SurfaceFormat aFormat) const
 {
   RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia();
 
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -81,16 +81,18 @@ public:
                           const GlyphRenderingOptions *aRenderingOptions = nullptr) override;
   virtual void Mask(const Pattern &aSource,
                     const Pattern &aMask,
                     const DrawOptions &aOptions = DrawOptions()) override;
   virtual void MaskSurface(const Pattern &aSource,
                            SourceSurface *aMask,
                            Point aOffset,
                            const DrawOptions &aOptions = DrawOptions()) override;
+  virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
+                                        const Matrix4x4& aMatrix) override;
   virtual void PushClip(const Path *aPath) override;
   virtual void PushClipRect(const Rect& aRect) override;
   virtual void PopClip() override;
   virtual void PushLayer(bool aOpaque, Float aOpacity,
                          SourceSurface* aMask,
                          const Matrix& aMaskTransform,
                          const IntRect& aBounds = IntRect(),
                          bool aCopyBackground = false) override;
--- a/gfx/2d/HelpersSkia.h
+++ b/gfx/2d/HelpersSkia.h
@@ -101,16 +101,24 @@ GfxFormatToGrConfig(SurfaceFormat format
 static inline void
 GfxMatrixToSkiaMatrix(const Matrix& mat, SkMatrix& retval)
 {
     retval.setAll(SkFloatToScalar(mat._11), SkFloatToScalar(mat._21), SkFloatToScalar(mat._31),
                   SkFloatToScalar(mat._12), SkFloatToScalar(mat._22), SkFloatToScalar(mat._32),
                   0, 0, SK_Scalar1);
 }
 
+static inline void
+GfxMatrixToSkiaMatrix(const Matrix4x4& aMatrix, SkMatrix& aResult)
+{
+  aResult.setAll(SkFloatToScalar(aMatrix._11), SkFloatToScalar(aMatrix._21), SkFloatToScalar(aMatrix._41),
+                 SkFloatToScalar(aMatrix._12), SkFloatToScalar(aMatrix._22), SkFloatToScalar(aMatrix._42),
+                 SkFloatToScalar(aMatrix._14), SkFloatToScalar(aMatrix._24), SkFloatToScalar(aMatrix._44));
+}
+
 static inline SkPaint::Cap
 CapStyleToSkiaCap(CapStyle aCap)
 {
   switch (aCap)
   {
     case CapStyle::BUTT:
       return SkPaint::kButt_Cap;
     case CapStyle::ROUND:
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -1264,34 +1264,16 @@ public:
     static const float error = 1e-5f;
     NudgeToInteger(&_41, error);
     NudgeToInteger(&_42, error);
     NudgeToInteger(&_43, error);
     NudgeToInteger(&_44, error);
     return *this;
   }
 
-  // Nudge the 3D components to integer so that this matrix will become 2D if
-  // it's very close to already being 2D.
-  // This doesn't change the _41 and _42 components.
-  Matrix4x4Typed &NudgeTo2D()
-  {
-    NudgeToInteger(&_13);
-    NudgeToInteger(&_14);
-    NudgeToInteger(&_23);
-    NudgeToInteger(&_24);
-    NudgeToInteger(&_31);
-    NudgeToInteger(&_32);
-    NudgeToInteger(&_33);
-    NudgeToInteger(&_34);
-    NudgeToInteger(&_43);
-    NudgeToInteger(&_44);
-    return *this;
-  }
-
   Point4D TransposedVector(int aIndex) const
   {
       MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
       return Point4D(*((&_11)+aIndex), *((&_21)+aIndex), *((&_31)+aIndex), *((&_41)+aIndex));
   }
 
   void SetTransposedVector(int aIndex, Point4D &aVector)
   {
--- a/gfx/doc/Silk.md
+++ b/gfx/doc/Silk.md
@@ -49,28 +49,28 @@ There is only one **VsyncSource** object
 Each platform is expected to implement their own **VsyncSource** to manage vsync events.
 On Firefox OS, this is through the **HwcComposer2D**.
 On OS X, this is through **CVDisplayLinkRef**.
 On Windows, it should be through **DwmGetCompositionTimingInfo**.
 
 #Compositor
 When the **CompositorVsyncDispatcher** is notified of the vsync event, the **CompositorVsyncObserver** associated with the **CompositorVsyncDispatcher** begins execution.
 Since the **CompositorVsyncDispatcher** executes on the *Hardware Vsync Thread* and the **Compositor** composites on the *CompositorThread*, the **CompositorVsyncObserver** posts a task to the *CompositorThread*.
-The **CompositorParent** then composites.
+The **CompositorBridgeParent** then composites.
 The model where the **CompositorVsyncDispatcher** notifies components on the *Hardware Vsync Thread*, and the component schedules the task on the appropriate thread is used everywhere.
 
 The **CompositorVsyncObserver** listens to vsync events as needed and stops listening to vsync when composites are no longer scheduled or required.
-Every **CompositorParent** is associated and tied to one **CompositorVsyncObserver**, which is associated with the **CompositorVsyncDispatcher**.
-Each **CompositorParent** is associated with one widget and is created when a new platform window or **nsBaseWidget** is created.
-The **CompositorParent**, **CompositorVsyncDispatcher**, **CompositorVsyncObserver**, and **nsBaseWidget** all have the same lifetimes, which are created and destroyed together.
+Every **CompositorBridgeParent** is associated and tied to one **CompositorVsyncObserver**, which is associated with the **CompositorVsyncDispatcher**.
+Each **CompositorBridgeParent** is associated with one widget and is created when a new platform window or **nsBaseWidget** is created.
+The **CompositorBridgeParent**, **CompositorVsyncDispatcher**, **CompositorVsyncObserver**, and **nsBaseWidget** all have the same lifetimes, which are created and destroyed together.
 
 ###CompositorVsyncDispatcher
 The **CompositorVsyncDispatcher** executes on the *Hardware Vsync Thread*.
 It contains references to the **nsBaseWidget** it is associated with and has a lifetime equal to the **nsBaseWidget**.
-The **CompositorVsyncDispatcher** is responsible for notifying the **CompositorParent** that a vsync event has occured.
+The **CompositorVsyncDispatcher** is responsible for notifying the **CompositorBridgeParent** that a vsync event has occured.
 There can be multiple **CompositorVsyncDispatchers** per **Display**, one **CompositorVsyncDispatcher** per window.
 The only responsibility of the **CompositorVsyncDispatcher** is to notify components when a vsync event has occured, and to stop listening to vsync when no components require vsync events.
 We require one **CompositorVsyncDispatcher** per window so that we can handle multiple **Displays**.
 
 ###Multiple Displays
 The **VsyncSource** has an API to switch a **CompositorVsyncDispatcher** from one **Display** to another **Display**.
 For example, when one window either goes into full screen mode or moves from one connected monitor to another.
 When one window moves to another monitor, we expect a platform specific notification to occur.
@@ -107,39 +107,39 @@ As of this writing, we have not analyzed
 
 One slight quirk is that input events can start a composite, for example during a scroll and after the **Compositor** is no longer listening to vsync events.
 In these cases, we notify the **Compositor** to observe vsync so that it dispatches touch events.
 If touch events were not dispatched, and since the **Compositor** is not listening to vsync events, the touch events would never be dispatched.
 The **GeckoTouchDispatcher** handles this case by always forcing the **Compositor** to listen to vsync events while touch events are occurring.
 
 ###Widget, Compositor, CompositorVsyncDispatcher, GeckoTouchDispatcher Shutdown Procedure
 When the [nsBaseWidget shuts down](http://hg.mozilla.org/mozilla-central/file/0df249a0e4d3/widget/nsBaseWidget.cpp#l182) - It calls nsBaseWidget::DestroyCompositor on the *Gecko Main Thread*.
-During nsBaseWidget::DestroyCompositor, it first destroys the CompositorChild.
-CompositorChild sends a sync IPC call to CompositorParent::RecvStop, which calls [CompositorParent::Destroy](http://hg.mozilla.org/mozilla-central/file/ab0490972e1e/gfx/layers/ipc/CompositorParent.cpp#l509).
+During nsBaseWidget::DestroyCompositor, it first destroys the CompositorBridgeChild.
+CompositorBridgeChild sends a sync IPC call to CompositorBridgeParent::RecvStop, which calls [CompositorBridgeParent::Destroy](http://hg.mozilla.org/mozilla-central/file/ab0490972e1e/gfx/layers/ipc/CompositorBridgeParent.cpp#l509).
 During this time, the *main thread* is blocked on the parent process.
-CompositorParent::RecvStop runs on the *Compositor thread* and cleans up some resources, including setting the **CompositorVsyncObserver** to nullptr.
-CompositorParent::RecvStop also explicitly keeps the CompositorParent alive and posts another task to run CompositorParent::DeferredDestroy on the Compositor loop so that all ipdl code can finish executing.
+CompositorBridgeParent::RecvStop runs on the *Compositor thread* and cleans up some resources, including setting the **CompositorVsyncObserver** to nullptr.
+CompositorBridgeParent::RecvStop also explicitly keeps the CompositorBridgeParent alive and posts another task to run CompositorBridgeParent::DeferredDestroy on the Compositor loop so that all ipdl code can finish executing.
 The **CompositorVsyncObserver** also unobserves from vsync and cancels any pending composite tasks.
-Once CompositorParent::RecvStop finishes, the *main thread* in the parent process continues shutting down the nsBaseWidget.
+Once CompositorBridgeParent::RecvStop finishes, the *main thread* in the parent process continues shutting down the nsBaseWidget.
 
-At the same time, the *Compositor thread* is executing tasks until CompositorParent::DeferredDestroy runs, which flushes the compositor message loop.
-Now we have two tasks as both the nsBaseWidget releases a reference to the Compositor on the *main thread* during destruction and the CompositorParent::DeferredDestroy releases a reference to the CompositorParent on the *Compositor Thread*.
-Finally, the CompositorParent itself is destroyed on the *main thread* once both references are gone due to explicit [main thread destruction](http://hg.mozilla.org/mozilla-central/file/50b95032152c/gfx/layers/ipc/CompositorParent.h#l148).
+At the same time, the *Compositor thread* is executing tasks until CompositorBridgeParent::DeferredDestroy runs, which flushes the compositor message loop.
+Now we have two tasks as both the nsBaseWidget releases a reference to the Compositor on the *main thread* during destruction and the CompositorBridgeParent::DeferredDestroy releases a reference to the CompositorBridgeParent on the *Compositor Thread*.
+Finally, the CompositorBridgeParent itself is destroyed on the *main thread* once both references are gone due to explicit [main thread destruction](http://hg.mozilla.org/mozilla-central/file/50b95032152c/gfx/layers/ipc/CompositorBridgeParent.h#l148).
 
 With the **CompositorVsyncObserver**, any accesses to the widget after nsBaseWidget::DestroyCompositor executes are invalid.
 Any accesses to the compositor between the time the nsBaseWidget::DestroyCompositor runs and the CompositorVsyncObserver's destructor runs aren't safe yet a hardware vsync event could occur between these times.
-Since any tasks posted on the Compositor loop after CompositorParent::DeferredDestroy is posted are invalid, we make sure that no vsync tasks can be posted once CompositorParent::RecvStop executes and DeferredDestroy is posted on the Compositor thread.
-When the sync call to CompositorParent::RecvStop executes, we explicitly set the CompositorVsyncObserver to null to prevent vsync notifications from occurring.
-If vsync notifications were allowed to occur, since the **CompositorVsyncObserver**'s vsync notification executes on the *hardware vsync thread*, it would post a task to the Compositor loop and may execute after CompositorParent::DeferredDestroy.
-Thus, we explicitly shut down vsync events in the **CompositorVsyncDispatcher** and **CompositorVsyncObserver** during nsBaseWidget::Shutdown to prevent any vsync tasks from executing after CompositorParent::DeferredDestroy.
+Since any tasks posted on the Compositor loop after CompositorBridgeParent::DeferredDestroy is posted are invalid, we make sure that no vsync tasks can be posted once CompositorBridgeParent::RecvStop executes and DeferredDestroy is posted on the Compositor thread.
+When the sync call to CompositorBridgeParent::RecvStop executes, we explicitly set the CompositorVsyncObserver to null to prevent vsync notifications from occurring.
+If vsync notifications were allowed to occur, since the **CompositorVsyncObserver**'s vsync notification executes on the *hardware vsync thread*, it would post a task to the Compositor loop and may execute after CompositorBridgeParent::DeferredDestroy.
+Thus, we explicitly shut down vsync events in the **CompositorVsyncDispatcher** and **CompositorVsyncObserver** during nsBaseWidget::Shutdown to prevent any vsync tasks from executing after CompositorBridgeParent::DeferredDestroy.
 
 The **CompositorVsyncDispatcher** may be destroyed on either the *main thread* or *Compositor Thread*, since both the nsBaseWidget and **CompositorVsyncObserver** race to destroy on different threads.
 nsBaseWidget is destroyed on the *main thread* and releases a reference to the **CompositorVsyncDispatcher** during destruction.
-The **CompositorVsyncObserver** has a race to be destroyed either during CompositorParent shutdown or from the **GeckoTouchDispatcher** which is destroyed on the main thread with [ClearOnShutdown](http://hg.mozilla.org/mozilla-central/file/21567e9a6e40/xpcom/base/ClearOnShutdown.h#l15).
-Whichever object, the CompositorParent or the **GeckoTouchDispatcher** is destroyed last will hold the last reference to the **CompositorVsyncDispatcher**, which destroys the object.
+The **CompositorVsyncObserver** has a race to be destroyed either during CompositorBridgeParent shutdown or from the **GeckoTouchDispatcher** which is destroyed on the main thread with [ClearOnShutdown](http://hg.mozilla.org/mozilla-central/file/21567e9a6e40/xpcom/base/ClearOnShutdown.h#l15).
+Whichever object, the CompositorBridgeParent or the **GeckoTouchDispatcher** is destroyed last will hold the last reference to the **CompositorVsyncDispatcher**, which destroys the object.
 
 #Refresh Driver
 The Refresh Driver is ticked from a [single active timer](http://hg.mozilla.org/mozilla-central/file/ab0490972e1e/layout/base/nsRefreshDriver.cpp#l11).
 The assumption is that there are multiple **RefreshDrivers** connected to a single **RefreshTimer**.
 There are two **RefreshTimers**: an active and an inactive **RefreshTimer**.
 Each Tab has its own **RefreshDriver**, which connects to one of the global **RefreshTimers**.
 The **RefreshTimers** execute on the *Main Thread* and tick their connected **RefreshDrivers**.
 We do not want to break this model of multiple **RefreshDrivers** per a set of two global **RefreshTimers**.
@@ -207,17 +207,17 @@ Based on which display the window is on,
 Each **TabParent** should also send a notification to their child.
 Each **TabChild**, given the display ID, switches to the correct **RefreshTimer** associated with the display ID.
 When each display vsync occurs, it sends one IPC message to notify vsync.
 The vsync message contains a display ID, to tick the appropriate **RefreshTimer** on the content process.
 There is still only one **VsyncParent/VsyncChild** pair, just each vsync notification will include a display ID, which maps to the correct **RefreshTimer**.
 
 #Object Lifetime
 1. CompositorVsyncDispatcher - Lives as long as the nsBaseWidget associated with the VsyncDispatcher
-2. CompositorVsyncObserver - Lives and dies the same time as the CompositorParent.
+2. CompositorVsyncObserver - Lives and dies the same time as the CompositorBridgeParent.
 3. RefreshTimerVsyncDispatcher - As long as the associated display object, which is the lifetime of Firefox.
 4. VsyncSource - Lives as long as the gfxPlatform on the chrome process, which is the lifetime of Firefox.
 5. VsyncParent/VsyncChild - Lives as long as the content process
 6. RefreshTimer - Lives as long as the process
 
 #Threads
 All **VsyncObservers** are notified on the *Hardware Vsync Thread*. It is the responsibility of the **VsyncObservers** to post tasks to their respective correct thread. For example, the **CompositorVsyncObserver** will be notified on the *Hardware Vsync Thread*, and post a task to the *Compositor Thread* to do the actual composition.
 
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -1,16 +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/. */
 
 #include "mozilla/layers/Compositor.h"
 #include "base/message_loop.h"          // for MessageLoop
-#include "mozilla/layers/CompositorParent.h"  // for CompositorParent
+#include "mozilla/layers/CompositorBridgeParent.h"  // for CompositorBridgeParent
 #include "mozilla/layers/Effects.h"     // for Effect, EffectChain, etc
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "gfx2DGlue.h"
 #include "nsAppRunner.h"
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 #include "libdisplay/GonkDisplay.h"     // for GonkDisplay
 #include <ui/Fence.h>
@@ -20,18 +20,18 @@
 
 namespace mozilla {
 
 namespace layers {
 
 /* static */ void
 Compositor::AssertOnCompositorThread()
 {
-  MOZ_ASSERT(!CompositorParent::CompositorLoop() ||
-             CompositorParent::CompositorLoop() == MessageLoop::current(),
+  MOZ_ASSERT(!CompositorBridgeParent::CompositorLoop() ||
+             CompositorBridgeParent::CompositorLoop() == MessageLoop::current(),
              "Can only call this from the compositor thread!");
 }
 
 bool
 Compositor::ShouldDrawDiagnostics(DiagnosticFlags aFlags)
 {
   if ((aFlags & DiagnosticFlags::TILE) && !(mDiagnosticTypes & DiagnosticTypes::TILE_BORDERS)) {
     return false;
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -121,17 +121,17 @@ namespace layers {
 struct Effect;
 struct EffectChain;
 class Image;
 class ImageHostOverlay;
 class Layer;
 class TextureSource;
 class DataTextureSource;
 class CompositingRenderTarget;
-class CompositorParent;
+class CompositorBridgeParent;
 class LayerManagerComposite;
 
 enum SurfaceInitMode
 {
   INIT_MODE_NONE,
   INIT_MODE_CLEAR
 };
 
@@ -180,17 +180,17 @@ enum SurfaceInitMode
 class Compositor
 {
 protected:
   virtual ~Compositor() {}
 
 public:
   NS_INLINE_DECL_REFCOUNTING(Compositor)
 
-  explicit Compositor(CompositorParent* aParent = nullptr)
+  explicit Compositor(CompositorBridgeParent* aParent = nullptr)
     : mCompositorID(0)
     , mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC)
     , mParent(aParent)
     , mScreenRotation(ROTATION_0)
   {
   }
 
   virtual already_AddRefed<DataTextureSource> CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) = 0;
@@ -549,17 +549,17 @@ protected:
    * When nonnull, during rendering, some compositable indicated that it will
    * change its rendering at this time. In order not to miss it, we composite
    * on every vsync until this time occurs (this is the latest such time).
    */
   TimeStamp mCompositeUntilTime;
 
   uint32_t mCompositorID;
   DiagnosticTypes mDiagnosticTypes;
-  CompositorParent* mParent;
+  CompositorBridgeParent* mParent;
 
   /**
    * We keep track of the total number of pixels filled as we composite the
    * current frame. This value is an approximation and is not accurate,
    * especially in the presence of transforms.
    */
   size_t mPixelsPerFrame;
   size_t mPixelsFilled;
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -12,17 +12,17 @@
 #include "Effects.h"
 #include "mozilla/Endian.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TimeStamp.h"
 
 #include "TexturePoolOGL.h"
 #include "mozilla/layers/CompositorOGL.h"
-#include "mozilla/layers/CompositorParent.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/TextureHostOGL.h"
 
 #include "gfxContext.h"
 #include "gfxUtils.h"
 #include "gfxPrefs.h"
 #include "nsIWidget.h"
 
@@ -1894,17 +1894,17 @@ LayerScope::SendLayerDump(UniquePtr<Pack
         new DebugGLLayersData(Move(aPacket)));
 }
 
 /*static*/
 bool
 LayerScope::CheckSendable()
 {
     // Only compositor threads check LayerScope status