Merge inbound to m-c on a CLOSED TREE. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 04 Aug 2014 16:06:19 -0400
changeset 197734 7f81be7db52884f813fd2d6ff2ae4fd0d8aeb452
parent 197503 25bf2f1664e91cc2192bb38aa825c80a5a758bd0 (current diff)
parent 197733 8ca82f7e965c71120175c00e70b34293c00513cd (diff)
child 197735 ebb6c174ab001a0e910f93fd197de3bf40f869d9
child 197812 ff5f51ffab715fd72b4ba9206f2c5371fbf007a8
child 197865 fe004e9051abec0ddfee03a1dcf66dd42e9b93ab
push id27249
push userryanvm@gmail.com
push dateMon, 04 Aug 2014 20:14:35 +0000
treeherdermozilla-central@7f81be7db528 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone34.0a1
first release with
nightly linux32
7f81be7db528 / 34.0a1 / 20140805030300 / files
nightly linux64
7f81be7db528 / 34.0a1 / 20140805030300 / files
nightly mac
7f81be7db528 / 34.0a1 / 20140805030300 / files
nightly win32
7f81be7db528 / 34.0a1 / 20140805030300 / files
nightly win64
7f81be7db528 / 34.0a1 / 20140805030300 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c on a CLOSED TREE. a=merge
dom/base/nsDOMClassInfo.cpp
media/libspeex_resampler/src/resample_sse.h
media/libspeex_resampler/src/sse_detect.cpp
media/libspeex_resampler/src/sse_detect.h
media/libspeex_resampler/sse-detect-runtime.patch
testing/mochitest/runtests.py
uriloader/exthandler/tests/mailcap
xpfe/appshell/public/moz.build
xpfe/appshell/public/nsAppShellCID.h
xpfe/appshell/public/nsIAppShellService.idl
xpfe/appshell/public/nsIPopupWindowManager.idl
xpfe/appshell/public/nsIWindowMediator.idl
xpfe/appshell/public/nsIWindowMediatorListener.idl
xpfe/appshell/public/nsIXULBrowserWindow.idl
xpfe/appshell/public/nsIXULWindow.idl
xpfe/appshell/src/moz.build
xpfe/appshell/src/nsAppShellFactory.cpp
xpfe/appshell/src/nsAppShellService.cpp
xpfe/appshell/src/nsAppShellService.h
xpfe/appshell/src/nsAppShellWindowEnumerator.cpp
xpfe/appshell/src/nsAppShellWindowEnumerator.h
xpfe/appshell/src/nsChromeTreeOwner.cpp
xpfe/appshell/src/nsChromeTreeOwner.h
xpfe/appshell/src/nsContentTreeOwner.cpp
xpfe/appshell/src/nsContentTreeOwner.h
xpfe/appshell/src/nsWebShellWindow.cpp
xpfe/appshell/src/nsWebShellWindow.h
xpfe/appshell/src/nsWindowMediator.cpp
xpfe/appshell/src/nsWindowMediator.h
xpfe/appshell/src/nsXULWindow.cpp
xpfe/appshell/src/nsXULWindow.h
xpfe/appshell/src/test/chrome.ini
xpfe/appshell/src/test/test_hiddenPrivateWindow.xul
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1046585 moved files to a different directory and required a clobber.
+Bug 1046533 needs a clobber on Android.
--- a/b2g/installer/Makefile.in
+++ b/b2g/installer/Makefile.in
@@ -24,16 +24,20 @@ DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MO
 ifdef WIN32_REDIST_DIR
 ifdef MOZ_NO_DEBUG_RTL
 DEFINES += -DMOZ_PACKAGE_MSVC_DLLS=1
 DEFINES += -DMSVC_C_RUNTIME_DLL=$(MSVC_C_RUNTIME_DLL)
 DEFINES += -DMSVC_CXX_RUNTIME_DLL=$(MSVC_CXX_RUNTIME_DLL)
 endif
 endif
 
+ifdef MOZ_DEBUG
+DEFINES += -DMOZ_DEBUG=1
+endif
+
 ifdef ENABLE_MARIONETTE
 DEFINES += -DENABLE_MARIONETTE=1
 endif
 
 ifdef MOZ_PKG_MANIFEST_P
 MOZ_PKG_MANIFEST = package-manifest
 endif
 
--- a/build/autoconf/hooks.m4
+++ b/build/autoconf/hooks.m4
@@ -12,57 +12,52 @@ changequote([, ])dnl
 
 dnl Wrap AC_INIT_PREPARE to add the above trap.
 define([_MOZ_AC_INIT_PREPARE], defn([AC_INIT_PREPARE]))
 define([AC_INIT_PREPARE],
 [_MOZ_AC_INIT_PREPARE($1)
 MOZ_CONFIG_LOG_TRAP
 ])
 
-dnl Disable the trap when running sub-configures.
-define(GEN_MOZ_AC_OUTPUT_SUBDIRS, [
-define([_MOZ_AC_OUTPUT_SUBDIRS], [
-patsubst($@, [$srcdir/$ac_config_dir], [$srcdir/$moz_config_srcdir])
-])
-])
-GEN_MOZ_AC_OUTPUT_SUBDIRS(defn([AC_OUTPUT_SUBDIRS]))
-
 define([AC_OUTPUT_SUBDIRS],
-[trap '' EXIT
-for moz_config_dir in $1; do
+[for moz_config_dir in $1; do
+  _CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
   case "$moz_config_dir" in
   *:*)
-    moz_config_srcdir=$(echo $moz_config_dir | awk -F: '{print [$]1}')
-    moz_config_dir=$(echo $moz_config_dir | awk -F: '{print [$]2}')
+    objdir=$(echo $moz_config_dir | awk -F: '{print [$]2}')
     ;;
   *)
-    moz_config_srcdir=$moz_config_dir
+    objdir=$moz_config_dir
     ;;
   esac
-  _CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+
+  dumpenv="true | "
   case "$host" in
   *-mingw*)
     _CONFIG_SHELL=$(cd $(dirname $_CONFIG_SHELL); pwd -W)/$(basename $_CONFIG_SHELL)
     if test ! -e "$_CONFIG_SHELL" -a -e "${_CONFIG_SHELL}.exe"; then
         _CONFIG_SHELL="${_CONFIG_SHELL}.exe"
     fi
+    dnl Yes, this is horrible. But since msys doesn't preserve environment
+    dnl variables and command line arguments as they are when transitioning
+    dnl from msys (this script) to python (below), we have to resort to hacks,
+    dnl storing the environment and command line arguments from a msys process
+    dnl (perl), and reading it from python.
+    dumpenv="$PERL $srcdir/build/win32/dumpenv4python.pl $ac_configure_args | "
     ;;
   esac
 
-  if test -d "$moz_config_dir"; then
-    (cd "$moz_config_dir"; eval $PYTHON $_topsrcdir/build/subconfigure.py dump "$_CONFIG_SHELL" $ac_configure_args)
-  else
-    mkdir -p "$moz_config_dir"
+  eval $dumpenv $PYTHON $_topsrcdir/build/subconfigure.py --prepare "$srcdir" "$moz_config_dir" "$_CONFIG_SHELL" $ac_configure_args ifelse($2,,,--cache-file="$2")
+
+  dnl Execute subconfigure, unless --no-recursion was passed to configure.
+  if test "$no_recursion" != yes; then
+    trap '' EXIT
+    if ! $PYTHON $_topsrcdir/build/subconfigure.py "$objdir"; then
+        exit 1
+    fi
+    MOZ_CONFIG_LOG_TRAP
   fi
-  _save_cache_file="$cache_file"
-  ifelse($2,,cache_file="$moz_config_dir/config.cache",cache_file="$2")
-  cache_file="$(cd $(dirname "$cache_file"); pwd -W 2>/dev/null || pwd)/$(basename "$cache_file")"
-  _MOZ_AC_OUTPUT_SUBDIRS($moz_config_dir)
-  cache_file="$_save_cache_file"
-  (cd "$moz_config_dir"; $PYTHON $_topsrcdir/build/subconfigure.py adjust $ac_sub_configure)
 done
-
-MOZ_CONFIG_LOG_TRAP
 ])
 
 dnl Print error messages in config.log as well as stderr
 define([AC_MSG_ERROR],
 [{ echo "configure: error: $1" 1>&2; echo "configure: error: $1" 1>&5; exit 1; }])
--- a/build/clang-plugin/configure
+++ b/build/clang-plugin/configure
@@ -1,14 +1,14 @@
 #!/bin/sh
 
 PLATFORM=`uname`
 
 # Default srcdir to this directory
-srcdir=
+srcdir=$(dirname $0)
 
 for option; do
   case "$option" in
   -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
   *) optarg= ;;
   esac
 
   case "$option" in
--- a/build/subconfigure.py
+++ b/build/subconfigure.py
@@ -1,43 +1,58 @@
 # 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/.
 
 # This script is used to capture the content of config.status-generated
 # files and subsequently restore their timestamp if they haven't changed.
 
 import argparse
+import errno
 import os
 import re
 import subprocess
 import sys
 import pickle
 
+import mozpack.path as mozpath
+
 class File(object):
     def __init__(self, path):
         self._path = path
         self._content = open(path, 'rb').read()
         stat = os.stat(path)
         self._times = (stat.st_atime, stat.st_mtime)
 
     @property
     def path(self):
         return self._path
 
     @property
     def mtime(self):
         return self._times[1]
 
+    @property
+    def modified(self):
+        '''Returns whether the file was modified since the instance was
+        created. Result is memoized.'''
+        if hasattr(self, '_modified'):
+            return self._modified
+
+        modified = True
+        if os.path.exists(self._path):
+            if open(self._path, 'rb').read() == self._content:
+                modified = False
+        self._modified = modified
+        return modified
+
     def update_time(self):
         '''If the file hasn't changed since the instance was created,
            restore its old modification time.'''
-        if not os.path.exists(self._path):
-            return
-        if open(self._path, 'rb').read() == self._content:
+        if not self.modified:
             os.utime(self._path, self._times)
 
 
 # As defined in the various sub-configures in the tree
 PRECIOUS_VARS = set([
     'build_alias',
     'host_alias',
     'target_alias',
@@ -56,113 +71,284 @@ PRECIOUS_VARS = set([
 
 
 # Autoconf, in some of the sub-configures used in the tree, likes to error
 # out when "precious" variables change in value. The solution it gives to
 # straighten things is to either run make distclean or remove config.cache.
 # There's no reason not to do the latter automatically instead of failing,
 # doing the cleanup (which, on buildbots means a full clobber), and
 # restarting from scratch.
-def maybe_clear_cache(args):
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--target', type=str)
-    parser.add_argument('--host', type=str)
-    parser.add_argument('--build', type=str)
-    args, others = parser.parse_known_args(args)
-    env = dict(os.environ)
+def maybe_clear_cache(data):
+    env = dict(data['env'])
     for kind in ('target', 'host', 'build'):
-        arg = getattr(args, kind)
+        arg = data[kind]
         if arg is not None:
             env['%s_alias' % kind] = arg
     # configure can take variables assignments in its arguments, and that
     # overrides whatever is in the environment.
-    for arg in others:
+    for arg in data['args']:
         if arg[:1] != '-' and '=' in arg:
             key, value = arg.split('=', 1)
             env[key] = value
 
     comment = re.compile(r'^\s+#')
     cache = {}
-    with open('config.cache') as f:
+    with open(data['cache-file']) as f:
         for line in f:
             if not comment.match(line) and '=' in line:
                 key, value = line.rstrip(os.linesep).split('=', 1)
                 # If the value is quoted, unquote it
                 if value[:1] == "'":
                     value = value[1:-1].replace("'\\''", "'")
                 cache[key] = value
     for precious in PRECIOUS_VARS:
         # If there is no entry at all for that precious variable, then
         # its value is not precious for that particular configure.
         if 'ac_cv_env_%s_set' % precious not in cache:
             continue
         is_set = cache.get('ac_cv_env_%s_set' % precious) == 'set'
         value = cache.get('ac_cv_env_%s_value' % precious) if is_set else None
         if value != env.get(precious):
-            print 'Removing config.cache because of %s value change from:' \
-                % precious
+            print 'Removing %s because of %s value change from:' \
+                % (data['cache-file'], precious)
             print '  %s' % (value if value is not None else 'undefined')
             print 'to:'
             print '  %s' % env.get(precious, 'undefined')
-            os.remove('config.cache')
-            return
+            os.remove(data['cache-file'])
+            return True
+    return False
 
 
-def dump(dump_file, shell, args):
-    if os.path.exists('config.cache'):
-        maybe_clear_cache(args)
-    if not os.path.exists('config.status'):
-        if os.path.exists(dump_file):
-            os.remove(dump_file)
-        return
+def split_template(s):
+    """Given a "file:template" string, returns "file", "template". If the string
+    is of the form "file" (without a template), returns "file", "file.in"."""
+    if ':' in s:
+        return s.split(':', 1)
+    return s, '%s.in' % s
+
 
-    config_files = [File('config.status')]
+def get_config_files(data):
+    config_status = mozpath.join(data['objdir'], 'config.status')
+    if not os.path.exists(config_status):
+        return [], []
+
+    configure = mozpath.join(data['srcdir'], 'configure')
+    config_files = []
+    command_files = []
 
     # Scan the config.status output for information about configuration files
     # it generates.
     config_status_output = subprocess.check_output(
-        [shell, '-c', './config.status --help'],
+        [data['shell'], '-c', '%s --help' % config_status],
         stderr=subprocess.STDOUT).splitlines()
     state = None
     for line in config_status_output:
         if line.startswith('Configuration') and line.endswith(':'):
-            state = 'config'
-        elif not line.startswith(' '):
+            if line.endswith('commands:'):
+                state = 'commands'
+            else:
+                state = 'config'
+        elif not line.strip():
             state = None
-        elif state == 'config':
-            for f in (couple.split(':')[0] for couple in line.split()):
-                if os.path.isfile(f):
-                    config_files.append(File(f))
+        elif state:
+            for f, t in (split_template(couple) for couple in line.split()):
+                f = mozpath.join(data['objdir'], f)
+                t = mozpath.join(data['srcdir'], t)
+                if state == 'commands':
+                    command_files.append(f)
+                else:
+                    config_files.append((f, t))
 
-    with open(dump_file, 'wb') as f:
-        pickle.dump(config_files, f)
+    return config_files, command_files
 
 
-def adjust(dump_file, configure):
-    if not os.path.exists(dump_file):
-        return
+def prepare(data_file, srcdir, objdir, shell, args):
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--target', type=str)
+    parser.add_argument('--host', type=str)
+    parser.add_argument('--build', type=str)
+    parser.add_argument('--cache-file', type=str)
+    # The --srcdir argument is simply ignored. It's a useless autoconf feature
+    # that we don't support well anyways. This makes it stripped from `others`
+    # and allows to skip setting it when calling the subconfigure (configure
+    # will take it from the configure path anyways).
+    parser.add_argument('--srcdir', type=str)
+
+    data_file = os.path.join(objdir, data_file)
+    previous_args = None
+    if os.path.exists(data_file):
+        with open(data_file, 'rb') as f:
+            data = pickle.load(f)
+            previous_args = data['args']
 
-    config_files = []
+    # Msys likes to break environment variables and command line arguments,
+    # so read those from stdin, as they are passed from the configure script
+    # when necessary (on windows).
+    # However, for some reason, $PATH is not handled like other environment
+    # variables, and msys remangles it even when giving it is already a msys
+    # $PATH. Fortunately, the mangling/demangling is just find for $PATH, so
+    # we can just take the value from the environment. Msys will convert it
+    # back properly when calling subconfigure.
+    input = sys.stdin.read()
+    if input:
+        data = {a: b for [a, b] in eval(input)}
+        environ = {a: b for a, b in data['env']}
+        environ['PATH'] = os.environ['PATH']
+        args = data['args']
+    else:
+        environ = os.environ
+
+    args, others = parser.parse_known_args(args)
+
+    data = {
+        'target': args.target,
+        'host': args.host,
+        'build': args.build,
+        'args': others,
+        'shell': shell,
+        'srcdir': srcdir,
+        'env': environ,
+    }
+
+    if args.cache_file:
+        data['cache-file'] = mozpath.normpath(mozpath.join(os.getcwd(),
+            args.cache_file))
+    else:
+        data['cache-file'] = mozpath.join(objdir, 'config.cache')
+
+    if previous_args is not None:
+        data['previous-args'] = previous_args
 
     try:
-        with open(dump_file, 'rb') as f:
-            config_files = pickle.load(f)
-    except Exception:
-        pass
+        os.makedirs(objdir)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            raise
 
-    for f in config_files:
-        # Still touch config.status if configure is newer than its original
-        # mtime.
-        if configure and os.path.basename(f.path) == 'config.status' and \
-                os.path.getmtime(configure) > f.mtime:
-            continue
-        f.update_time()
-
-    os.remove(dump_file)
+    with open(data_file, 'wb') as f:
+        pickle.dump(data, f)
 
 
-CONFIG_DUMP = 'config_files.pkl'
+def run(data_file, objdir):
+    ret = 0
+
+    with open(os.path.join(objdir, data_file), 'rb') as f:
+        data = pickle.load(f)
+
+    data['objdir'] = objdir
+
+    cache_file = data['cache-file']
+    cleared_cache = True
+    if os.path.exists(cache_file):
+        cleared_cache = maybe_clear_cache(data)
+
+    config_files, command_files = get_config_files(data)
+    contents = []
+    for f, t in config_files:
+        contents.append(File(f))
+
+    # AC_CONFIG_COMMANDS actually only registers tags, not file names
+    # but most commands are tagged with the file name they create.
+    # However, a few don't, or are tagged with a directory name (and their
+    # command is just to create that directory)
+    for f in command_files:
+        if os.path.isfile(f):
+            contents.append(File(f))
+
+    # Only run configure if one of the following is true:
+    # - config.status doesn't exist
+    # - config.status is older than configure
+    # - the configure arguments changed
+    # - the environment changed in a way that requires a cache clear.
+    configure = mozpath.join(data['srcdir'], 'configure')
+    config_status_path = mozpath.join(objdir, 'config.status')
+    skip_configure = True
+    if not os.path.exists(config_status_path):
+        skip_configure = False
+        config_status = None
+    else:
+        config_status = File(config_status_path)
+        if config_status.mtime < os.path.getmtime(configure) or \
+                data.get('previous-args', data['args']) != data['args'] or \
+                cleared_cache:
+            skip_configure = False
+
+    if not skip_configure:
+        command = [data['shell'], configure]
+        for kind in ('target', 'build', 'host'):
+            if data.get(kind) is not None:
+                command += ['--%s=%s' % (kind, data[kind])]
+        command += data['args']
+        command += ['--cache-file=%s' % cache_file]
+
+        # Pass --no-create to configure so that it doesn't run config.status.
+        # We're going to run it ourselves.
+        command += ['--no-create']
+
+        print 'configuring in %s' % os.path.relpath(objdir, os.getcwd())
+        print 'running %s' % ' '.join(command[:-1])
+        sys.stdout.flush()
+        ret = subprocess.call(command, cwd=objdir, env=data['env'])
+
+        if ret:
+            return ret
+
+        # Leave config.status with a new timestamp if configure is newer than
+        # its original mtime.
+        if config_status and os.path.getmtime(configure) <= config_status.mtime:
+            config_status.update_time()
+
+    # Only run config.status if one of the following is true:
+    # - config.status changed or did not exist
+    # - one of the templates for config files is newer than the corresponding
+    #   config file.
+    skip_config_status = True
+    if not config_status or config_status.modified:
+        # If config.status doesn't exist after configure (because it's not
+        # an autoconf configure), skip it.
+        if os.path.exists(config_status_path):
+            skip_config_status = False
+    else:
+        # config.status changed or was created, so we need to update the
+        # list of config and command files.
+        config_files, command_files = get_config_files(data)
+        for f, t in config_files:
+            if not os.path.exists(t) or \
+                    os.path.getmtime(f) < os.path.getmtime(t):
+                skip_config_status = False
+
+    if not skip_config_status:
+        if skip_configure:
+            print 'running config.status in %s' % os.path.relpath(objdir,
+                os.getcwd())
+            sys.stdout.flush()
+        ret = subprocess.call([data['shell'], '-c', './config.status'],
+            cwd=objdir, env=data['env'])
+
+        for f in contents:
+            f.update_time()
+
+    return ret
+
+
+CONFIGURE_DATA = 'configure.pkl'
+
+def main(args):
+    if args[0] != '--prepare':
+        if len(args) != 1:
+            raise Exception('Usage: %s relativeobjdir' % __file__)
+        return run(CONFIGURE_DATA, args[0])
+
+    topsrcdir = os.path.abspath(args[1])
+    subdir = args[2]
+    # subdir can be of the form srcdir:objdir
+    if ':' in subdir:
+        srcdir, subdir = subdir.split(':', 1)
+    else:
+        srcdir = subdir
+    srcdir = os.path.join(topsrcdir, srcdir)
+    objdir = os.path.abspath(subdir)
+
+    return prepare(CONFIGURE_DATA, srcdir, objdir, args[3], args[4:])
+
 
 if __name__ == '__main__':
-    if sys.argv[1] == 'dump':
-        dump(CONFIG_DUMP, sys.argv[2], sys.argv[3:])
-    elif sys.argv[1] == 'adjust':
-        adjust(CONFIG_DUMP, sys.argv[2] if len(sys.argv) > 2 else None)
+    sys.exit(main(sys.argv[1:]))
new file mode 100644
--- /dev/null
+++ b/build/win32/dumpenv4python.pl
@@ -0,0 +1,19 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# See build/autoconf/hooks.m4
+
+use Data::Dumper;
+
+$Data::Dumper::Terse = 1;
+$Data::Dumper::Indent = 0;
+
+# We can't use perl hashes because Mozilla-Build's perl is 5.6, and perl
+# 5.6's Data::Dumper doesn't have Pair to change ' => ' into ' : '.
+@data = (
+  ['env', [map { [$_, $ENV{$_}] } keys %ENV]],
+  ['args', \@ARGV],
+);
+
+print Dumper \@data;
--- a/config/config.mk
+++ b/config/config.mk
@@ -824,23 +824,16 @@ EXPAND_MOZLIBNAME = $(foreach lib,$(1),$
 PLY_INCLUDE = -I$(topsrcdir)/other-licenses/ply
 
 export CL_INCLUDES_PREFIX
 # Make sure that the build system can handle non-ASCII characters
 # in environment variables to prevent it from breking silently on
 # non-English systems.
 export NONASCII
 
-ifdef MOZ_GTK2_CFLAGS
-MOZ_GTK2_CFLAGS := -I$(topsrcdir)/widget/gtk/compat $(MOZ_GTK2_CFLAGS)
-endif
-ifdef MOZ_GTK3_CFLAGS
-MOZ_GTK3_CFLAGS := -I$(topsrcdir)/widget/gtk/compat-gtk3 $(MOZ_GTK3_CFLAGS)
-endif
-
 DEFINES += -DNO_NSPR_10_SUPPORT
 
 ifdef IS_GYP_DIR
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/ipc/chromium/src \
   -I$(topsrcdir)/ipc/glue \
   -I$(DEPTH)/ipc/ipdl/_ipdlheaders \
   $(NULL)
--- a/configure.in
+++ b/configure.in
@@ -4266,23 +4266,25 @@ fi
 
 if test "$MOZ_INSTRUMENT_EVENT_LOOP"; then
    AC_DEFINE(MOZ_INSTRUMENT_EVENT_LOOP)
 fi
 
 if test "$COMPILE_ENVIRONMENT"; then
   if test "$MOZ_ENABLE_GTK3"; then
     PKG_CHECK_MODULES(MOZ_GTK3, gtk+-3.0 >= $GTK3_VERSION gtk+-unix-print-3.0 glib-2.0 gobject-2.0 $GDK_PACKAGES)
+    MOZ_GTK3_CFLAGS="-I${_topsrcdir}/widget/gtk/compat-gtk3 $MOZ_GTK3_CFLAGS"
   fi
   if test "$MOZ_ENABLE_GTK"; then
     if test "$MOZ_X11"; then
       GDK_PACKAGES=gdk-x11-2.0
     fi
 
     PKG_CHECK_MODULES(MOZ_GTK2, gtk+-2.0 >= $GTK2_VERSION gtk+-unix-print-2.0 glib-2.0 gobject-2.0 $GDK_PACKAGES)
+    MOZ_GTK2_CFLAGS="-I${_topsrcdir}/widget/gtk/compat $MOZ_GTK2_CFLAGS"
   fi
 
 fi # COMPILE_ENVIRONMENT
 
 AC_SUBST(MOZ_FS_LAYOUT)
 
 dnl ========================================================
 dnl Use ARM userspace kernel helpers; tell NSPR to enable
@@ -4983,19 +4985,21 @@ AC_SUBST(MOZ_WEBRTC)
 AC_SUBST(MOZ_WEBRTC_LEAKING_TESTS)
 AC_SUBST(MOZ_WEBRTC_SIGNALING)
 AC_SUBST(MOZ_PEERCONNECTION)
 AC_SUBST(MOZ_WEBRTC_ASSERT_ALWAYS)
 AC_SUBST(MOZ_SCTP)
 AC_SUBST(MOZ_SRTP)
 AC_SUBST(MOZ_WEBRTC_X11_LIBS)
 
-dnl Use integers over floats for audio on B2G and Android, because audio
-dnl backends for those platforms don't support floats.
-if test "$OS_TARGET" = "Android"; then
+dnl Use integers over floats for audio on B2G and Android
+dnl (regarless of the CPU architecture, because audio
+dnl backends for those platforms don't support floats. We also
+dnl use integers on ARM with other OS, because it's more efficient.
+if test "$OS_TARGET" = "Android" -o "$CPU_ARCH" = "arm"; then
     MOZ_SAMPLE_TYPE_S16=1
     AC_DEFINE(MOZ_SAMPLE_TYPE_S16)
     AC_SUBST(MOZ_SAMPLE_TYPE_S16)
 else
     MOZ_SAMPLE_TYPE_FLOAT32=1
     AC_DEFINE(MOZ_SAMPLE_TYPE_FLOAT32)
     AC_SUBST(MOZ_SAMPLE_TYPE_FLOAT32)
 fi
@@ -5390,16 +5394,18 @@ if test -n "$MOZ_WEBRTC" -a -z "$MOZ_OPU
 fi
 
 if test -n "$MOZ_VORBIS"; then
     AC_DEFINE(MOZ_VORBIS)
 fi
 
 if test -n "$MOZ_TREMOR"; then
     AC_DEFINE(MOZ_TREMOR)
+    # Tremor doesn't have an encoder.
+    MOZ_WEBM_ENCODER=
 fi
 
 if test -n "$MOZ_OPUS"; then
     AC_DEFINE(MOZ_OPUS)
 fi
 
 if test -n "$MOZ_WEBM_ENCODER"; then
     AC_DEFINE(MOZ_WEBM_ENCODER)
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -640,26 +640,31 @@ public:
                          const nsAString& aLocalName,
                          ErrorResult& aError);
   bool HasAttribute(const nsAString& aName) const
   {
     return InternalGetExistingAttrNameFromQName(aName) != nullptr;
   }
   bool HasAttributeNS(const nsAString& aNamespaceURI,
                       const nsAString& aLocalName) const;
+  bool Matches(const nsAString& aSelector,
+               ErrorResult& aError);
   already_AddRefed<nsIHTMLCollection>
     GetElementsByTagName(const nsAString& aQualifiedName);
   already_AddRefed<nsIHTMLCollection>
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                            const nsAString& aLocalName,
                            ErrorResult& aError);
   already_AddRefed<nsIHTMLCollection>
     GetElementsByClassName(const nsAString& aClassNames);
   bool MozMatchesSelector(const nsAString& aSelector,
-                          ErrorResult& aError);
+                          ErrorResult& aError)
+  {
+    return Matches(aSelector, aError);
+  }
   void SetPointerCapture(int32_t aPointerId, ErrorResult& aError)
   {
     bool activeState = false;
     if (!nsIPresShell::GetPointerInfo(aPointerId, activeState)) {
       aError.Throw(NS_ERROR_DOM_INVALID_POINTER_ERR);
       return;
     }
     if (!activeState) {
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -146,17 +146,17 @@ enum EventNameType {
   EventNameType_All = 0xFFFF
 };
 
 struct EventNameMapping
 {
   nsIAtom* mAtom;
   uint32_t mId;
   int32_t  mType;
-  uint32_t mStructType;
+  mozilla::EventClassID mEventClassID;
 };
 
 struct nsShortcutCandidate {
   nsShortcutCandidate(uint32_t aCharCode, bool aIgnoreShift) :
     mCharCode(aCharCode), mIgnoreShift(aIgnoreShift)
   {
   }
   uint32_t mCharCode;
@@ -1028,35 +1028,35 @@ public:
    * event name with the 'on' prefix. Returns NS_USER_DEFINED_EVENT if the
    * event doesn't match a known event name.
    *
    * @param aName the event name to look up
    */
   static uint32_t GetEventId(nsIAtom* aName);
 
   /**
-   * Return the category for the event with the given name. The name is the
-   * event name *without* the 'on' prefix. Returns NS_EVENT if the event
-   * is not known to be in any particular category.
+   * Return the EventClassID for the event with the given name. The name is the
+   * event name *without* the 'on' prefix. Returns eBasicEventClass if the event
+   * is not known to be of any particular event class.
    *
    * @param aName the event name to look up
    */
-  static uint32_t GetEventCategory(const nsAString& aName);
+  static mozilla::EventClassID GetEventClassID(const nsAString& aName);
 
   /**
    * Return the event id and atom for the event with the given name.
    * The name is the event name *without* the 'on' prefix.
    * Returns NS_USER_DEFINED_EVENT on the aEventID if the
    * event doesn't match a known event name in the category.
    *
    * @param aName the event name to look up
-   * @param aEventStruct only return event id in aEventStruct category
+   * @param aEventClassID only return event id for aEventClassID
    */
   static nsIAtom* GetEventIdAndAtom(const nsAString& aName,
-                                    uint32_t aEventStruct,
+                                    mozilla::EventClassID aEventClassID,
                                     uint32_t* aEventID);
 
   /**
    * Used only during traversal of the XPCOM graph by the cycle
    * collector: push a pointer to the listener manager onto the
    * children deque, if it exists. Do nothing if there is no listener
    * manager.
    *
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -1723,17 +1723,17 @@ Element::DispatchClickEvent(nsPresContex
   uint32_t clickCount = 1;
   float pressure = 0;
   uint16_t inputSource = 0;
   WidgetMouseEvent* sourceMouseEvent = aSourceEvent->AsMouseEvent();
   if (sourceMouseEvent) {
     clickCount = sourceMouseEvent->clickCount;
     pressure = sourceMouseEvent->pressure;
     inputSource = sourceMouseEvent->inputSource;
-  } else if (aSourceEvent->eventStructType == NS_KEY_EVENT) {
+  } else if (aSourceEvent->mClass == eKeyboardEventClass) {
     inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
   }
   event.pressure = pressure;
   event.clickCount = clickCount;
   event.inputSource = inputSource;
   event.modifiers = aSourceEvent->modifiers;
   if (aExtraEventFlags) {
     // Be careful not to overwrite existing flags!
@@ -2731,18 +2731,17 @@ Element::SetTokenList(nsIAtom* aAtom, ns
   nsAutoString string;
   aValue->GetAsAString(string);
   ErrorResult rv;
   itemType->SetValue(string, rv);
   return rv.ErrorCode();
 }
 
 bool
-Element::MozMatchesSelector(const nsAString& aSelector,
-                            ErrorResult& aError)
+Element::Matches(const nsAString& aSelector, ErrorResult& aError)
 {
   nsCSSSelectorList* selectorList = ParseSelectorList(aSelector, aError);
   if (!selectorList) {
     // Either we failed (and aError already has the exception), or this
     // is a pseudo-element-only selector that matches nothing.
     return false;
   }
 
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -809,17 +809,17 @@ nsIContent::PreHandleEvent(EventChainPre
   // Event may need to be retargeted if this is the root of a native
   // anonymous content subtree or event is dispatched somewhere inside XBL.
   if (isAnonForEvents) {
 #ifdef DEBUG
     // If a DOM event is explicitly dispatched using node.dispatchEvent(), then
     // all the events are allowed even in the native anonymous content..
     nsCOMPtr<nsIContent> t = do_QueryInterface(aVisitor.mEvent->originalTarget);
     NS_ASSERTION(!t || !t->ChromeOnlyAccess() ||
-                 aVisitor.mEvent->eventStructType != NS_MUTATION_EVENT ||
+                 aVisitor.mEvent->mClass != eMutationEventClass ||
                  aVisitor.mDOMEvent,
                  "Mutation event dispatched in native anonymous content!?!");
 #endif
     aVisitor.mEventTargetAtParent = parent;
   } else if (parent && aVisitor.mOriginalTargetIsInAnon) {
     nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->target));
     if (content && content->GetBindingParent() == parent) {
       aVisitor.mEventTargetAtParent = parent;
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -620,18 +620,18 @@ nsContentUtils::InitializeModifierString
 }
 
 bool
 nsContentUtils::InitializeEventTable() {
   NS_ASSERTION(!sAtomEventTable, "EventTable already initialized!");
   NS_ASSERTION(!sStringEventTable, "EventTable already initialized!");
 
   static const EventNameMapping eventArray[] = {
-#define EVENT(name_,  _id, _type, _struct)          \
-    { nsGkAtoms::on##name_, _id, _type, _struct },
+#define EVENT(name_,  _id, _type, _class)          \
+    { nsGkAtoms::on##name_, _id, _type, _class },
 #define WINDOW_ONLY_EVENT EVENT
 #define NON_IDL_EVENT EVENT
 #include "mozilla/EventNameList.h"
 #undef WINDOW_ONLY_EVENT
 #undef EVENT
     { nullptr }
   };
 
@@ -653,19 +653,19 @@ nsContentUtils::InitializeEventTable() {
 
 void
 nsContentUtils::InitializeTouchEventTable()
 {
   static bool sEventTableInitialized = false;
   if (!sEventTableInitialized && sAtomEventTable && sStringEventTable) {
     sEventTableInitialized = true;
     static const EventNameMapping touchEventArray[] = {
-#define EVENT(name_,  _id, _type, _struct)
-#define TOUCH_EVENT(name_,  _id, _type, _struct)      \
-      { nsGkAtoms::on##name_, _id, _type, _struct },
+#define EVENT(name_,  _id, _type, _class)
+#define TOUCH_EVENT(name_,  _id, _type, _class)      \
+      { nsGkAtoms::on##name_, _id, _type, _class },
 #include "mozilla/EventNameList.h"
 #undef TOUCH_EVENT
 #undef EVENT
       { nullptr }
     };
     // Subtract one from the length because of the trailing null
     for (uint32_t i = 0; i < ArrayLength(touchEventArray) - 1; ++i) {
       sAtomEventTable->Put(touchEventArray[i].mAtom, touchEventArray[i]);
@@ -3597,35 +3597,35 @@ nsContentUtils::GetEventId(nsIAtom* aNam
       return mapping.mId;
     }
   }
 
   return NS_USER_DEFINED_EVENT;
 }
 
 // static
-uint32_t
-nsContentUtils::GetEventCategory(const nsAString& aName)
+mozilla::EventClassID
+nsContentUtils::GetEventClassID(const nsAString& aName)
 {
   EventNameMapping mapping;
   if (sStringEventTable->Get(aName, &mapping))
-    return mapping.mStructType;
-
-  return NS_EVENT;
+    return mapping.mEventClassID;
+
+  return eBasicEventClass;
 }
 
 nsIAtom*
 nsContentUtils::GetEventIdAndAtom(const nsAString& aName,
-                                  uint32_t aEventStruct,
+                                  mozilla::EventClassID aEventClassID,
                                   uint32_t* aEventID)
 {
   EventNameMapping mapping;
   if (sStringEventTable->Get(aName, &mapping)) {
-    *aEventID =
-      mapping.mStructType == aEventStruct ? mapping.mId : NS_USER_DEFINED_EVENT;
+    *aEventID = mapping.mEventClassID == aEventClassID ? mapping.mId :
+                                                         NS_USER_DEFINED_EVENT;
     return mapping.mAtom;
   }
 
   // If we have cached lots of user defined event names, clear some of them.
   if (sUserDefinedEvents->Count() > 127) {
     while (sUserDefinedEvents->Count() > 64) {
       nsIAtom* first = sUserDefinedEvents->ObjectAt(0);
       sStringEventTable->Remove(Substring(nsDependentAtomString(first), 2));
@@ -3634,17 +3634,17 @@ nsContentUtils::GetEventIdAndAtom(const 
   }
 
   *aEventID = NS_USER_DEFINED_EVENT;
   nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aName);
   sUserDefinedEvents->AppendObject(atom);
   mapping.mAtom = atom;
   mapping.mId = NS_USER_DEFINED_EVENT;
   mapping.mType = EventNameType_None;
-  mapping.mStructType = NS_EVENT_NULL;
+  mapping.mEventClassID = eBasicEventClass;
   sStringEventTable->Put(aName, mapping);
   return mapping.mAtom;
 }
 
 static
 nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget,
                            const nsAString& aEventName,
                            bool aCanBubble, bool aCancelable,
@@ -4889,17 +4889,17 @@ nsContentUtils::GetAccelKeyCandidates(ns
   aDOMKeyEvent->GetType(eventType);
   // Don't process if aDOMKeyEvent is not a keypress event.
   if (!eventType.EqualsLiteral("keypress"))
     return;
 
   WidgetKeyboardEvent* nativeKeyEvent =
     aDOMKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
   if (nativeKeyEvent) {
-    NS_ASSERTION(nativeKeyEvent->eventStructType == NS_KEY_EVENT,
+    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...
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -428,16 +428,17 @@ nsXMLHttpRequest::ResetResponse()
   mResponseBody.Truncate();
   mResponseText.Truncate();
   mResponseBlob = nullptr;
   mDOMFile = nullptr;
   mBlobSet = nullptr;
   mResultArrayBuffer = nullptr;
   mArrayBufferBuilder.reset();
   mResultJSON = JSVAL_VOID;
+  mDataAvailable = 0;
   mLoadTransferred = 0;
   mResponseBodyDecodedPos = 0;
 }
 
 void
 nsXMLHttpRequest::SetRequestObserver(nsIRequestObserver* aObserver)
 {
   mRequestObserver = aObserver;
@@ -776,21 +777,24 @@ nsXMLHttpRequest::CreateResponseParsedJS
   mResultJSON = value;
   return NS_OK;
 }
 
 void
 nsXMLHttpRequest::CreatePartialBlob()
 {
   if (mDOMFile) {
+    // Use progress info to determine whether load is complete, but use
+    // mDataAvailable to ensure a slice is created based on the uncompressed
+    // data count.
     if (mLoadTotal == mLoadTransferred) {
       mResponseBlob = mDOMFile;
     } else {
       mResponseBlob =
-        mDOMFile->CreateSlice(0, mLoadTransferred, EmptyString());
+        mDOMFile->CreateSlice(0, mDataAvailable, EmptyString());
     }
     return;
   }
 
   // mBlobSet can be null if the request has been canceled
   if (!mBlobSet) {
     return;
   }
@@ -1904,22 +1908,22 @@ nsXMLHttpRequest::OnDataAvailable(nsIReq
 
   uint32_t totalRead;
   nsresult rv = inStr->ReadSegments(nsXMLHttpRequest::StreamReaderFunc,
                                     (void*)this, count, &totalRead);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (cancelable) {
     // We don't have to read from the local file for the blob response
-    mDOMFile->GetSize(&mLoadTransferred);
+    mDOMFile->GetSize(&mDataAvailable);
     ChangeState(XML_HTTP_REQUEST_LOADING);
     return request->Cancel(NS_OK);
   }
 
-  mLoadTransferred += totalRead;
+  mDataAvailable += totalRead;
 
   ChangeState(XML_HTTP_REQUEST_LOADING);
   
   MaybeDispatchProgressEvents(false);
 
   return NS_OK;
 }
 
@@ -3594,17 +3598,17 @@ nsXMLHttpRequest::OnProgress(nsIRequest 
     }
     mUploadLengthComputable = lengthComputable;
     mProgressSinceLastProgressEvent = true;
 
     MaybeDispatchProgressEvents(false);
   } else {
     mLoadLengthComputable = lengthComputable;
     mLoadTotal = lengthComputable ? aProgressMax : 0;
-    
+    mLoadTransferred = aProgress;
     // Don't dispatch progress events here. OnDataAvailable will take care
     // of that.
   }
 
   if (mProgressEventSink) {
     mProgressEventSink->OnProgress(aRequest, aContext, aProgress,
                                    aProgressMax);
   }
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -719,16 +719,26 @@ protected:
   bool mErrorLoad;
   bool mWaitingForOnStopRequest;
   bool mProgressTimerIsActive;
   bool mIsHtml;
   bool mWarnAboutMultipartHtml;
   bool mWarnAboutSyncHtml;
   bool mLoadLengthComputable;
   uint64_t mLoadTotal; // 0 if not known.
+  // Amount of script-exposed (i.e. after undoing gzip compresion) data
+  // received.
+  uint64_t mDataAvailable;
+  // Number of HTTP message body bytes received so far. This quantity is
+  // in the same units as Content-Length and mLoadTotal, and hence counts
+  // compressed bytes when the channel has gzip Content-Encoding. If the
+  // channel does not have Content-Encoding, this will be the same as
+  // mDataReceived except between the OnProgress that changes mLoadTransferred
+  // and the corresponding OnDataAvailable (which changes mDataReceived).
+  // Ordering of OnProgress and OnDataAvailable is undefined.
   uint64_t mLoadTransferred;
   nsCOMPtr<nsITimer> mProgressNotifier;
   void HandleProgressTimerCallback();
 
   bool mIsSystem;
   bool mIsAnon;
 
   /**
--- a/content/base/test/chrome/test_bug800386.xul
+++ b/content/base/test/chrome/test_bug800386.xul
@@ -21,27 +21,29 @@ https://bugzilla.mozilla.org/show_bug.cg
   Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
   SimpleTest.waitForExplicitFinish();
 
   var triedForwarding = false;
   var forwardFailed = false;
 
   var xhr = new XMLHttpRequest;
+  var xhr2 = new XMLHttpRequest;
+
   var eventSink = xhr.getInterface(Components.interfaces.nsIProgressEventSink);
   isnot(eventSink, null, "Should get event sink directly!");
 
   // Now jump through some hoops to get us a getInterface call from C++
 
   var requestor = {
     getInterface: function(aIID) {
       if (aIID.equals(Components.interfaces.nsIProgressEventSink)) {
         triedForwarding = true;
         try {
-          return xhr.getInterface(aIID);
+          return xhr2.getInterface(aIID);
         } catch (e) {
           forwardFailed = true;
         }
       }
       throw Components.results.NS_ERROR_NO_INTERFACE;
     },
 
     QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports,
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -215,16 +215,17 @@ support-files =
   invalid_accesscontrol.resource
   invalid_accesscontrol.resource^headers^
   mutationobserver_dialog.html
   progressserver.sjs
   responseIdentical.sjs
   script-1_bug597345.sjs
   script-2_bug597345.js
   script_bug602838.sjs
+  send_gzip_content.sjs
   somedatas.resource
   somedatas.resource^headers^
   variable_style_sheet.sjs
   viewport_helpers.js
   w3element_traversal.svg
   wholeTexty-helper.xml
 
 [test_CrossSiteXHR.html]
@@ -602,16 +603,17 @@ skip-if = buildapp == 'mulet' || buildap
 [test_mutationobservers.html]
 skip-if = buildapp == 'b2g' || e10s # b2g(bug 901385, showmodaldialog) b2g-debug(bug 901385, showmodaldialog) b2g-desktop(bug 901385, showmodaldialog)
 [test_nodelist_holes.html]
 [test_object.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(needs plugin support) b2g-debug(needs plugin support) b2g-desktop(needs plugin support)
 [test_plugin_freezing.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #CLICK_TO_PLAY
 [test_processing_instruction_update_stylesheet.xhtml]
+[test_progress_events_for_gzip_data.html]
 [test_range_bounds.html]
 skip-if = toolkit == 'android' || e10s
 [test_reentrant_flush.html]
 skip-if = toolkit == 'android' || e10s #RANDOM
 [test_sync_xhr_timer.xhtml]
 skip-if = toolkit == 'android' || e10s #RANDOM
 [test_text_wholeText.html]
 [test_textnode_normalize_in_selection.html]
@@ -646,8 +648,9 @@ disabled = Disabled for now. Mochitest i
 support-files = bug444546.sjs
 [test_bug503473.html]
 disabled = Disabled due to making the harness time out
 support-files = file_bug503473-frame.sjs
 [test_bug1011748.html]
 skip-if = buildapp == 'b2g' || e10s
 support-files = file_bug1011748_redirect.sjs file_bug1011748_OK.sjs
 [test_bug1025933.html]
+[test_element.matches.html]
new file mode 100644
--- /dev/null
+++ b/content/base/test/send_gzip_content.sjs
@@ -0,0 +1,48 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+function gzipCompressString(string, obs) {
+
+  let scs = Cc["@mozilla.org/streamConverters;1"]
+           .getService(Ci.nsIStreamConverterService);
+  let listener = Cc["@mozilla.org/network/stream-loader;1"]
+                .createInstance(Ci.nsIStreamLoader);
+  listener.init(obs);
+  let converter = scs.asyncConvertData("uncompressed", "gzip",
+                                        listener, null);
+  let stringStream = Cc["@mozilla.org/io/string-input-stream;1"]
+                    .createInstance(Ci.nsIStringInputStream);
+  stringStream.data = string;
+  converter.onStartRequest(null, null);
+  converter.onDataAvailable(null, null, stringStream, 0, string.length);
+  converter.onStopRequest(null, null, null);
+}
+
+function produceData() {
+  var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+";
+  var result = '';
+  for (var i = 0; i < 100000; ++i) {
+    result += chars;
+  }
+  return result;
+}
+
+function handleRequest(request, response)
+{
+  response.processAsync();
+
+  // Generate data
+  var strings_to_send = produceData();
+  response.setHeader("Content-Type", "text/plain", false);
+  response.setHeader("Content-Encoding", "gzip", false);
+
+  let observer = {
+    onStreamComplete: function(loader, context, status, length, result) {
+      buffer = String.fromCharCode.apply(this, result);
+      response.setHeader("Content-Length", ""+buffer.length, false);
+      response.write(buffer);
+      response.finish();
+    }
+  };
+  gzipCompressString(strings_to_send, observer);
+}
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_element.matches.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=886308
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 886308</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 886308 **/
+  ok(document.head.matches("head"), "head should match 'head'");
+  ok(document.querySelector("link").matches("html *"), "link is a descendant of 'html'");
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=886308">Mozilla Bug 886308</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_progress_events_for_gzip_data.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test progess events in case of gzipped data.</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="onLoadData()">
+<script  class="testbody" type="text/javascript">"use strict";
+SimpleTest.waitForExplicitFinish();
+
+var url = "send_gzip_content.sjs";
+var loaded = 0;
+var total = 0;
+
+function onProgress(e) {
+  if(e.lengthComputable) {
+    loaded = e.loaded;
+    total = e.total;
+    if (loaded > total) {
+      ok(false, "We have loaded more bytes (" + loaded +
+                ") than the total amount of bytes (" + total +
+                ") available!!!");
+    }
+  }
+}
+
+function onLoadData() {
+  var xhr = new XMLHttpRequest();
+  xhr.addEventListener('progress', onProgress, false);
+  xhr.open('GET', url, true);
+  xhr.onreadystatechange = function() {
+    if (xhr.readyState == 4) {
+      is(loaded, total, "loaded should be equal to total");
+      isnot(loaded, 0, "loaded should be bigger than 0");
+      SimpleTest.finish();
+    }
+  }
+  xhr.send(null);
+}
+
+</script>
+</body>
+</html>
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -288,17 +288,17 @@ HTMLCanvasElement::CopyInnerTo(Element* 
       rv = err.ErrorCode();
     }
   }
   return rv;
 }
 
 nsresult HTMLCanvasElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
 {
-  if (aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT) {
+  if (aVisitor.mEvent->mClass == eMouseEventClass) {
     WidgetMouseEventBase* evt = (WidgetMouseEventBase*)aVisitor.mEvent;
     if (mCurrentContext) {
       nsIFrame *frame = GetPrimaryFrame();
       if (!frame)
         return NS_OK;
       nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(evt, frame);
       nsRect paddingRect = frame->GetContentRectRelativeToSelf();
       Point hitpoint;
--- a/content/html/content/src/HTMLFormElement.cpp
+++ b/content/html/content/src/HTMLFormElement.cpp
@@ -59,31 +59,17 @@
 
 #include "nsIDOMHTMLButtonElement.h"
 #include "nsSandboxFlags.h"
 
 // images
 #include "mozilla/dom/HTMLImageElement.h"
 
 // construction, destruction
-nsGenericHTMLElement*
-NS_NewHTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
-                      mozilla::dom::FromParser aFromParser)
-{
-  mozilla::dom::HTMLFormElement* it = new mozilla::dom::HTMLFormElement(aNodeInfo);
-
-  nsresult rv = it->Init();
-
-  if (NS_FAILED(rv)) {
-    delete it;
-    return nullptr;
-  }
-
-  return it;
-}
+NS_IMPL_NS_NEW_HTML_ELEMENT(Form)
 
 namespace mozilla {
 namespace dom {
 
 static const uint8_t NS_FORM_AUTOCOMPLETE_ON  = 1;
 static const uint8_t NS_FORM_AUTOCOMPLETE_OFF = 0;
 
 static const nsAttrValue::EnumTable kFormAutocompleteTable[] = {
@@ -94,16 +80,17 @@ static const nsAttrValue::EnumTable kFor
 // Default autocomplete value is 'on'.
 static const nsAttrValue::EnumTable* kFormDefaultAutocomplete = &kFormAutocompleteTable[0];
 
 bool HTMLFormElement::gFirstFormSubmitted = false;
 bool HTMLFormElement::gPasswordManagerInitialized = false;
 
 HTMLFormElement::HTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo),
+    mControls(new HTMLFormControlsCollection(MOZ_THIS_IN_INITIALIZER_LIST())),
     mSelectedRadioButtons(4),
     mRequiredRadioButtonCounts(4),
     mValueMissingRadioGroups(4),
     mGeneratingSubmit(false),
     mGeneratingReset(false),
     mIsSubmitting(false),
     mDeferSubmission(false),
     mNotifiedObservers(false),
@@ -126,24 +113,16 @@ HTMLFormElement::~HTMLFormElement()
 {
   if (mControls) {
     mControls->DropFormReference();
   }
 
   Clear();
 }
 
-nsresult
-HTMLFormElement::Init()
-{
-  mControls = new HTMLFormControlsCollection(this);
-  return NS_OK;
-}
-
-
 // nsISupports
 
 static PLDHashOperator
 ElementTraverser(const nsAString& key, HTMLInputElement* element,
                  void* userArg)
 {
   nsCycleCollectionTraversalCallback *cb =
     static_cast<nsCycleCollectionTraversalCallback*>(userArg);
@@ -186,17 +165,17 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION
                                nsIForm,
                                nsIWebProgressListener,
                                nsIRadioGroupContainer)
 NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
 
 
 // nsIDOMHTMLFormElement
 
-NS_IMPL_ELEMENT_CLONE_WITH_INIT(HTMLFormElement)
+NS_IMPL_ELEMENT_CLONE(HTMLFormElement)
 
 nsIHTMLCollection*
 HTMLFormElement::Elements()
 {
   return mControls;
 }
 
 NS_IMETHODIMP
--- a/content/html/content/src/HTMLFormElement.h
+++ b/content/html/content/src/HTMLFormElement.h
@@ -38,19 +38,16 @@ class HTMLFormElement MOZ_FINAL : public
                                   public nsIWebProgressListener,
                                   public nsIForm,
                                   public nsIRadioGroupContainer
 {
   friend class HTMLFormControlsCollection;
 
 public:
   HTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
-  virtual ~HTMLFormElement();
-
-  nsresult Init();
 
   enum {
     FORM_CONTROL_LIST_HASHTABLE_SIZE = 16
   };
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
@@ -625,21 +622,18 @@ protected:
    */
   bool mEverTriedInvalidSubmit;
 
 protected:
   /** Detection of first form to notify observers */
   static bool gFirstFormSubmitted;
   /** Detection of first password input to initialize the password manager */
   static bool gPasswordManagerInitialized;
+
+private:
+  ~HTMLFormElement();
 };
 
 } // namespace dom
 
-template<>
-struct HasDangerousPublicDestructor<dom::HTMLFormElement>
-{
-  static const bool value = true;
-};
-
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLFormElement_h
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -3246,17 +3246,17 @@ HTMLInputElement::NeedToInitializeEditor
                     EventChainPreVisitor& aVisitor) const
 {
   // We only need to initialize the editor for single line input controls because they
   // are lazily initialized.  We don't need to initialize the control for
   // certain types of events, because we know that those events are safe to be
   // handled without the editor being initialized.  These events include:
   // mousein/move/out, overflow/underflow, and DOM mutation events.
   if (!IsSingleLineTextControl(false) ||
-      aVisitor.mEvent->eventStructType == NS_MUTATION_EVENT) {
+      aVisitor.mEvent->mClass == eMutationEventClass) {
     return false;
   }
 
   switch (aVisitor.mEvent->message) {
   case NS_MOUSE_MOVE:
   case NS_MOUSE_ENTER:
   case NS_MOUSE_EXIT:
   case NS_MOUSE_ENTER_SYNTH:
@@ -4264,19 +4264,19 @@ HTMLInputElement::PostHandleEvent(EventC
 }
 
 void
 HTMLInputElement::PostHandleEventForRangeThumb(EventChainPostVisitor& aVisitor)
 {
   MOZ_ASSERT(mType == NS_FORM_INPUT_RANGE);
 
   if (nsEventStatus_eConsumeNoDefault == aVisitor.mEventStatus ||
-      !(aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT ||
-        aVisitor.mEvent->eventStructType == NS_TOUCH_EVENT ||
-        aVisitor.mEvent->eventStructType == NS_KEY_EVENT)) {
+      !(aVisitor.mEvent->mClass == eMouseEventClass ||
+        aVisitor.mEvent->mClass == eTouchEventClass ||
+        aVisitor.mEvent->mClass == eKeyboardEventClass)) {
     return;
   }
 
   nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
   if (!rangeFrame && mIsDraggingRange) {
     CancelRangeThumbDrag();
     return;
   }
--- a/content/html/content/src/HTMLTableElement.cpp
+++ b/content/html/content/src/HTMLTableElement.cpp
@@ -617,39 +617,16 @@ HTMLTableElement::DeleteRow(int32_t aInd
   if (!row) {
     aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
   row->RemoveFromParent();
 }
 
-static const nsAttrValue::EnumTable kFrameTable[] = {
-  { "void",   NS_STYLE_TABLE_FRAME_NONE },
-  { "above",  NS_STYLE_TABLE_FRAME_ABOVE },
-  { "below",  NS_STYLE_TABLE_FRAME_BELOW },
-  { "hsides", NS_STYLE_TABLE_FRAME_HSIDES },
-  { "lhs",    NS_STYLE_TABLE_FRAME_LEFT },
-  { "rhs",    NS_STYLE_TABLE_FRAME_RIGHT },
-  { "vsides", NS_STYLE_TABLE_FRAME_VSIDES },
-  { "box",    NS_STYLE_TABLE_FRAME_BOX },
-  { "border", NS_STYLE_TABLE_FRAME_BORDER },
-  { 0 }
-};
-
-static const nsAttrValue::EnumTable kRulesTable[] = {
-  { "none",   NS_STYLE_TABLE_RULES_NONE },
-  { "groups", NS_STYLE_TABLE_RULES_GROUPS },
-  { "rows",   NS_STYLE_TABLE_RULES_ROWS },
-  { "cols",   NS_STYLE_TABLE_RULES_COLS },
-  { "all",    NS_STYLE_TABLE_RULES_ALL },
-  { 0 }
-};
-
-
 bool
 HTMLTableElement::ParseAttribute(int32_t aNamespaceID,
                                  nsIAtom* aAttribute,
                                  const nsAString& aValue,
                                  nsAttrValue& aResult)
 {
   /* ignore summary, just a string */
   if (aNamespaceID == kNameSpaceID_None) {
@@ -675,22 +652,16 @@ HTMLTableElement::ParseAttribute(int32_t
     
     if (aAttribute == nsGkAtoms::align) {
       return ParseTableHAlignValue(aValue, aResult);
     }
     if (aAttribute == nsGkAtoms::bgcolor ||
         aAttribute == nsGkAtoms::bordercolor) {
       return aResult.ParseColor(aValue);
     }
-    if (aAttribute == nsGkAtoms::frame) {
-      return aResult.ParseEnumValue(aValue, kFrameTable, false);
-    }
-    if (aAttribute == nsGkAtoms::rules) {
-      return aResult.ParseEnumValue(aValue, kRulesTable, false);
-    }
     if (aAttribute == nsGkAtoms::hspace ||
         aAttribute == nsGkAtoms::vspace) {
       return aResult.ParseIntWithBounds(aValue, 0);
     }
   }
 
   return nsGenericHTMLElement::ParseBackgroundAttribute(aNamespaceID,
                                                         aAttribute, aValue,
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -564,25 +564,25 @@ MediaStreamGraphImpl::UpdateStreamOrder(
         stream->AsSourceStream()->NeedsMixing()) {
       shouldMix = true;
     }
   }
 
   if (!mMixer && shouldMix) {
     mMixer = new AudioMixer(AudioMixerCallback);
     for (uint32_t i = 0; i < mStreams.Length(); ++i) {
-      for (uint32_t i = 0; i < mStreams[i]->mAudioOutputStreams.Length(); ++i) {
-        mStreams[i]->mAudioOutputStreams[i].mStream->SetMicrophoneActive(true);
+      for (uint32_t j = 0; j < mStreams[i]->mAudioOutputStreams.Length(); ++j) {
+        mStreams[i]->mAudioOutputStreams[j].mStream->SetMicrophoneActive(true);
       }
     }
   } else if (mMixer && !shouldMix) {
     mMixer = nullptr;
     for (uint32_t i = 0; i < mStreams.Length(); ++i) {
-      for (uint32_t i = 0; i < mStreams[i]->mAudioOutputStreams.Length(); ++i) {
-        mStreams[i]->mAudioOutputStreams[i].mStream->SetMicrophoneActive(false);
+      for (uint32_t j = 0; j < mStreams[i]->mAudioOutputStreams.Length(); ++j) {
+        mStreams[i]->mAudioOutputStreams[j].mStream->SetMicrophoneActive(false);
       }
     }
   }
 
   // The algorithm for finding cycles is based on Tim Leslie's iterative
   // implementation [1][2] of Pearce's variant [3] of Tarjan's strongly
   // connected components (SCC) algorithm.  There are variations (a) to
   // distinguish whether streams in SCCs of size 1 are in a cycle and (b) to
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -550,16 +550,17 @@ public:
   {
     return true;
   }
 
   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
   void SetAudioChannelType(dom::AudioChannel aType) { mAudioChannelType = aType; }
+  dom::AudioChannel AudioChannelType() const { return mAudioChannelType; }
 
 protected:
   virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime, GraphTime aBlockedTime)
   {
     mBufferStartTime += aBlockedTime;
     mGraphUpdateIndices.InsertTimeAtStart(aBlockedTime);
     mGraphUpdateIndices.AdvanceCurrentTime(aCurrentTime);
     mExplicitBlockerCount.AdvanceCurrentTime(aCurrentTime);
--- a/content/media/fmp4/MP4Reader.cpp
+++ b/content/media/fmp4/MP4Reader.cpp
@@ -137,16 +137,21 @@ MP4Reader::Shutdown()
     mVideo.mDecoder = nullptr;
   }
   if (mVideo.mTaskQueue) {
     mVideo.mTaskQueue->Shutdown();
     mVideo.mTaskQueue = nullptr;
   }
   // Dispose of the queued sample before shutting down the demuxer
   mQueuedVideoSample = nullptr;
+
+  if (mPlatform) {
+    mPlatform->Shutdown();
+    mPlatform = nullptr;
+  }
 }
 
 void
 MP4Reader::InitLayersBackendType()
 {
   if (!IsVideoContentType(mDecoder->GetResource()->GetContentType())) {
     // Not playing video, we don't care about the layers backend type.
     return;
--- a/content/media/fmp4/MP4Reader.h
+++ b/content/media/fmp4/MP4Reader.h
@@ -55,23 +55,22 @@ public:
 
   virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
                                int64_t aStartTime) MOZ_OVERRIDE;
 
   virtual bool IsWaitingMediaResources() MOZ_OVERRIDE;
 
   virtual nsresult ResetDecode() MOZ_OVERRIDE;
 
+  virtual void Shutdown() MOZ_OVERRIDE;
+
 private:
 
   void ExtractCryptoInitData(nsTArray<uint8_t>& aInitData);
 
-  // Destroys all decoder resources.
-  void Shutdown();
-
   // Initializes mLayersBackendType if possible.
   void InitLayersBackendType();
 
   // Blocks until the demuxer produces an sample of specified type.
   // Returns nullptr on error on EOS. Caller must delete sample.
   mp4_demuxer::MP4Sample* PopSample(mp4_demuxer::TrackType aTrack);
 
   bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed);
--- a/content/media/fmp4/PlatformDecoderModule.cpp
+++ b/content/media/fmp4/PlatformDecoderModule.cpp
@@ -104,16 +104,19 @@ PlatformDecoderModule::CreateCDMWrapper(
                               cdmDecodesVideo,
                               CreateTaskQueue());
 }
 
 /* static */
 PlatformDecoderModule*
 PlatformDecoderModule::Create()
 {
+  // Note: This runs on the decode thread.
+  MOZ_ASSERT(!NS_IsMainThread());
+
   if (sUseBlankDecoder) {
     return CreateBlankDecoderModule();
   }
 #ifdef XP_WIN
   nsAutoPtr<WMFDecoderModule> m(new WMFDecoderModule());
   if (NS_SUCCEEDED(m->Startup())) {
     return m.forget();
   }
--- a/content/media/fmp4/PlatformDecoderModule.h
+++ b/content/media/fmp4/PlatformDecoderModule.h
@@ -58,63 +58,64 @@ public:
   // needed by Create().
   static void Init();
 
   // Factory method that creates the appropriate PlatformDecoderModule for
   // the platform we're running on. Caller is responsible for deleting this
   // instance. It's expected that there will be multiple
   // PlatformDecoderModules alive at the same time. There is one
   // PlatformDecoderModule created per MP4Reader.
-  // This is called on the decode thread.
+  // This is called on the decode task queue.
   static PlatformDecoderModule* Create();
 
   // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or
   // decrypt-and-decode EME encrypted content. If the CDM only decrypts and
   // does not decode, we create a PDM and use that to create MediaDataDecoders
   // that we use on on aTaskQueue to decode the decrypted stream.
+  // This is called on the decode task queue.
   static PlatformDecoderModule* CreateCDMWrapper(CDMProxy* aProxy,
                                                  bool aHasAudio,
                                                  bool aHasVideo,
                                                  MediaTaskQueue* aTaskQueue);
 
-  // Called to shutdown the decoder module and cleanup state. This should
-  // block until shutdown is complete. This is called after Shutdown() has
-  // been called on all MediaDataDecoders created from this
-  // PlatformDecoderModule.
-  // Called on the main thread only.
+  // Called to shutdown the decoder module and cleanup state. The PDM
+  // is deleted immediately after Shutdown() is called. Shutdown() is
+  // called after Shutdown() has been called on all MediaDataDecoders
+  // created from this PlatformDecoderModule.
+  // This is called on the decode task queue.
   virtual nsresult Shutdown() = 0;
 
   // Creates an H.264 decoder. The layers backend is passed in so that
   // decoders can determine whether hardware accelerated decoding can be used.
   // Asynchronous decoding of video should be done in runnables dispatched
   // to aVideoTaskQueue. If the task queue isn't needed, the decoder should
   // not hold a reference to it.
   // Output and errors should be returned to the reader via aCallback.
   // On Windows the task queue's threads in have MSCOM initialized with
   // COINIT_MULTITHREADED.
   // Returns nullptr if the decoder can't be created.
   // It is safe to store a reference to aConfig.
-  // Called on decode thread.
+  // This is called on the decode task queue.
   virtual already_AddRefed<MediaDataDecoder>
   CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                     layers::LayersBackend aLayersBackend,
                     layers::ImageContainer* aImageContainer,
                     MediaTaskQueue* aVideoTaskQueue,
                     MediaDataDecoderCallback* aCallback) = 0;
 
   // Creates an AAC decoder with the specified properties.
   // Asynchronous decoding of audio should be done in runnables dispatched to
   // aAudioTaskQueue. If the task queue isn't needed, the decoder should
   // not hold a reference to it.
   // Output and errors should be returned to the reader via aCallback.
   // Returns nullptr if the decoder can't be created.
   // On Windows the task queue's threads in have MSCOM initialized with
   // COINIT_MULTITHREADED.
   // It is safe to store a reference to aConfig.
-  // Called on decode thread.
+  // This is called on the decode task queue.
   virtual already_AddRefed<MediaDataDecoder>
   CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
                    MediaTaskQueue* aAudioTaskQueue,
                    MediaDataDecoderCallback* aCallback) = 0;
 
   virtual ~PlatformDecoderModule() {}
 
 protected:
--- a/content/media/fmp4/apple/AppleDecoderModule.cpp
+++ b/content/media/fmp4/apple/AppleDecoderModule.cpp
@@ -51,23 +51,31 @@ AppleDecoderModule::Startup()
   // Check whether ::Init() above succeeded to know if
   // we're functional.
   if (!sIsEnabled) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
+class UnlinkTask : public nsRunnable {
+public:
+  NS_IMETHOD Run() MOZ_OVERRIDE {
+    MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
+    AppleVTLinker::Unlink();
+    AppleCMLinker::Unlink();
+    return NS_OK;
+  }
+};
+
 nsresult
 AppleDecoderModule::Shutdown()
 {
-  MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
-  AppleVTLinker::Unlink();
-  AppleCMLinker::Unlink();
-
+  nsRefPtr<nsIRunnable> task(new UnlinkTask());
+  NS_DispatchToMainThread(task);
   return NS_OK;
 }
 
 already_AddRefed<MediaDataDecoder>
 AppleDecoderModule::CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                                       layers::LayersBackend aLayersBackend,
                                       layers::ImageContainer* aImageContainer,
                                       MediaTaskQueue* aVideoTaskQueue,
--- a/content/media/fmp4/eme/EMEDecoderModule.cpp
+++ b/content/media/fmp4/eme/EMEDecoderModule.cpp
@@ -179,17 +179,16 @@ EMEDecoderModule::EMEDecoderModule(CDMPr
 
 EMEDecoderModule::~EMEDecoderModule()
 {
 }
 
 nsresult
 EMEDecoderModule::Shutdown()
 {
-  MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   if (mPDM) {
     return mPDM->Shutdown();
   }
   mTaskQueue->Shutdown();
   return NS_OK;
 }
 
 already_AddRefed<MediaDataDecoder>
--- a/content/media/fmp4/wmf/WMFDecoderModule.h
+++ b/content/media/fmp4/wmf/WMFDecoderModule.h
@@ -12,37 +12,34 @@
 namespace mozilla {
 
 class WMFDecoderModule : public PlatformDecoderModule {
 public:
   WMFDecoderModule();
   virtual ~WMFDecoderModule();
 
   // Initializes the module, loads required dynamic libraries, etc.
-  // Main thread only.
   nsresult Startup();
 
-  // Called when the decoders have shutdown. Main thread only.
-  // Does this really need to be main thread only????
+  // Called when the decoders have shutdown.
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
-  // Decode thread.
   virtual already_AddRefed<MediaDataDecoder>
   CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                     layers::LayersBackend aLayersBackend,
                     layers::ImageContainer* aImageContainer,
                     MediaTaskQueue* aVideoTaskQueue,
                     MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
 
-  // Decode thread.
   virtual already_AddRefed<MediaDataDecoder>
   CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
                    MediaTaskQueue* aAudioTaskQueue,
                    MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
 
+  // Called on main thread.
   static void Init();
 private:
   static bool sIsWMFEnabled;
   static bool sDXVAEnabled;
 };
 
 } // namespace mozilla
 
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/GMPAudioDecoderChild.cpp
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GMPAudioDecoderChild.h"
+#include "GMPChild.h"
+#include "GMPAudioHost.h"
+#include "mozilla/unused.h"
+#include <stdio.h>
+
+namespace mozilla {
+namespace gmp {
+
+GMPAudioDecoderChild::GMPAudioDecoderChild(GMPChild* aPlugin)
+  : mPlugin(aPlugin)
+  , mAudioDecoder(nullptr)
+{
+  MOZ_ASSERT(mPlugin);
+}
+
+GMPAudioDecoderChild::~GMPAudioDecoderChild()
+{
+}
+
+void
+GMPAudioDecoderChild::Init(GMPAudioDecoder* aDecoder)
+{
+  MOZ_ASSERT(aDecoder, "Cannot initialize Audio decoder child without a Audio decoder!");
+  mAudioDecoder = aDecoder;
+}
+
+GMPAudioHostImpl&
+GMPAudioDecoderChild::Host()
+{
+  return mAudioHost;
+}
+
+void
+GMPAudioDecoderChild::Decoded(GMPAudioSamples* aDecodedSamples)
+{
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  if (!aDecodedSamples) {
+    MOZ_CRASH("Not given decoded audio samples!");
+  }
+
+  GMPAudioDecodedSampleData samples;
+  samples.mData().AppendElements((int16_t*)aDecodedSamples->Buffer(),
+                                 aDecodedSamples->Size() / sizeof(int16_t));
+  samples.mTimeStamp() = aDecodedSamples->TimeStamp();
+
+  unused << SendDecoded(samples);
+
+  aDecodedSamples->Destroy();
+}
+
+void
+GMPAudioDecoderChild::InputDataExhausted()
+{
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  unused << SendInputDataExhausted();
+}
+
+void
+GMPAudioDecoderChild::DrainComplete()
+{
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  unused << SendDrainComplete();
+}
+
+void
+GMPAudioDecoderChild::ResetComplete()
+{
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  unused << SendResetComplete();
+}
+
+void
+GMPAudioDecoderChild::Error(GMPErr aError)
+{
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  unused << SendError(aError);
+}
+
+bool
+GMPAudioDecoderChild::RecvInitDecode(const GMPAudioCodecData& a)
+{
+  MOZ_ASSERT(mAudioDecoder);
+  if (!mAudioDecoder) {
+    return false;
+  }
+
+  GMPAudioCodec codec;
+  codec.mCodecType = a.mCodecType();
+  codec.mChannelCount = a.mChannelCount();
+  codec.mBitsPerChannel = a.mBitsPerChannel();
+  codec.mSamplesPerSecond = a.mSamplesPerSecond();
+  codec.mExtraData = a.mExtraData().Elements();
+  codec.mExtraDataLen = a.mExtraData().Length();
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mAudioDecoder->InitDecode(codec, this);
+
+  return true;
+}
+
+bool
+GMPAudioDecoderChild::RecvDecode(const GMPAudioEncodedSampleData& aEncodedSamples)
+{
+  if (!mAudioDecoder) {
+    return false;
+  }
+
+  GMPAudioSamples* samples = new GMPAudioSamplesImpl(aEncodedSamples);
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mAudioDecoder->Decode(samples);
+
+  return true;
+}
+
+bool
+GMPAudioDecoderChild::RecvReset()
+{
+  if (!mAudioDecoder) {
+    return false;
+  }
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mAudioDecoder->Reset();
+
+  return true;
+}
+
+bool
+GMPAudioDecoderChild::RecvDrain()
+{
+  if (!mAudioDecoder) {
+    return false;
+  }
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mAudioDecoder->Drain();
+
+  return true;
+}
+
+bool
+GMPAudioDecoderChild::RecvDecodingComplete()
+{
+  if (mAudioDecoder) {
+    // Ignore any return code. It is OK for this to fail without killing the process.
+    mAudioDecoder->DecodingComplete();
+    mAudioDecoder = nullptr;
+  }
+
+  mPlugin = nullptr;
+
+  unused << Send__delete__(this);
+
+  return true;
+}
+
+} // namespace gmp
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/GMPAudioDecoderChild.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GMPAudioDecoderChild_h_
+#define GMPAudioDecoderChild_h_
+
+#include "mozilla/gmp/PGMPAudioDecoderChild.h"
+#include "gmp-audio-decode.h"
+#include "GMPAudioHost.h"
+
+namespace mozilla {
+namespace gmp {
+
+class GMPChild;
+
+class GMPAudioDecoderChild : public PGMPAudioDecoderChild,
+                             public GMPAudioDecoderCallback
+{
+public:
+  GMPAudioDecoderChild(GMPChild* aPlugin);
+  virtual ~GMPAudioDecoderChild();
+
+  void Init(GMPAudioDecoder* aDecoder);
+  GMPAudioHostImpl& Host();
+
+  // GMPAudioDecoderCallback
+  virtual void Decoded(GMPAudioSamples* aEncodedSamples) MOZ_OVERRIDE;
+  virtual void InputDataExhausted() MOZ_OVERRIDE;
+  virtual void DrainComplete() MOZ_OVERRIDE;
+  virtual void ResetComplete() MOZ_OVERRIDE;
+  virtual void Error(GMPErr aError) MOZ_OVERRIDE;
+
+private:
+  // PGMPAudioDecoderChild
+  virtual bool RecvInitDecode(const GMPAudioCodecData& codecSettings) MOZ_OVERRIDE;
+  virtual bool RecvDecode(const GMPAudioEncodedSampleData& input) MOZ_OVERRIDE;
+  virtual bool RecvReset() MOZ_OVERRIDE;
+  virtual bool RecvDrain() MOZ_OVERRIDE;
+  virtual bool RecvDecodingComplete() MOZ_OVERRIDE;
+
+  GMPChild* mPlugin;
+  GMPAudioDecoder* mAudioDecoder;
+  GMPAudioHostImpl mAudioHost;
+};
+
+} // namespace gmp
+} // namespace mozilla
+
+#endif // GMPAudioDecoderChild_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/GMPAudioDecoderParent.cpp
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GMPAudioDecoderParent.h"
+#include "GMPParent.h"
+#include <stdio.h>
+#include "mozilla/unused.h"
+#include "GMPMessageUtils.h"
+#include "nsThreadUtils.h"
+#include "prlog.h"
+
+namespace mozilla {
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#ifdef PR_LOGGING
+extern PRLogModuleInfo* GetGMPLog();
+
+#define LOGD(msg) PR_LOG(GetGMPLog(), PR_LOG_DEBUG, msg)
+#define LOG(level, msg) PR_LOG(GetGMPLog(), (level), msg)
+#else
+#define LOGD(msg)
+#define LOG(level, msg)
+#endif
+
+namespace gmp {
+
+GMPAudioDecoderParent::GMPAudioDecoderParent(GMPParent* aPlugin)
+  : mIsOpen(false)
+  , mPlugin(aPlugin)
+  , mCallback(nullptr)
+{
+  MOZ_ASSERT(mPlugin);
+}
+
+GMPAudioDecoderParent::~GMPAudioDecoderParent()
+{
+}
+
+nsresult
+GMPAudioDecoderParent::InitDecode(GMPAudioCodecType aCodecType,
+                                  uint32_t aChannelCount,
+                                  uint32_t aBitsPerChannel,
+                                  uint32_t aSamplesPerSecond,
+                                  nsTArray<uint8_t>& aExtraData,
+                                  GMPAudioDecoderProxyCallback* aCallback)
+{
+  if (mIsOpen) {
+    NS_WARNING("Trying to re-init an in-use GMP audio decoder!");
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+
+  if (!aCallback) {
+    return NS_ERROR_FAILURE;
+  }
+  mCallback = aCallback;
+
+  GMPAudioCodecData data;
+  data.mCodecType() = aCodecType;
+  data.mChannelCount() = aChannelCount;
+  data.mBitsPerChannel() = aBitsPerChannel;
+  data.mSamplesPerSecond() = aSamplesPerSecond;
+  data.mExtraData() = aExtraData;
+  if (!SendInitDecode(data)) {
+    return NS_ERROR_FAILURE;
+  }
+  mIsOpen = true;
+
+  // Async IPC, we don't have access to a return value.
+  return NS_OK;
+}
+
+nsresult
+GMPAudioDecoderParent::Decode(GMPAudioSamplesImpl& aEncodedSamples)
+{
+
+  if (!mIsOpen) {
+    NS_WARNING("Trying to use a dead GMP Audio decoder!");
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+
+  GMPAudioEncodedSampleData samples;
+  aEncodedSamples.RelinquishData(samples);
+
+  if (!SendDecode(samples)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Async IPC, we don't have access to a return value.
+  return NS_OK;
+}
+
+nsresult
+GMPAudioDecoderParent::Reset()
+{
+  if (!mIsOpen) {
+    NS_WARNING("Trying to use a dead GMP Audio decoder!");
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+
+  if (!SendReset()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Async IPC, we don't have access to a return value.
+  return NS_OK;
+}
+
+nsresult
+GMPAudioDecoderParent::Drain()
+{
+  if (!mIsOpen) {
+    NS_WARNING("Trying to use a dead GMP Audio decoder!");
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+
+  if (!SendDrain()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Async IPC, we don't have access to a return value.
+  return NS_OK;
+}
+
+// Note: Consider keeping ActorDestroy sync'd up when making changes here.
+nsresult
+GMPAudioDecoderParent::Close()
+{
+  LOGD(("%s: %p", __FUNCTION__, this));
+  MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+
+  // Consumer is done with us; we can shut down.  No more callbacks should
+  // be made to mCallback.  Note: do this before Shutdown()!
+  mCallback = nullptr;
+  // Let Shutdown mark us as dead so it knows if we had been alive
+
+  // In case this is the last reference
+  nsRefPtr<GMPAudioDecoderParent> kungfudeathgrip(this);
+  NS_RELEASE(kungfudeathgrip);
+  Shutdown();
+
+  return NS_OK;
+}
+
+// Note: Consider keeping ActorDestroy sync'd up when making changes here.
+nsresult
+GMPAudioDecoderParent::Shutdown()
+{
+  LOGD(("%s: %p", __FUNCTION__, this));
+  MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+
+  // Notify client we're gone!  Won't occur after Close()
+  if (mCallback) {
+    mCallback->Terminated();
+    mCallback = nullptr;
+  }
+
+  if (mIsOpen) {
+    // Don't send DecodingComplete if we died
+    mIsOpen = false;
+    unused << SendDecodingComplete();
+  }
+
+  return NS_OK;
+}
+
+// Note: Keep this sync'd up with DecodingComplete
+void
+GMPAudioDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mIsOpen = false;
+  if (mCallback) {
+    // May call Close() (and Shutdown()) immediately or with a delay
+    mCallback->Terminated();
+    mCallback = nullptr;
+  }
+  if (mPlugin) {
+    // Ignore any return code. It is OK for this to fail without killing the process.
+    mPlugin->AudioDecoderDestroyed(this);
+    mPlugin = nullptr;
+  }
+}
+
+bool
+GMPAudioDecoderParent::RecvDecoded(const GMPAudioDecodedSampleData& aDecoded)
+{
+  if (!mCallback) {
+    return false;
+  }
+
+  mCallback->Decoded(aDecoded.mData(), aDecoded.mTimeStamp());
+
+  return true;
+}
+
+bool
+GMPAudioDecoderParent::RecvInputDataExhausted()
+{
+  if (!mCallback) {
+    return false;
+  }
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mCallback->InputDataExhausted();
+
+  return true;
+}
+
+bool
+GMPAudioDecoderParent::RecvDrainComplete()
+{
+  if (!mCallback) {
+    return false;
+  }
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mCallback->DrainComplete();
+
+  return true;
+}
+
+bool
+GMPAudioDecoderParent::RecvResetComplete()
+{
+  if (!mCallback) {
+    return false;
+  }
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mCallback->ResetComplete();
+
+  return true;
+}
+
+bool
+GMPAudioDecoderParent::RecvError(const GMPErr& aError)
+{
+  if (!mCallback) {
+    return false;
+  }
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mCallback->Error(aError);
+
+  return true;
+}
+
+bool
+GMPAudioDecoderParent::Recv__delete__()
+{
+  if (mPlugin) {
+    // Ignore any return code. It is OK for this to fail without killing the process.
+    mPlugin->AudioDecoderDestroyed(this);
+    mPlugin = nullptr;
+  }
+
+  return true;
+}
+
+} // namespace gmp
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/GMPAudioDecoderParent.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GMPAudioDecoderParent_h_
+#define GMPAudioDecoderParent_h_
+
+#include "mozilla/RefPtr.h"
+#include "gmp-audio-decode.h"
+#include "gmp-audio-codec.h"
+#include "mozilla/gmp/PGMPAudioDecoderParent.h"
+#include "GMPMessageUtils.h"
+#include "GMPAudioDecoderProxy.h"
+
+namespace mozilla {
+namespace gmp {
+
+class GMPParent;
+
+class GMPAudioDecoderParent MOZ_FINAL : public GMPAudioDecoderProxy
+                                      , public PGMPAudioDecoderParent
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(GMPAudioDecoderParent)
+
+  GMPAudioDecoderParent(GMPParent *aPlugin);
+
+  nsresult Shutdown();
+
+  // GMPAudioDecoderProxy
+  virtual nsresult InitDecode(GMPAudioCodecType aCodecType,
+                              uint32_t aChannelCount,
+                              uint32_t aBitsPerChannel,
+                              uint32_t aSamplesPerSecond,
+                              nsTArray<uint8_t>& aExtraData,
+                              GMPAudioDecoderProxyCallback* aCallback) MOZ_OVERRIDE;
+  virtual nsresult Decode(GMPAudioSamplesImpl& aInput) MOZ_OVERRIDE;
+  virtual nsresult Reset() MOZ_OVERRIDE;
+  virtual nsresult Drain() MOZ_OVERRIDE;
+  virtual nsresult Close() MOZ_OVERRIDE;
+
+private:
+  ~GMPAudioDecoderParent();
+
+  // PGMPAudioDecoderParent
+  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+  virtual bool RecvDecoded(const GMPAudioDecodedSampleData& aDecoded) MOZ_OVERRIDE;
+  virtual bool RecvInputDataExhausted() MOZ_OVERRIDE;
+  virtual bool RecvDrainComplete() MOZ_OVERRIDE;
+  virtual bool RecvResetComplete() MOZ_OVERRIDE;
+  virtual bool RecvError(const GMPErr& aError) MOZ_OVERRIDE;
+  virtual bool Recv__delete__() MOZ_OVERRIDE;
+
+  bool mIsOpen;
+  nsRefPtr<GMPParent> mPlugin;
+  GMPAudioDecoderProxyCallback* mCallback;
+};
+
+} // namespace gmp
+} // namespace mozilla
+
+#endif // GMPAudioDecoderParent_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/GMPAudioDecoderProxy.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GMPAudioDecoderProxy_h_
+#define GMPAudioDecoderProxy_h_
+
+#include "GMPCallbackBase.h"
+#include "gmp-audio-codec.h"
+#include "GMPAudioHost.h"
+#include "nsTArray.h"
+#include "mozilla/gmp/GMPTypes.h"
+
+class GMPAudioDecoderProxyCallback : public GMPCallbackBase {
+public:
+  virtual ~GMPAudioDecoderProxyCallback() {}
+  virtual void Decoded(const nsTArray<int16_t>& aPCM, uint64_t aTimeStamp) = 0;
+  virtual void InputDataExhausted() = 0;
+  virtual void DrainComplete() = 0;
+  virtual void ResetComplete() = 0;
+  virtual void Error(GMPErr aError) = 0;
+};
+
+class GMPAudioDecoderProxy {
+public:
+  virtual ~GMPAudioDecoderProxy() {}
+
+  virtual nsresult InitDecode(GMPAudioCodecType aCodecType,
+                              uint32_t aChannelCount,
+                              uint32_t aBitsPerChannel,
+                              uint32_t aSamplesPerSecond,
+                              nsTArray<uint8_t>& aExtraData,
+                              GMPAudioDecoderProxyCallback* aCallback) = 0;
+  virtual nsresult Decode(mozilla::gmp::GMPAudioSamplesImpl& aSamples) = 0;
+  virtual nsresult Reset() = 0;
+  virtual nsresult Drain() = 0;
+  // Call to tell GMP/plugin the consumer will no longer use this
+  // interface/codec.
+  virtual nsresult Close() = 0;
+};
+
+#endif // GMPAudioDecoderProxy_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/GMPAudioHost.cpp
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GMPAudioHost.h"
+#include "gmp-audio-samples.h"
+#include "gmp-errors.h"
+#include "GMPEncryptedBufferDataImpl.h"
+
+namespace mozilla {
+namespace gmp {
+
+GMPAudioSamplesImpl::GMPAudioSamplesImpl(GMPAudioFormat aFormat)
+  : mFormat(aFormat)
+  , mTimeStamp(0)
+{
+}
+
+GMPAudioSamplesImpl::GMPAudioSamplesImpl(const GMPAudioEncodedSampleData& aData)
+  : mFormat(kGMPAudioEncodedSamples)
+  , mBuffer(aData.mData())
+  , mTimeStamp(aData.mTimeStamp())
+{
+  if (aData.mDecryptionData().mKeyId().Length() > 0) {
+    mCrypto = new GMPEncryptedBufferDataImpl(aData.mDecryptionData());
+  }
+}
+
+GMPAudioSamplesImpl::GMPAudioSamplesImpl(mp4_demuxer::MP4Sample* aSample)
+ : mFormat(kGMPAudioEncodedSamples)
+ , mTimeStamp(aSample->composition_timestamp)
+{
+  mBuffer.AppendElements(aSample->data, aSample->size);
+  if (aSample->crypto.valid) {
+    mCrypto = new GMPEncryptedBufferDataImpl(aSample->crypto);
+  }
+}
+
+GMPAudioSamplesImpl::~GMPAudioSamplesImpl()
+{
+}
+
+GMPAudioFormat
+GMPAudioSamplesImpl::GetFormat()
+{
+  return mFormat;
+}
+
+void
+GMPAudioSamplesImpl::Destroy()
+{
+  delete this;
+}
+
+GMPErr
+GMPAudioSamplesImpl::SetBufferSize(uint32_t aSize)
+{
+  mBuffer.SetLength(aSize);
+  return GMPNoErr;
+}
+
+uint32_t
+GMPAudioSamplesImpl::Size()
+{
+  return mBuffer.Length();
+}
+
+void
+GMPAudioSamplesImpl::SetTimeStamp(uint64_t aTimeStamp)
+{
+  mTimeStamp = aTimeStamp;
+}
+
+uint64_t
+GMPAudioSamplesImpl::TimeStamp()
+{
+  return mTimeStamp;
+}
+
+const uint8_t*
+GMPAudioSamplesImpl::Buffer() const
+{
+  return mBuffer.Elements();
+}
+
+uint8_t*
+GMPAudioSamplesImpl::Buffer()
+{
+  return mBuffer.Elements();
+}
+
+const GMPEncryptedBufferMetadata*
+GMPAudioSamplesImpl::GetDecryptionData() const
+{
+  return mCrypto;
+}
+
+void
+GMPAudioSamplesImpl::InitCrypto(const mp4_demuxer::CryptoSample& aCrypto)
+{
+  if (!aCrypto.valid) {
+    return;
+  }
+  mCrypto = new GMPEncryptedBufferDataImpl(aCrypto);
+}
+
+void
+GMPAudioSamplesImpl::RelinquishData(GMPAudioEncodedSampleData& aData)
+{
+  aData.mData() = Move(mBuffer);
+  aData.mTimeStamp() = TimeStamp();
+  if (mCrypto) {
+    mCrypto->RelinquishData(aData.mDecryptionData());
+  }
+}
+
+GMPErr
+GMPAudioHostImpl::CreateSamples(GMPAudioFormat aFormat,
+                                GMPAudioSamples** aSamples)
+{
+
+  *aSamples = new GMPAudioSamplesImpl(aFormat);
+  return GMPNoErr;
+}
+
+} // namespace gmp
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/GMPAudioHost.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GMPAudioHost_h_
+#define GMPAudioHost_h_
+
+#include "gmp-audio-host.h"
+#include "gmp-audio-samples.h"
+#include "nsTArray.h"
+#include "gmp-decryption.h"
+#include "mp4_demuxer/DecoderData.h"
+#include "nsAutoPtr.h"
+#include "GMPEncryptedBufferDataImpl.h"
+#include "mozilla/gmp/GMPTypes.h"
+
+namespace mozilla {
+namespace gmp {
+
+class GMPAudioSamplesImpl : public GMPAudioSamples {
+public:
+  GMPAudioSamplesImpl(GMPAudioFormat aFormat);
+  GMPAudioSamplesImpl(const GMPAudioEncodedSampleData& aData);
+  GMPAudioSamplesImpl(mp4_demuxer::MP4Sample* aSample);
+  virtual ~GMPAudioSamplesImpl();
+
+  virtual GMPAudioFormat GetFormat() MOZ_OVERRIDE;
+  virtual void Destroy() MOZ_OVERRIDE;
+  virtual GMPErr SetBufferSize(uint32_t aSize) MOZ_OVERRIDE;
+  virtual uint32_t Size() MOZ_OVERRIDE;
+  virtual void SetTimeStamp(uint64_t aTimeStamp) MOZ_OVERRIDE;
+  virtual uint64_t TimeStamp() MOZ_OVERRIDE;
+  virtual const uint8_t* Buffer() const MOZ_OVERRIDE;
+  virtual uint8_t* Buffer() MOZ_OVERRIDE;
+  virtual const GMPEncryptedBufferMetadata* GetDecryptionData() const MOZ_OVERRIDE;
+
+  void InitCrypto(const mp4_demuxer::CryptoSample& aCrypto);
+
+  void RelinquishData(GMPAudioEncodedSampleData& aData);
+
+private:
+  GMPAudioFormat mFormat;
+  nsTArray<uint8_t> mBuffer;
+  int64_t mTimeStamp;
+  nsAutoPtr<GMPEncryptedBufferDataImpl> mCrypto;
+};
+
+class GMPAudioHostImpl : public GMPAudioHost
+{
+public:
+  virtual GMPErr CreateSamples(GMPAudioFormat aFormat,
+                               GMPAudioSamples** aSamples) MOZ_OVERRIDE;
+private:
+};
+
+} // namespace gmp
+} // namespace mozilla
+
+#endif // GMPAudioHost_h_
--- a/content/media/gmp/GMPChild.cpp
+++ b/content/media/gmp/GMPChild.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GMPChild.h"
 #include "GMPVideoDecoderChild.h"
 #include "GMPVideoEncoderChild.h"
+#include "GMPAudioDecoderChild.h"
 #include "GMPDecryptorChild.h"
 #include "GMPVideoHost.h"
 #include "nsIFile.h"
 #include "nsXULAppAPI.h"
 #include "gmp-video-decode.h"
 #include "gmp-video-encode.h"
 #include "GMPPlatform.h"
 #include "mozilla/dom/CrashReporterChild.h"
@@ -165,16 +166,29 @@ GMPChild::ProcessingError(Result aWhat)
       MOZ_CRASH("aborting because of MsgRouteError");
     case MsgValueError:
       MOZ_CRASH("aborting because of MsgValueError");
     default:
       MOZ_CRASH("not reached");
   }
 }
 
+PGMPAudioDecoderChild*
+GMPChild::AllocPGMPAudioDecoderChild()
+{
+  return new GMPAudioDecoderChild(this);
+}
+
+bool
+GMPChild::DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
 mozilla::dom::PCrashReporterChild*
 GMPChild::AllocPCrashReporterChild(const NativeThreadId& aThread)
 {
   return new CrashReporterChild();
 }
 
 bool
 GMPChild::DeallocPCrashReporterChild(PCrashReporterChild* aCrashReporter)
@@ -204,16 +218,32 @@ GMPChild::AllocPGMPDecryptorChild()
 
 bool
 GMPChild::DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor)
 {
   delete aActor;
   return true;
 }
 
+bool
+GMPChild::RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor)
+{
+  auto vdc = static_cast<GMPAudioDecoderChild*>(aActor);
+
+  void* vd = nullptr;
+  GMPErr err = mGetAPIFunc("decode-audio", &vdc->Host(), &vd);
+  if (err != GMPNoErr || !vd) {
+    return false;
+  }
+
+  vdc->Init(static_cast<GMPAudioDecoder*>(vd));
+
+  return true;
+}
+
 PGMPVideoEncoderChild*
 GMPChild::AllocPGMPVideoEncoderChild()
 {
   return new GMPVideoEncoderChild(this);
 }
 
 bool
 GMPChild::DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor)
@@ -269,14 +299,14 @@ GMPChild::RecvPGMPDecryptorConstructor(P
   child->Init(static_cast<GMPDecryptor*>(session));
 
   return true;
 }
 
 bool
 GMPChild::RecvCrashPluginNow()
 {
-  abort();
+  MOZ_CRASH();
   return true;
 }
 
 } // namespace gmp
 } // namespace mozilla
--- a/content/media/gmp/GMPChild.h
+++ b/content/media/gmp/GMPChild.h
@@ -42,16 +42,20 @@ private:
   virtual PGMPVideoEncoderChild* AllocPGMPVideoEncoderChild() MOZ_OVERRIDE;
   virtual bool DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor) MOZ_OVERRIDE;
   virtual bool RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor) MOZ_OVERRIDE;
 
   virtual PGMPDecryptorChild* AllocPGMPDecryptorChild() MOZ_OVERRIDE;
   virtual bool DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor) MOZ_OVERRIDE;
   virtual bool RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor) MOZ_OVERRIDE;
 
+  virtual PGMPAudioDecoderChild* AllocPGMPAudioDecoderChild() MOZ_OVERRIDE;
+  virtual bool DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor) MOZ_OVERRIDE;
+  virtual bool RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor) MOZ_OVERRIDE;
+
   virtual bool RecvCrashPluginNow() MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   virtual void ProcessingError(Result aWhat) MOZ_OVERRIDE;
 
   PRLibrary* mLib;
   GMPGetAPIFunc mGetAPIFunc;
   MessageLoop* mGMPMessageLoop;
--- a/content/media/gmp/GMPEncryptedBufferDataImpl.cpp
+++ b/content/media/gmp/GMPEncryptedBufferDataImpl.cpp
@@ -21,16 +21,20 @@ GMPEncryptedBufferDataImpl::GMPEncrypted
 {
   mKeyId = aData.mKeyId();
   mIV = aData.mIV();
   mClearBytes = aData.mClearBytes();
   mCipherBytes = aData.mCipherBytes();
   MOZ_ASSERT(mClearBytes.Length() == mCipherBytes.Length());
 }
 
+GMPEncryptedBufferDataImpl::~GMPEncryptedBufferDataImpl()
+{
+}
+
 void
 GMPEncryptedBufferDataImpl::RelinquishData(GMPDecryptionData& aData)
 {
   aData.mKeyId() = Move(mKeyId);
   aData.mIV() = Move(mIV);
   aData.mClearBytes() = Move(mClearBytes);
   aData.mCipherBytes() = Move(mCipherBytes);
 }
--- a/content/media/gmp/GMPEncryptedBufferDataImpl.h
+++ b/content/media/gmp/GMPEncryptedBufferDataImpl.h
@@ -15,16 +15,17 @@ namespace mozilla {
 namespace gmp {
 
 class GMPEncryptedBufferDataImpl : public GMPEncryptedBufferMetadata {
 private:
   typedef mp4_demuxer::CryptoSample CryptoSample;
 public:
   GMPEncryptedBufferDataImpl(const CryptoSample& aCrypto);
   GMPEncryptedBufferDataImpl(const GMPDecryptionData& aData);
+  virtual ~GMPEncryptedBufferDataImpl();
 
   void RelinquishData(GMPDecryptionData& aData);
 
   virtual const uint8_t* KeyId() const MOZ_OVERRIDE;
   virtual uint32_t KeyIdSize() const MOZ_OVERRIDE;
   virtual const uint8_t* IV() const MOZ_OVERRIDE;
   virtual uint32_t IVSize() const MOZ_OVERRIDE;
   virtual uint32_t NumSubsamples() const MOZ_OVERRIDE;
--- a/content/media/gmp/GMPMessageUtils.h
+++ b/content/media/gmp/GMPMessageUtils.h
@@ -3,16 +3,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/. */
 
 #ifndef GMPMessageUtils_h_
 #define GMPMessageUtils_h_
 
 #include "gmp-video-codec.h"
 #include "gmp-video-frame-encoded.h"
+#include "gmp-audio-codec.h"
 #include "gmp-decryption.h"
 
 namespace IPC {
 
 template <>
 struct ParamTraits<GMPErr>
 : public ContiguousEnumSerializer<GMPErr,
                                   GMPNoErr,
@@ -55,16 +56,23 @@ struct ParamTraits<GMPDOMException>
 template <>
 struct ParamTraits<GMPSessionType>
 : public ContiguousEnumSerializer<GMPSessionType,
                                   kGMPTemporySession,
                                   kGMPPersistentSession>
 {};
 
 template <>
+struct ParamTraits<GMPAudioCodecType>
+: public ContiguousEnumSerializer<GMPAudioCodecType,
+                                  kGMPAudioCodecAAC,
+                                  kGMPAudioCodecInvalid>
+{};
+
+template <>
 struct ParamTraits<GMPVideoCodecComplexity>
 : public ContiguousEnumSerializer<GMPVideoCodecComplexity,
                                   kGMPComplexityNormal,
                                   kGMPComplexityInvalid>
 {};
 
 template <>
 struct ParamTraits<GMPVP8ResilienceMode>
--- a/content/media/gmp/GMPParent.cpp
+++ b/content/media/gmp/GMPParent.cpp
@@ -149,22 +149,36 @@ GMPParent::CloseIfUnused()
 {
   MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
 
   if ((mDeleteProcessOnlyOnUnload ||
        mState == GMPStateLoaded ||
        mState == GMPStateUnloading) &&
       mVideoDecoders.IsEmpty() &&
       mVideoEncoders.IsEmpty() &&
-      mDecryptors.IsEmpty()) {
+      mDecryptors.IsEmpty() &&
+      mAudioDecoders.IsEmpty()) {
     Shutdown();
   }
 }
 
 void
+GMPParent::AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder)
+{
+  MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
+
+  MOZ_ALWAYS_TRUE(mAudioDecoders.RemoveElement(aDecoder));
+
+  // Recv__delete__ is on the stack, don't potentially destroy the top-level actor
+  // until after this has completed.
+  nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &GMPParent::CloseIfUnused);
+  NS_DispatchToCurrentThread(event);
+}
+
+void
 GMPParent::CloseActive(bool aDieWhenUnloaded)
 {
   LOGD(("%s::%s: %p state %d", __CLASS__, __FUNCTION__, this, mState));
   if (aDieWhenUnloaded) {
     mDeleteProcessOnlyOnUnload = true; // don't allow this to go back...
   }
   if (mState == GMPStateLoaded) {
     mState = GMPStateUnloading;
@@ -180,16 +194,21 @@ GMPParent::CloseActive(bool aDieWhenUnlo
     mVideoEncoders[i - 1]->Shutdown();
   }
 
   // Invalidate and remove any remaining API objects.
   for (uint32_t i = mDecryptors.Length(); i > 0; i--) {
     mDecryptors[i - 1]->Shutdown();
   }
 
+  // Invalidate and remove any remaining API objects.
+  for (uint32_t i = mAudioDecoders.Length(); i > 0; i--) {
+    mAudioDecoders[i - 1]->Shutdown();
+  }
+
   // Note: the shutdown of the codecs is async!  don't kill
   // the plugin-container until they're all safely shut down via
   // CloseIfUnused();
   CloseIfUnused();
 }
 
 void
 GMPParent::Shutdown()
@@ -362,16 +381,39 @@ GMPParent::EnsureProcessLoaded()
   }
 
   nsresult rv = LoadProcess();
 
   return NS_SUCCEEDED(rv);
 }
 
 nsresult
+GMPParent::GetGMPAudioDecoder(GMPAudioDecoderParent** aGMPAD)
+{
+  MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
+
+  if (!EnsureProcessLoaded()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  PGMPAudioDecoderParent* pvap = SendPGMPAudioDecoderConstructor();
+  if (!pvap) {
+    return NS_ERROR_FAILURE;
+  }
+  GMPAudioDecoderParent* vap = static_cast<GMPAudioDecoderParent*>(pvap);
+  // This addref corresponds to the Proxy pointer the consumer is returned.
+  // It's dropped by calling Close() on the interface.
+  NS_ADDREF(vap);
+  *aGMPAD = vap;
+  mAudioDecoders.AppendElement(vap);
+
+  return NS_OK;
+}
+
+nsresult
 GMPParent::GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD)
 {
   MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
 
   if (!EnsureProcessLoaded()) {
     return NS_ERROR_FAILURE;
   }
 
@@ -555,16 +597,32 @@ GMPParent::AllocPGMPDecryptorParent()
 bool
 GMPParent::DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor)
 {
   GMPDecryptorParent* ksp = static_cast<GMPDecryptorParent*>(aActor);
   NS_RELEASE(ksp);
   return true;
 }
 
+PGMPAudioDecoderParent*
+GMPParent::AllocPGMPAudioDecoderParent()
+{
+  GMPAudioDecoderParent* vdp = new GMPAudioDecoderParent(this);
+  NS_ADDREF(vdp);
+  return vdp;
+}
+
+bool
+GMPParent::DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor)
+{
+  GMPAudioDecoderParent* vdp = static_cast<GMPAudioDecoderParent*>(aActor);
+  NS_RELEASE(vdp);
+  return true;
+}
+
 nsresult
 ParseNextRecord(nsILineInputStream* aLineInputStream,
                 const nsCString& aPrefix,
                 nsCString& aResult,
                 bool& aMoreLines)
 {
   nsAutoCString record;
   nsresult rv = aLineInputStream->ReadLine(record, &aMoreLines);
--- a/content/media/gmp/GMPParent.h
+++ b/content/media/gmp/GMPParent.h
@@ -3,16 +3,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/. */
 
 #ifndef GMPParent_h_
 #define GMPParent_h_
 
 #include "GMPProcessParent.h"
 #include "GMPService.h"
+#include "GMPAudioDecoderParent.h"
 #include "GMPDecryptorParent.h"
 #include "GMPVideoDecoderParent.h"
 #include "GMPVideoEncoderParent.h"
 #include "mozilla/gmp/PGMPParent.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 #include "nsISupports.h"
 #include "nsString.h"
@@ -85,16 +86,19 @@ public:
   void VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder);
 
   nsresult GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE);
   void VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder);
 
   nsresult GetGMPDecryptor(GMPDecryptorParent** aGMPKS);
   void DecryptorDestroyed(GMPDecryptorParent* aSession);
 
+  nsresult GetGMPAudioDecoder(GMPAudioDecoderParent** aGMPAD);
+  void AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder);
+
   GMPState State() const;
 #ifdef DEBUG
   nsIThread* GMPThread();
 #endif
 
   // A GMP can either be a single instance shared across all origins (like
   // in the OpenH264 case), or we can require a new plugin instance for every
   // origin running the plugin (as in the EME plugin case).
@@ -141,30 +145,34 @@ private:
   virtual bool DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor) MOZ_OVERRIDE;
   
   virtual PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() MOZ_OVERRIDE;
   virtual bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) MOZ_OVERRIDE;
 
   virtual PGMPDecryptorParent* AllocPGMPDecryptorParent() MOZ_OVERRIDE;
   virtual bool DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor) MOZ_OVERRIDE;
 
+  virtual PGMPAudioDecoderParent* AllocPGMPAudioDecoderParent() MOZ_OVERRIDE;
+  virtual bool DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) MOZ_OVERRIDE;
+
   GMPState mState;
   nsCOMPtr<nsIFile> mDirectory; // plugin directory on disk
   nsString mName; // base name of plugin on disk, UTF-16 because used for paths
   nsCString mDisplayName; // name of plugin displayed to users
   nsCString mDescription; // description of plugin for display to users
   nsCString mVersion;
   nsTArray<nsAutoPtr<GMPCapability>> mCapabilities;
   GMPProcessParent* mProcess;
   bool mDeleteProcessOnlyOnUnload;
   bool mAbnormalShutdownInProgress;
 
   nsTArray<nsRefPtr<GMPVideoDecoderParent>> mVideoDecoders;
   nsTArray<nsRefPtr<GMPVideoEncoderParent>> mVideoEncoders;
   nsTArray<nsRefPtr<GMPDecryptorParent>> mDecryptors;
+  nsTArray<nsRefPtr<GMPAudioDecoderParent>> mAudioDecoders;
 #ifdef DEBUG
   nsCOMPtr<nsIThread> mGMPThread;
 #endif
   // Origin the plugin is assigned to, or empty if the the plugin is not
   // assigned to an origin.
   nsAutoString mOrigin;
 };
 
--- a/content/media/gmp/GMPService.cpp
+++ b/content/media/gmp/GMPService.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SyncRunnable.h"
 #include "nsXPCOMPrivate.h"
 #include "mozilla/Services.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsIConsoleService.h"
 #include "mozilla/unused.h"
 #include "GMPDecryptorParent.h"
+#include "GMPAudioDecoderParent.h"
 #include "runnable_utils.h"
 
 namespace mozilla {
 
 #ifdef LOG
 #undef LOG
 #endif
 
@@ -236,16 +237,47 @@ GeckoMediaPluginService::GetThread(nsITh
 
   NS_ADDREF(mGMPThread);
   *aThread = mGMPThread;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+GeckoMediaPluginService::GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
+                                            const nsAString& aOrigin,
+                                            GMPAudioDecoderProxy** aGMPAD)
+{
+  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
+  NS_ENSURE_ARG(aTags && aTags->Length() > 0);
+  NS_ENSURE_ARG(aGMPAD);
+
+  if (mShuttingDownOnGMPThread) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
+                                               NS_LITERAL_CSTRING("decode-audio"),
+                                               *aTags);
+  if (!gmp) {
+    return NS_ERROR_FAILURE;
+  }
+
+  GMPAudioDecoderParent* gmpADP;
+  nsresult rv = gmp->GetGMPAudioDecoder(&gmpADP);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  *aGMPAD = gmpADP;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
                                             const nsAString& aOrigin,
                                             GMPVideoHost** aOutVideoHost,
                                             GMPVideoDecoderProxy** aGMPVD)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
   NS_ENSURE_ARG(aOutVideoHost);
--- a/content/media/gmp/GMPTypes.ipdlh
+++ b/content/media/gmp/GMPTypes.ipdlh
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 using GMPBufferType from "gmp-video-codec.h";
+using GMPAudioCodecType from "gmp-audio-codec.h";
 
 namespace mozilla {
 namespace gmp {
 
 struct GMPDecryptionData {
   uint8_t[] mKeyId;
   uint8_t[] mIV;
   uint16_t[] mClearBytes;
@@ -42,10 +43,33 @@ struct GMPVideoi420FrameData
   GMPPlaneData mUPlane;
   GMPPlaneData mVPlane;
   int32_t mWidth;
   int32_t mHeight;
   uint64_t mTimestamp; // microseconds
   uint64_t mDuration; // microseconds
 };
 
+struct GMPAudioCodecData
+{
+  GMPAudioCodecType mCodecType;
+  uint32_t mChannelCount;
+  uint32_t mBitsPerChannel;
+  uint32_t mSamplesPerSecond;
+
+  uint8_t[] mExtraData;
+};
+
+struct GMPAudioEncodedSampleData
+{
+  uint8_t[] mData;
+  uint64_t mTimeStamp; // microseconds.
+  GMPDecryptionData mDecryptionData;
+};
+
+struct GMPAudioDecodedSampleData
+{
+  int16_t[] mData;
+  uint64_t mTimeStamp; // microseconds.
+};
+
 }
 }
--- a/content/media/gmp/GMPVideoEncodedFrameImpl.cpp
+++ b/content/media/gmp/GMPVideoEncodedFrameImpl.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GMPVideoEncodedFrameImpl.h"
 #include "GMPVideoHost.h"
 #include "mozilla/gmp/GMPTypes.h"
 #include "GMPSharedMemManager.h"
+#include "GMPEncryptedBufferDataImpl.h"
 
 namespace mozilla {
 namespace gmp {
 
 GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(GMPVideoHostImpl* aHost)
 : mEncodedWidth(0),
   mEncodedHeight(0),
   mTimeStamp(0ll),
@@ -35,31 +36,40 @@ GMPVideoEncodedFrameImpl::GMPVideoEncode
   mFrameType(static_cast<GMPVideoFrameType>(aFrameData.mFrameType())),
   mSize(aFrameData.mSize()),
   mCompleteFrame(aFrameData.mCompleteFrame()),
   mHost(aHost),
   mBuffer(aFrameData.mBuffer()),
   mBufferType(aFrameData.mBufferType())
 {
   MOZ_ASSERT(aHost);
+  if (aFrameData.mDecryptionData().mKeyId().Length() > 0) {
+    mCrypto = new GMPEncryptedBufferDataImpl(aFrameData.mDecryptionData());
+  }
   aHost->EncodedFrameCreated(this);
 }
 
 GMPVideoEncodedFrameImpl::~GMPVideoEncodedFrameImpl()
 {
   DestroyBuffer();
   if (mHost) {
     mHost->EncodedFrameDestroyed(this);
   }
 }
 
+void
+GMPVideoEncodedFrameImpl::InitCrypto(const mp4_demuxer::CryptoSample& aCrypto)
+{
+  mCrypto = new GMPEncryptedBufferDataImpl(aCrypto);
+}
+
 const GMPEncryptedBufferMetadata*
 GMPVideoEncodedFrameImpl::GetDecryptionData() const
 {
-  return nullptr;
+  return mCrypto;
 }
 
 GMPVideoFrameFormat
 GMPVideoEncodedFrameImpl::GetFrameFormat()
 {
   return kGMPEncodedVideoFrame;
 }
 
@@ -90,16 +100,19 @@ GMPVideoEncodedFrameImpl::RelinquishFram
   aFrameData.mEncodedHeight() = mEncodedHeight;
   aFrameData.mTimestamp() = mTimeStamp;
   aFrameData.mDuration() = mDuration;
   aFrameData.mFrameType() = mFrameType;
   aFrameData.mSize() = mSize;
   aFrameData.mCompleteFrame() = mCompleteFrame;
   aFrameData.mBuffer() = mBuffer;
   aFrameData.mBufferType() = mBufferType;
+  if (mCrypto) {
+    mCrypto->RelinquishData(aFrameData.mDecryptionData());
+  }
 
   // This method is called right before Shmem is sent to another process.
   // We need to effectively zero out our member copy so that we don't
   // try to delete Shmem we don't own later.
   mBuffer = ipc::Shmem();
 
   return true;
 }
@@ -146,16 +159,17 @@ GMPVideoEncodedFrameImpl::CopyFrame(cons
   mEncodedWidth = f.mEncodedWidth;
   mEncodedHeight = f.mEncodedHeight;
   mTimeStamp = f.mTimeStamp;
   mDuration = f.mDuration;
   mFrameType = f.mFrameType;
   mSize = f.mSize; // already set...
   mCompleteFrame = f.mCompleteFrame;
   mBufferType = f.mBufferType;
+  mCrypto = new GMPEncryptedBufferDataImpl(*(f.mCrypto));
   // Don't copy host, that should have been set properly on object creation via host.
 
   return GMPNoErr;
 }
 
 void
 GMPVideoEncodedFrameImpl::SetEncodedWidth(uint32_t aEncodedWidth)
 {
--- a/content/media/gmp/GMPVideoEncodedFrameImpl.h
+++ b/content/media/gmp/GMPVideoEncodedFrameImpl.h
@@ -31,31 +31,35 @@
 #ifndef GMPVideoEncodedFrameImpl_h_
 #define GMPVideoEncodedFrameImpl_h_
 
 #include "gmp-errors.h"
 #include "gmp-video-frame.h"
 #include "gmp-video-frame-encoded.h"
 #include "gmp-decryption.h"
 #include "mozilla/ipc/Shmem.h"
+#include "mp4_demuxer/DecoderData.h"
 
 namespace mozilla {
 namespace gmp {
 
 class GMPVideoHostImpl;
 class GMPVideoEncodedFrameData;
+class GMPEncryptedBufferDataImpl;
 
 class GMPVideoEncodedFrameImpl: public GMPVideoEncodedFrame
 {
   friend struct IPC::ParamTraits<mozilla::gmp::GMPVideoEncodedFrameImpl>;
 public:
   GMPVideoEncodedFrameImpl(GMPVideoHostImpl* aHost);
   GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameData& aFrameData, GMPVideoHostImpl* aHost);
   virtual ~GMPVideoEncodedFrameImpl();
 
+  void InitCrypto(const mp4_demuxer::CryptoSample& aCrypto);
+
   // This is called during a normal destroy sequence, which is
   // when a consumer is finished or during XPCOM shutdown.
   void DoneWithAPI();
   // Does not attempt to release Shmem, as the Shmem has already been released.
   void ActorDestroyed();
 
   bool RelinquishFrameData(GMPVideoEncodedFrameData& aFrameData);
 
@@ -101,14 +105,15 @@ private:
   uint64_t mTimeStamp;
   uint64_t mDuration;
   GMPVideoFrameType mFrameType;
   uint32_t mSize;
   bool     mCompleteFrame;
   GMPVideoHostImpl* mHost;
   ipc::Shmem mBuffer;
   GMPBufferType mBufferType;
+  nsAutoPtr<GMPEncryptedBufferDataImpl> mCrypto;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPVideoEncodedFrameImpl_h_
--- a/content/media/gmp/GMPVideoEncoderParent.cpp
+++ b/content/media/gmp/GMPVideoEncoderParent.cpp
@@ -8,16 +8,17 @@
 #include "GMPVideoi420FrameImpl.h"
 #include "GMPVideoEncodedFrameImpl.h"
 #include "mozilla/unused.h"
 #include "GMPMessageUtils.h"
 #include "nsAutoRef.h"
 #include "GMPParent.h"
 #include "mozilla/gmp/GMPTypes.h"
 #include "nsThreadUtils.h"
+#include "runnable_utils.h"
 
 template <>
 class nsAutoRefTraits<GMPVideoi420Frame> : public nsPointerRefTraits<GMPVideoi420Frame>
 {
 public:
   static void Release(GMPVideoi420Frame* aFrame) { aFrame->Destroy(); }
 };
 
@@ -57,20 +58,26 @@ namespace gmp {
 GMPVideoEncoderParent::GMPVideoEncoderParent(GMPParent *aPlugin)
 : GMPSharedMemManager(aPlugin),
   mIsOpen(false),
   mPlugin(aPlugin),
   mCallback(nullptr),
   mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
 {
   MOZ_ASSERT(mPlugin);
+
+  nsresult rv = NS_NewNamedThread("GMPEncoded", getter_AddRefs(mEncodedThread));
+  if (NS_FAILED(rv)) {
+    MOZ_CRASH();
+  }
 }
 
 GMPVideoEncoderParent::~GMPVideoEncoderParent()
 {
+  mEncodedThread->Shutdown();
 }
 
 GMPVideoHostImpl&
 GMPVideoEncoderParent::Host()
 {
   return mVideoHost;
 }
 
@@ -245,31 +252,48 @@ GMPVideoEncoderParent::ActorDestroy(Acto
   if (mPlugin) {
     // Ignore any return code. It is OK for this to fail without killing the process.
     mPlugin->VideoEncoderDestroyed(this);
     mPlugin = nullptr;
   }
   mVideoHost.ActorDestroyed();
 }
 
+static void
+EncodedCallback(GMPVideoEncoderCallbackProxy* aCallback,
+                GMPVideoEncodedFrame* aEncodedFrame,
+                nsTArray<uint8_t>* aCodecSpecificInfo,
+                nsCOMPtr<nsIThread> aThread)
+{
+  aCallback->Encoded(aEncodedFrame, *aCodecSpecificInfo);
+  delete aCodecSpecificInfo;
+  // Ugh.  Must destroy the frame on GMPThread.
+  // XXX add locks to the ShmemManager instead?
+  aThread->Dispatch(WrapRunnable(aEncodedFrame,
+                                &GMPVideoEncodedFrame::Destroy),
+                   NS_DISPATCH_NORMAL);
+}
+
 bool
 GMPVideoEncoderParent::RecvEncoded(const GMPVideoEncodedFrameData& aEncodedFrame,
                                    const nsTArray<uint8_t>& aCodecSpecificInfo)
 {
   if (!mCallback) {
     return false;
   }
 
   auto f = new GMPVideoEncodedFrameImpl(aEncodedFrame, &mVideoHost);
+  nsTArray<uint8_t> *codecSpecificInfo = new nsTArray<uint8_t>;
+  codecSpecificInfo->AppendElements((uint8_t*)aCodecSpecificInfo.Elements(), aCodecSpecificInfo.Length());
+  nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
 
-  // Ignore any return code. It is OK for this to fail without killing the process.
-  mCallback->Encoded(f, aCodecSpecificInfo);
+  mEncodedThread->Dispatch(WrapRunnableNM(&EncodedCallback,
+                                          mCallback, f, codecSpecificInfo, thread),
+                           NS_DISPATCH_NORMAL);
 
-  // Return SHM to sender to recycle
-  //SendEncodedReturn(aEncodedFrame, aCodecSpecificInfo);
   return true;
 }
 
 bool
 GMPVideoEncoderParent::RecvError(const GMPErr& aError)
 {
   if (!mCallback) {
     return false;
--- a/content/media/gmp/GMPVideoEncoderParent.h
+++ b/content/media/gmp/GMPVideoEncoderParent.h
@@ -72,14 +72,15 @@ private:
   virtual bool AnswerNeedShmem(const uint32_t& aEncodedBufferSize,
                                Shmem* aMem) MOZ_OVERRIDE;
   virtual bool Recv__delete__() MOZ_OVERRIDE;
 
   bool mIsOpen;
   nsRefPtr<GMPParent> mPlugin;
   GMPVideoEncoderCallbackProxy* mCallback;
   GMPVideoHostImpl mVideoHost;
+  nsCOMPtr<nsIThread> mEncodedThread;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPVideoEncoderParent_h_
--- a/content/media/gmp/PGMP.ipdl
+++ b/content/media/gmp/PGMP.ipdl
@@ -2,33 +2,36 @@
 /* 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 protocol PGMPVideoDecoder;
 include protocol PGMPVideoEncoder;
 include protocol PCrashReporter;
 include protocol PGMPDecryptor;
+include protocol PGMPAudioDecoder;
 
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 
 namespace mozilla {
 namespace gmp {
 
 intr protocol PGMP
 {
+  manages PGMPAudioDecoder;
   manages PGMPDecryptor;
   manages PGMPVideoDecoder;
   manages PGMPVideoEncoder;
   manages PCrashReporter;
 
 parent:
   async PCrashReporter(NativeThreadId tid);
 
 child:
+  async PGMPAudioDecoder();
   async PGMPDecryptor();
   async PGMPVideoDecoder();
   async PGMPVideoEncoder();
 
   async CrashPluginNow();
 };
 
 } // namespace gmp
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/PGMPAudioDecoder.ipdl
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PGMP;
+include GMPTypes;
+
+using GMPCodecSpecificInfo from "gmp-audio-codec.h";
+using GMPErr from "gmp-errors.h";
+
+include "GMPMessageUtils.h";
+
+namespace mozilla {
+namespace gmp {
+
+async protocol PGMPAudioDecoder
+{
+  manager PGMP;
+child:
+  InitDecode(GMPAudioCodecData aCodecSettings);
+  Decode(GMPAudioEncodedSampleData aInput);
+  Reset();
+  Drain();
+  DecodingComplete();
+parent:
+  __delete__();
+  Decoded(GMPAudioDecodedSampleData aDecoded);
+  InputDataExhausted();
+  DrainComplete();
+  ResetComplete();
+  Error(GMPErr aErr);
+};
+
+} // namespace gmp
+} // namespace mozilla
--- a/content/media/gmp/moz.build
+++ b/content/media/gmp/moz.build
@@ -24,16 +24,20 @@ EXPORTS += [
     'gmp-api/gmp-video-codec.h',
     'gmp-api/gmp-video-decode.h',
     'gmp-api/gmp-video-encode.h',
     'gmp-api/gmp-video-frame-encoded.h',
     'gmp-api/gmp-video-frame-i420.h',
     'gmp-api/gmp-video-frame.h',
     'gmp-api/gmp-video-host.h',
     'gmp-api/gmp-video-plane.h',
+    'GMPAudioDecoderChild.h',
+    'GMPAudioDecoderParent.h',
+    'GMPAudioDecoderProxy.h',
+    'GMPAudioHost.h',
     'GMPCallbackBase.h',
     'GMPChild.h',
     'GMPDecryptorChild.h',
     'GMPDecryptorParent.h',
     'GMPDecryptorProxy.h',
     'GMPEncryptedBufferDataImpl.h',
     'GMPMessageUtils.h',
     'GMPParent.h',
@@ -50,16 +54,19 @@ EXPORTS += [
     'GMPVideoEncoderParent.h',
     'GMPVideoEncoderProxy.h',
     'GMPVideoHost.h',
     'GMPVideoi420FrameImpl.h',
     'GMPVideoPlaneImpl.h',
 ]
 
 UNIFIED_SOURCES += [
+    'GMPAudioDecoderChild.cpp',
+    'GMPAudioDecoderParent.cpp',
+    'GMPAudioHost.cpp',
     'GMPChild.cpp',
     'GMPDecryptorChild.cpp',
     'GMPDecryptorParent.cpp',
     'GMPEncryptedBufferDataImpl.cpp',
     'GMPParent.cpp',
     'GMPPlatform.cpp',
     'GMPProcessChild.cpp',
     'GMPProcessParent.cpp',
@@ -73,16 +80,17 @@ UNIFIED_SOURCES += [
     'GMPVideoHost.cpp',
     'GMPVideoi420FrameImpl.cpp',
     'GMPVideoPlaneImpl.cpp',
 ]
 
 IPDL_SOURCES += [
   'GMPTypes.ipdlh',
   'PGMP.ipdl',
+  'PGMPAudioDecoder.ipdl',
   'PGMPDecryptor.ipdl',
   'PGMPVideoDecoder.ipdl',
   'PGMPVideoEncoder.ipdl',
 ]
 
 if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
     NO_VISIBILITY_FLAGS = True
 
--- a/content/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/content/media/gmp/mozIGeckoMediaPluginService.idl
@@ -5,30 +5,32 @@
 
 #include "nsISupports.idl"
 #include "nsIThread.idl"
 #include "nsIPrincipal.idl"
 
 %{C++
 #include "nsTArray.h"
 #include "nsStringGlue.h"
+class GMPAudioDecoderProxy;
 class GMPDecryptorProxy;
 class GMPVideoDecoderProxy;
 class GMPVideoEncoderProxy;
 class GMPVideoHost;
 %}
 
 [ptr] native GMPVideoDecoderProxy(GMPVideoDecoderProxy);
 [ptr] native GMPVideoEncoderProxy(GMPVideoEncoderProxy);
 [ptr] native GMPVideoHost(GMPVideoHost);
 [ptr] native MessageLoop(MessageLoop);
 [ptr] native TagArray(nsTArray<nsCString>);
 [ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
+[ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
 
-[scriptable, uuid(b301ea8b-8a1e-4839-a13c-9dd32b2d684b)]
+[scriptable, uuid(6ea374fc-32ad-46f6-ae9d-80b668f4fd49)]
 interface mozIGeckoMediaPluginService : nsISupports
 {
   /**
    * The GMP thread. Callable from any thread.
    */
   readonly attribute nsIThread thread;
 
   /**
@@ -57,16 +59,23 @@ interface mozIGeckoMediaPluginService : 
    * other tags.
    * Callable only on GMP thread.
    */
   [noscript]
   GMPVideoEncoderProxy getGMPVideoEncoder(in TagArray tags,
 		                                      [optional] in AString origin,
 		                                      out GMPVideoHost outVideoHost);
 
+  // Returns an audio decoder that supports the specified tags.
+  // The array of tags should at least contain a codec tag, and optionally
+  // other tags such as for EME keysystem.
+  // Callable only on GMP thread.
+  GMPAudioDecoderProxy getGMPAudioDecoder(in TagArray tags,
+                                          [optional] in AString origin);
+
   // Returns a decryption session manager that supports the specified tags.
   // The array of tags should at least contain a key system tag, and optionally
   // other tags.
   // Callable only on GMP thread.
   GMPDecryptorProxy getGMPDecryptor(in TagArray tags, in AString origin);
 
   /**
    * Add a directory to scan for gecko media plugins.
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -649,16 +649,25 @@ AudioContext::MozAudioChannelType() cons
 }
 
 void
 AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
 {
   mDestination->SetMozAudioChannelType(aValue, aRv);
 }
 
+AudioChannel
+AudioContext::TestAudioChannelInAudioNodeStream()
+{
+  MediaStream* stream = mDestination->Stream();
+  MOZ_ASSERT(stream);
+
+  return stream->AudioChannelType();
+}
+
 size_t
 AudioContext::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   // AudioNodes are tracked separately because we do not want the AudioContext
   // to track all of the AudioNodes it creates, so we wouldn't be able to
   // traverse them from here.
 
   size_t amount = aMallocSizeOf(this);
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -219,16 +219,18 @@ public:
   void Mute() const;
   void Unmute() const;
 
   JSObject* GetGlobalJSObject() const;
 
   AudioChannel MozAudioChannelType() const;
   void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
 
+  AudioChannel TestAudioChannelInAudioNodeStream();
+
   void UpdateNodeCount(int32_t aDelta);
 
   double DOMTimeToStreamTime(double aTime) const
   {
     return aTime - ExtraCurrentTime();
   }
 
   IMPL_EVENT_HANDLER(mozinterruptbegin)
--- a/content/media/webaudio/test/test_mozaudiochannel.html
+++ b/content/media/webaudio/test/test_mozaudiochannel.html
@@ -45,35 +45,46 @@ function test_basic() {
 }
 
 function test_permission(aChannel) {
   var ac = new AudioContext();
   ok(ac, "AudioContext created");
 
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
+  var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
+  is(channel, "normal", "AudioNodeStream is using the correct default audio channel.");
+
   SpecialPowers.pushPermissions(
     [{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }],
     function() {
       ac.mozAudioChannelType = aChannel;
       is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
+
+      var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
+      is(channel, aChannel, "AudioNodeStream is using the correct new audio channel.");
+
       runTest();
     }
   );
 }
 
 function test_preferences(aChannel) {
   SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", aChannel ]]},
     function() {
       SpecialPowers.pushPermissions(
         [{ "type": "audio-channel-" + aChannel, "allow": false, "context": document }],
         function() {
           var ac = new AudioContext(aChannel);
           ok(ac, "AudioContext created");
           is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
+
+          var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
+          is(channel, aChannel, "AudioNodeStream is using the correct audio channel.");
+
           runTest();
         }
       );
     }
   );
 }
 
 function test_wrong_preferences() {
@@ -82,16 +93,31 @@ function test_wrong_preferences() {
       var ac = new AudioContext();
       ok(ac, "AudioContext created");
       is(ac.mozAudioChannelType, 'normal', "Default ac channel == 'normal'");
       runTest();
     }
   );
 }
 
+function test_testAudioChannelInAudioNodeStream() {
+  var ac = new AudioContext();
+  ok(ac, "AudioContext created");
+
+  var status = false;
+  try {
+    ac.testAudioChannelInAudioNodeStream();
+  } catch(e) {
+    status = true;
+  }
+
+  ok(status, "testAudioChannelInAudioNodeStream() should not exist in content.");
+  runTest();
+}
+
 var tests = [
   test_basic,
 
   function() { test_permission("content"); },
   function() { test_permission("notification"); },
   function() { test_permission("alarm"); },
   function() { test_permission("telephony"); },
   function() { test_permission("ringer"); },
@@ -100,16 +126,18 @@ var tests = [
   function() { test_preferences("content"); },
   function() { test_preferences("notification"); },
   function() { test_preferences("alarm"); },
   function() { test_preferences("telephony"); },
   function() { test_preferences("ringer"); },
   function() { test_preferences("publicnotification"); },
 
   test_wrong_preferences,
+
+  test_testAudioChannelInAudioNodeStream,
 ];
 
 function runTest() {
   if (!tests.length) {
     SimpleTest.finish();
     return;
   }
 
--- a/content/media/webrtc/MediaEngineWebRTC.cpp
+++ b/content/media/webrtc/MediaEngineWebRTC.cpp
@@ -376,41 +376,49 @@ MediaEngineWebRTC::EnumerateAudioDevices
 
 void
 MediaEngineWebRTC::Shutdown()
 {
   // This is likely paranoia
   MutexAutoLock lock(mMutex);
 
   // Clear callbacks before we go away since the engines may outlive us
+  mVideoSources.Clear();
+  mAudioSources.Clear();
   if (mVideoEngine) {
-    mVideoSources.Clear();
     mVideoEngine->SetTraceCallback(nullptr);
     webrtc::VideoEngine::Delete(mVideoEngine);
   }
 
   if (mScreenEngine) {
+    mScreenEngine->SetTraceCallback(nullptr);
     webrtc::VideoEngine::Delete(mScreenEngine);
   }
+  if (mWinEngine) {
+    mWinEngine->SetTraceCallback(nullptr);
+    webrtc::VideoEngine::Delete(mWinEngine);
+  }
   if (mBrowserEngine) {
+    mBrowserEngine->SetTraceCallback(nullptr);
     webrtc::VideoEngine::Delete(mBrowserEngine);
   }
   if (mAppEngine) {
+    mAppEngine->SetTraceCallback(nullptr);
     webrtc::VideoEngine::Delete(mAppEngine);
   }
 
   if (mVoiceEngine) {
-    mAudioSources.Clear();
     mVoiceEngine->SetTraceCallback(nullptr);
     webrtc::VoiceEngine::Delete(mVoiceEngine);
   }
 
   mVideoEngine = nullptr;
   mVoiceEngine = nullptr;
   mScreenEngine = nullptr;
+  mWinEngine = nullptr;
   mBrowserEngine = nullptr;
   mAppEngine = nullptr;
 
   if (mThread) {
     mThread->Shutdown();
     mThread = nullptr;
   }
 }
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1284,17 +1284,17 @@ nsXULElement::PreHandleEvent(EventChainP
          aVisitor.mEvent->message == NS_DRAGDROP_START ||
          aVisitor.mEvent->message == NS_DRAGDROP_GESTURE)) {
         // Don't propagate these events from native anonymous scrollbar.
         aVisitor.mCanHandle = true;
         aVisitor.mParentTarget = nullptr;
         return NS_OK;
     }
     if (aVisitor.mEvent->message == NS_XUL_COMMAND &&
-        aVisitor.mEvent->eventStructType == NS_INPUT_EVENT &&
+        aVisitor.mEvent->mClass == eInputEventClass &&
         aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this) &&
         tag != nsGkAtoms::command) {
         // Check that we really have an xul command event. That will be handled
         // in a special way.
         nsCOMPtr<nsIDOMXULCommandEvent> xulEvent =
             do_QueryInterface(aVisitor.mDOMEvent);
         // See if we have a command elt.  If so, we execute on the command
         // instead of on our content element.
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -7361,25 +7361,28 @@ nsDocShell::CreateAboutBlankContentViewe
     return NS_ERROR_FAILURE;
 
   AutoRestore<bool> creatingDocument(mCreatingDocument);
   mCreatingDocument = true;
 
   // mContentViewer->PermitUnload may release |this| docshell.
   nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
   
+  // Make sure timing is created.  But first record whether we had it
+  // already, so we don't clobber the timing for an in-progress load.
+  bool hadTiming = mTiming;
+  MaybeInitTiming();
   if (mContentViewer) {
     // We've got a content viewer already. Make sure the user
     // permits us to discard the current document and replace it
     // with about:blank. And also ensure we fire the unload events
     // in the current document.
 
-    // Make sure timing is created. Unload gets fired first for
+    // Unload gets fired first for
     // document loaded from the session history.
-    MaybeInitTiming();
     mTiming->NotifyBeforeUnload();
 
     bool okToUnload;
     rv = mContentViewer->PermitUnload(false, &okToUnload);
 
     if (NS_SUCCEEDED(rv) && !okToUnload) {
       // The user chose not to unload the page, interrupt the load.
       return NS_ERROR_FAILURE;
@@ -7454,16 +7457,22 @@ nsDocShell::CreateAboutBlankContentViewe
         rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
       }
     }
   }
 
   // The transient about:blank viewer doesn't have a session history entry.
   SetHistoryEntry(&mOSHE, nullptr);
 
+  // Clear out our mTiming like we would in EndPageLoad, if we didn't
+  // have one before entering this function.
+  if (!hadTiming) {
+    mTiming = nullptr;
+  }
+
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal *aPrincipal)
 {
     return CreateAboutBlankContentViewer(aPrincipal, nullptr);
 }
--- a/docshell/test/mochitest.ini
+++ b/docshell/test/mochitest.ini
@@ -93,14 +93,15 @@ skip-if = (buildapp == 'b2g' && toolkit 
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug691547.html]
 [test_bug694612.html]
 [test_bug703855.html]
 [test_bug713825.html]
 [test_bug728939.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug797909.html]
+[test_bug1045096.html]
 [test_framedhistoryframes.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #Bug 931116, b2g desktop specific, initial triage, and also bug 784321
 support-files = file_framedhistoryframes.html
 [test_pushState_after_document_open.html]
 [test_windowedhistoryframes.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
new file mode 100644
--- /dev/null
+++ b/docshell/test/test_bug1045096.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1045096
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1045096</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=1045096">Mozilla Bug 1045096</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+  <script type="application/javascript">
+
+  /** Test for Bug 1045096 **/
+  var i = document.createElement('iframe');
+  i.src = "javascript:false"; // This is required!
+  $("content").appendChild(i);
+  ok(i.contentWindow.performance, "Should have a performance object");
+  </script>
+</body>
+</html>
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -78,21 +78,22 @@ GetWindowFromGlobal(JSObject* aGlobal)
   }
   XPCWrappedNative* wrapper = XPCWrappedNative::Get(aGlobal);
   nsCOMPtr<nsPIDOMWindow> piWin = do_QueryWrappedNative(wrapper);
   MOZ_ASSERT(piWin);
   return static_cast<nsGlobalWindow*>(piWin.get());
 }
 
 bool
-WindowNamedPropertiesHandler::getOwnPropertyDescriptor(JSContext* aCx,
-                                                       JS::Handle<JSObject*> aProxy,
-                                                       JS::Handle<jsid> aId,
-                                                       JS::MutableHandle<JSPropertyDescriptor> aDesc)
-                                                       const
+WindowNamedPropertiesHandler::getOwnPropDescriptor(JSContext* aCx,
+                                                   JS::Handle<JSObject*> aProxy,
+                                                   JS::Handle<jsid> aId,
+                                                   bool /* unused */,
+                                                   JS::MutableHandle<JSPropertyDescriptor> aDesc)
+                                                   const
 {
   if (!JSID_IS_STRING(aId)) {
     // Nothing to do if we're resolving a non-string property.
     return true;
   }
 
   JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
   if (HasPropertyOnPrototype(aCx, aProxy, aId)) {
--- a/dom/base/WindowNamedPropertiesHandler.h
+++ b/dom/base/WindowNamedPropertiesHandler.h
@@ -23,20 +23,21 @@ public:
   preventExtensions(JSContext* aCx, JS::Handle<JSObject*> aProxy) const MOZ_OVERRIDE
   {
     // Throw a TypeError, per WebIDL.
     JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
                          JSMSG_CANT_CHANGE_EXTENSIBILITY);
     return false;
   }
   virtual bool
-  getOwnPropertyDescriptor(JSContext* aCx, JS::Handle<JSObject*> aProxy,
-                           JS::Handle<jsid> aId,
-                           JS::MutableHandle<JSPropertyDescriptor> aDesc)
-                           const MOZ_OVERRIDE;
+  getOwnPropDescriptor(JSContext* aCx, JS::Handle<JSObject*> aProxy,
+                       JS::Handle<jsid> aId,
+                       bool /* unused */,
+                       JS::MutableHandle<JSPropertyDescriptor> aDesc)
+                       const MOZ_OVERRIDE;
   virtual bool
   defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy,
                  JS::Handle<jsid> aId,
                  JS::MutableHandle<JSPropertyDescriptor> aDesc) const MOZ_OVERRIDE;
   virtual bool
   ownPropNames(JSContext* aCx, JS::Handle<JSObject*> aProxy, unsigned flags,
                JS::AutoIdVector& aProps) const MOZ_OVERRIDE;
   virtual bool
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -453,27 +453,16 @@ FindObjectClass(JSContext* cx, JSObject*
   do {
     obj = proto;
     js::GetObjectProto(cx, obj, &proto);
   } while (proto);
 
   sObjectClass = js::GetObjectJSClass(obj);
 }
 
-static inline JSString *
-IdToString(JSContext *cx, jsid id)
-{
-  if (JSID_IS_STRING(id))
-    return JSID_TO_STRING(id);
-  JS::Rooted<JS::Value> idval(cx);
-  if (!::JS_IdToValue(cx, id, &idval))
-    return nullptr;
-  return JS::ToString(cx, idval);
-}
-
 static inline nsresult
 WrapNative(JSContext *cx, nsISupports *native,
            nsWrapperCache *cache, const nsIID* aIID, JS::MutableHandle<JS::Value> vp,
            bool aAllowWrapping)
 {
   if (!native) {
     vp.setNull();
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -13489,17 +13489,17 @@ nsGlobalWindow::BeginWindowMove(Event& a
 #endif
 
   if (!widget) {
     return;
   }
 
   WidgetMouseEvent* mouseEvent =
     aMouseDownEvent.GetInternalNSEvent()->AsMouseEvent();
-  if (!mouseEvent || mouseEvent->eventStructType != NS_MOUSE_EVENT) {
+  if (!mouseEvent || mouseEvent->mClass != eMouseEventClass) {
     aError.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   aError = widget->BeginMoveDrag(mouseEvent);
 }
 
 //Note: This call will lock the cursor, it will not change as it moves.
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -49,20 +49,21 @@
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "prmem.h"
 #include "WrapperFactory.h"
 #include "nsGlobalWindow.h"
 #include "nsScriptNameSpaceManager.h"
 #include "StructuredCloneTags.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/dom/CryptoKey.h"
 #include "mozilla/dom/ErrorEvent.h"
+#include "mozilla/dom/ImageDataBinding.h"
 #include "mozilla/dom/ImageData.h"
-#include "mozilla/dom/CryptoKey.h"
-#include "mozilla/dom/ImageDataBinding.h"
+#include "mozilla/dom/StructuredClone.h"
 #include "mozilla/dom/SubtleCryptoBinding.h"
 #include "nsAXPCNativeCallContext.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 
 #include "nsJSPrincipals.h"
 
 #ifdef XP_MACOSX
 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
@@ -2806,35 +2807,17 @@ SetIncrementalCCPrefChangedCallback(cons
 JSObject*
 NS_DOMReadStructuredClone(JSContext* cx,
                           JSStructuredCloneReader* reader,
                           uint32_t tag,
                           uint32_t data,
                           void* closure)
 {
   if (tag == SCTAG_DOM_IMAGEDATA) {
-    // Read the information out of the stream.
-    uint32_t width, height;
-    JS::Rooted<JS::Value> dataArray(cx);
-    if (!JS_ReadUint32Pair(reader, &width, &height) ||
-        !JS_ReadTypedArray(reader, &dataArray)) {
-      return nullptr;
-    }
-    MOZ_ASSERT(dataArray.isObject());
-
-    // Protect the result from a moving GC in ~nsRefPtr.
-    JS::Rooted<JSObject*> result(cx);
-    {
-      // Construct the ImageData.
-      nsRefPtr<ImageData> imageData = new ImageData(width, height,
-                                                    dataArray.toObject());
-      // Wrap it in a JS::Value.
-      result = imageData->WrapObject(cx);
-    }
-    return result;
+    return ReadStructuredCloneImageData(cx, reader);
   } else if (tag == SCTAG_DOM_WEBCRYPTO_KEY) {
     nsIGlobalObject *global = xpc::GetNativeForGlobal(JS::CurrentGlobalOrNull(cx));
     if (!global) {
       return nullptr;
     }
 
     // Prevent the return value from being trashed by a GC during ~nsRefPtr.
     JS::Rooted<JSObject*> result(cx);
@@ -2858,27 +2841,17 @@ bool
 NS_DOMWriteStructuredClone(JSContext* cx,
                            JSStructuredCloneWriter* writer,
                            JS::Handle<JSObject*> obj,
                            void *closure)
 {
   // Handle ImageData cloning
   ImageData* imageData;
   if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, obj, imageData))) {
-    // Prepare the ImageData internals.
-    uint32_t width = imageData->Width();
-    uint32_t height = imageData->Height();
-    JS::Rooted<JSObject*> dataArray(cx, imageData->GetDataObject());
-
-    // Write the internals to the stream.
-    JSAutoCompartment ac(cx, dataArray);
-    JS::Rooted<JS::Value> arrayValue(cx, JS::ObjectValue(*dataArray));
-    return JS_WriteUint32Pair(writer, SCTAG_DOM_IMAGEDATA, 0) &&
-           JS_WriteUint32Pair(writer, width, height) &&
-           JS_WriteTypedArray(writer, arrayValue);
+    return WriteStructuredCloneImageData(cx, writer, imageData);
   }
 
   // Handle Key cloning
   CryptoKey* key;
   if (NS_SUCCEEDED(UNWRAP_OBJECT(CryptoKey, obj, key))) {
     return JS_WriteUint32Pair(writer, SCTAG_DOM_WEBCRYPTO_KEY, 0) &&
            key->WriteStructuredClone(writer);
   }
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -20,16 +20,17 @@
 #include "jsfriendapi.h"
 #include "js/OldDebugAPI.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsIDOMGlobalPropertyInitializer.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsIXPConnect.h"
+#include "nsUTF8Utils.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XPCQuickStubs.h"
 #include "XrayWrapper.h"
 #include "nsPrintfCString.h"
 #include "prprf.h"
 
 #include "mozilla/dom/ScriptSettings.h"
@@ -2156,16 +2157,46 @@ NonVoidByteStringToJsval(JSContext *cx, 
 
     if (!jsStr)
         return false;
 
     rval.setString(jsStr);
     return true;
 }
 
+
+template<typename T> static void
+NormalizeScalarValueStringInternal(JSContext* aCx, T& aString)
+{
+  char16_t* start = aString.BeginWriting();
+  // Must use const here because we can't pass char** to UTF16CharEnumerator as
+  // it expects const char**.  Unclear why this is illegal...
+  const char16_t* nextChar = start;
+  const char16_t* end = aString.Data() + aString.Length();
+  while (nextChar < end) {
+    uint32_t enumerated = UTF16CharEnumerator::NextChar(&nextChar, end);
+    if (enumerated == UCS2_REPLACEMENT_CHAR) {
+      int32_t lastCharIndex = (nextChar - start) - 1;
+      start[lastCharIndex] = static_cast<char16_t>(enumerated);
+    }
+  }
+}
+
+void
+NormalizeScalarValueString(JSContext* aCx, nsAString& aString)
+{
+  NormalizeScalarValueStringInternal(aCx, aString);
+}
+
+void
+NormalizeScalarValueString(JSContext* aCx, binding_detail::FakeString& aString)
+{
+  NormalizeScalarValueStringInternal(aCx, aString);
+}
+
 bool
 ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
                            bool nullable, nsACString& result)
 {
   JS::Rooted<JSString*> s(cx);
   if (v.isString()) {
     s = v.toString();
   } else {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1895,16 +1895,22 @@ ConvertJSValueToString(JSContext* cx, JS
     if (!s) {
       return false;
     }
   }
 
   return AssignJSString(cx, result, s);
 }
 
+void
+NormalizeScalarValueString(JSContext* aCx, nsAString& aString);
+
+void
+NormalizeScalarValueString(JSContext* aCx, binding_detail::FakeString& aString);
+
 bool
 ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
                            bool nullable, nsACString& result);
 
 template<typename T>
 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
 template<typename T>
 void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -51,18 +51,17 @@ def isTypeCopyConstructible(type):
             # because of rooting issues.
             (type.isInterface() and type.isGeckoInterface()))
 
 
 def idlTypeNeedsCycleCollection(type):
     type = type.unroll()  # Takes care of sequences and nullables
     if ((type.isPrimitive() and type.tag() in builtinNames) or
         type.isEnum() or
-        type.isDOMString() or
-        type.isByteString() or
+        type.isString() or
         type.isAny() or
         type.isObject() or
         type.isSpiderMonkeyInterface()):
         return False
     elif type.isCallback() or type.isGeckoInterface():
         return True
     elif type.isUnion():
         return any(idlTypeNeedsCycleCollection(t) for t in type.flatMemberTypes)
@@ -4562,17 +4561,17 @@ def getJSToNativeConversionInfo(type, de
             declArgs = None
         return JSToNativeConversionInfo(template,
                                         declType=declType,
                                         holderType=holderType,
                                         dealWithOptional=isOptional,
                                         declArgs=declArgs,
                                         holderArgs=holderArgs)
 
-    if type.isDOMString():
+    if type.isDOMString() or type.isScalarValueString():
         assert not isEnforceRange and not isClamp
 
         treatAs = {
             "Default": "eStringify",
             "EmptyString": "eEmpty",
             "Null": "eNull",
         }
         if type.nullable():
@@ -4580,21 +4579,27 @@ def getJSToNativeConversionInfo(type, de
             treatNullAs = "Null"
             # For nullable strings undefined also becomes a null string.
             undefinedBehavior = "eNull"
         else:
             undefinedBehavior = "eStringify"
         nullBehavior = treatAs[treatNullAs]
 
         def getConversionCode(varName):
+            normalizeCode = ""
+            if type.isScalarValueString():
+                normalizeCode = "NormalizeScalarValueString(cx, %s);\n" % varName
+
             conversionCode = (
                 "if (!ConvertJSValueToString(cx, ${val}, %s, %s, %s)) {\n"
                 "%s"
-                "}\n" % (nullBehavior, undefinedBehavior, varName,
-                         exceptionCodeIndented.define()))
+                "}\n"
+                "%s" % (nullBehavior, undefinedBehavior, varName,
+                        exceptionCodeIndented.define(), normalizeCode))
+
             if defaultValue is None:
                 return conversionCode
 
             if isinstance(defaultValue, IDLNullValue):
                 assert(type.nullable())
                 defaultCode = "%s.SetIsVoid(true)" % varName
             else:
                 defaultCode = handleDefaultStringValue(defaultValue,
@@ -5499,17 +5504,17 @@ def getWrapTemplateForType(type, descrip
             else:
                 getIID = ""
             wrap = "WrapObject(cx, %s, %s${jsvalHandle})" % (result, getIID)
             failed = None
 
         wrappingCode += wrapAndSetPtr(wrap, failed)
         return (wrappingCode, False)
 
-    if type.isDOMString():
+    if type.isDOMString() or type.isScalarValueString():
         if type.nullable():
             return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result), False)
         else:
             return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
 
     if type.isByteString():
         if type.nullable():
             return (wrapAndSetPtr("ByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
@@ -5777,17 +5782,17 @@ def getRetvalDeclarationForType(returnTy
     if returnType is None or returnType.isVoid():
         # Nothing to declare
         return None, None, None, None
     if returnType.isPrimitive() and returnType.tag() in builtinNames:
         result = CGGeneric(builtinNames[returnType.tag()])
         if returnType.nullable():
             result = CGTemplatedType("Nullable", result)
         return result, None, None, None
-    if returnType.isDOMString():
+    if returnType.isDOMString() or returnType.isScalarValueString():
         if isMember:
             return CGGeneric("nsString"), "ref", None, None
         return CGGeneric("DOMString"), "ref", None, None
     if returnType.isByteString():
         return CGGeneric("nsCString"), "ref", None, None
     if returnType.isEnum():
         result = CGGeneric(returnType.unroll().inner.identifier.name)
         if returnType.nullable():
@@ -8167,17 +8172,17 @@ def getUnionAccessorSignatureType(type, 
         else:
             typeName = CGWrapper(typeName, post="&")
         return typeName
 
     if type.isSpiderMonkeyInterface():
         typeName = CGGeneric(type.name)
         return CGWrapper(typeName, post=" const &")
 
-    if type.isDOMString():
+    if type.isDOMString() or type.isScalarValueString():
         return CGGeneric("const nsAString&")
 
     if type.isByteString():
         return CGGeneric("const nsCString&")
 
     if type.isEnum():
         return CGGeneric(type.inner.identifier.name)
 
@@ -9627,23 +9632,24 @@ class CGProxyUnwrap(CGAbstractMethod):
               obj = js::UncheckedUnwrap(obj);
             }
             MOZ_ASSERT(IsProxy(obj));
             return static_cast<${type}*>(js::GetProxyPrivate(obj).toPrivate());
             """,
             type=self.descriptor.nativeType)
 
 
-class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
+class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'proxy'),
                 Argument('JS::Handle<jsid>', 'id'),
+                Argument('bool', 'ignoreNamedProps'),
                 Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc')]
-        ClassMethod.__init__(self, "getOwnPropertyDescriptor", "bool", args,
+        ClassMethod.__init__(self, "getOwnPropDescriptor", "bool", args,
                              virtual=True, override=True, const=True)
         self.descriptor = descriptor
 
     def getBody(self):
         indexedGetter = self.descriptor.operations['IndexedGetter']
         indexedSetter = self.descriptor.operations['IndexedSetter']
 
         if self.descriptor.supportsIndexedProperties():
@@ -9704,16 +9710,17 @@ class CGDOMJSProxyHandler_getOwnProperty
             fillDescriptor = (
                 "FillPropertyDescriptor(desc, proxy, %s, %s);\n"
                 "return true;\n" % (readonly, enumerable))
             templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
                               'obj': 'proxy', 'successCode': fillDescriptor}
             condition = "!HasPropertyOnPrototype(cx, proxy, id)"
             if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
                 condition = "(!isXray || %s)" % condition
+            condition = "!ignoreNamedProps && " + condition
             if self.descriptor.supportsIndexedProperties():
                 condition = "!IsArrayIndex(index) && " + condition
             namedGet = (CGIfWrapper(CGProxyNamedGetter(self.descriptor, templateValues),
                                     condition).define() +
                         "\n")
         else:
             namedGet = ""
 
@@ -10362,17 +10369,17 @@ class CGDOMJSProxyHandler_getInstance(Cl
             return &instance;
             """)
 
 
 class CGDOMJSProxyHandler(CGClass):
     def __init__(self, descriptor):
         assert (descriptor.supportsIndexedProperties() or
                 descriptor.supportsNamedProperties())
-        methods = [CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor),
+        methods = [CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor),
                    CGDOMJSProxyHandler_defineProperty(descriptor),
                    ClassUsingDeclaration("mozilla::dom::DOMProxyHandler",
                                          "defineProperty"),
                    CGDOMJSProxyHandler_ownPropNames(descriptor),
                    CGDOMJSProxyHandler_hasOwn(descriptor),
                    CGDOMJSProxyHandler_get(descriptor),
                    CGDOMJSProxyHandler_className(descriptor),
                    CGDOMJSProxyHandler_finalizeInBackground(descriptor),
@@ -11793,17 +11800,17 @@ class CGNativeMember(ClassMethod):
             result = CGGeneric(builtinNames[type.tag()])
             defaultReturnArg = "0"
             if type.nullable():
                 result = CGTemplatedType("Nullable", result)
                 defaultReturnArg = ""
             return (result.define(),
                     "%s(%s)" % (result.define(), defaultReturnArg),
                     "return ${declName};\n")
-        if type.isDOMString():
+        if type.isDOMString() or type.isScalarValueString():
             if isMember:
                 # No need for a third element in the isMember case
                 return "nsString", None, None
             # Outparam
             return "void", "", "aRetVal = ${declName};\n"
         if type.isByteString():
             if isMember:
                 # No need for a third element in the isMember case
@@ -11913,17 +11920,17 @@ class CGNativeMember(ClassMethod):
             return "void", "", ""
 
         raise TypeError("Don't know how to declare return value for %s" %
                         type)
 
     def getArgs(self, returnType, argList):
         args = [self.getArg(arg) for arg in argList]
         # Now the outparams
-        if returnType.isDOMString():
+        if returnType.isDOMString() or returnType.isScalarValueString():
             args.append(Argument("nsString&", "aRetVal"))
         elif returnType.isByteString():
             args.append(Argument("nsCString&", "aRetVal"))
         elif returnType.isSequence():
             nullable = returnType.nullable()
             if nullable:
                 returnType = returnType.inner
             # And now the actual underlying type
@@ -12039,17 +12046,17 @@ class CGNativeMember(ClassMethod):
                     False, False)
 
         if type.isSpiderMonkeyInterface():
             if self.jsObjectsArePtr:
                 return "JSObject*", False, False
 
             return type.name, True, True
 
-        if type.isDOMString():
+        if type.isDOMString() or type.isScalarValueString():
             if isMember:
                 declType = "nsString"
             else:
                 declType = "nsAString"
             return declType, True, False
 
         if type.isByteString():
             declType = "nsCString"
@@ -13842,17 +13849,17 @@ class CGEventGetter(CGNativeMember):
             raise TypeError("Event code generators does not support static attributes")
         return CGNativeMember.getArgs(self, returnType, argList)
 
     def getMethodBody(self):
         type = self.member.type
         memberName = CGDictionary.makeMemberName(self.member.identifier.name)
         if (type.isPrimitive() and type.tag() in builtinNames) or type.isEnum() or type.isGeckoInterface():
             return "return " + memberName + ";\n"
-        if type.isDOMString() or type.isByteString():
+        if type.isDOMString() or type.isByteString() or type.isScalarValueString():
             return "aRetVal = " + memberName + ";\n"
         if type.isSpiderMonkeyInterface() or type.isObject():
             return fill(
                 """
                 if (${memberName}) {
                   JS::ExposeObjectToActiveJS(${memberName});
                 }
                 aRetVal.set(${memberName});
@@ -14216,17 +14223,17 @@ class CGEventClass(CGBindingImplClass):
         if type.isPrimitive() and type.tag() in builtinNames:
             nativeType = CGGeneric(builtinNames[type.tag()])
             if type.nullable():
                 nativeType = CGTemplatedType("Nullable", nativeType)
         elif type.isEnum():
             nativeType = CGGeneric(type.unroll().inner.identifier.name)
             if type.nullable():
                 nativeType = CGTemplatedType("Nullable", nativeType)
-        elif type.isDOMString():
+        elif type.isDOMString() or type.isScalarValueString():
             nativeType = CGGeneric("nsString")
         elif type.isByteString():
             nativeType = CGGeneric("nsCString")
         elif type.isGeckoInterface():
             iface = type.unroll().inner
             nativeType = self.descriptor.getDescriptor(
                 iface.identifier.name).nativeType
             # Now trim off unnecessary namespaces
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -179,16 +179,26 @@ BaseDOMProxyHandler::getPropertyDescript
     desc.object().set(nullptr);
     return true;
   }
 
   return JS_GetPropertyDescriptorById(cx, proto, id, desc);
 }
 
 bool
+BaseDOMProxyHandler::getOwnPropertyDescriptor(JSContext* cx,
+                                              JS::Handle<JSObject*> proxy,
+                                              JS::Handle<jsid> id,
+                                              MutableHandle<JSPropertyDescriptor> desc) const
+{
+  return getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ false,
+                              desc);
+}
+
+bool
 DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                                 MutableHandle<JSPropertyDescriptor> desc, bool* defined) const
 {
   if (desc.hasGetterObject() && desc.setter() == JS_StrictPropertyStub) {
     return JS_ReportErrorFlagsAndNumber(cx,
                                         JSREPORT_WARNING | JSREPORT_STRICT |
                                         JSREPORT_STRICT_MODE_ERROR,
                                         js_GetErrorMessage, nullptr,
@@ -216,17 +226,40 @@ DOMProxyHandler::set(JSContext *cx, Hand
              "Should not have a XrayWrapper here");
   bool done;
   if (!setCustom(cx, proxy, id, vp, &done)) {
     return false;
   }
   if (done) {
     return true;
   }
-  return mozilla::dom::BaseDOMProxyHandler::set(cx, proxy, receiver, id, strict, vp);
+
+  // Make sure to ignore our named properties when checking for own
+  // property descriptors for a set.
+  JS::Rooted<JSPropertyDescriptor> desc(cx);
+  if (!getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ true,
+                            &desc)) {
+    return false;
+  }
+  bool descIsOwn = desc.object() != nullptr;
+  if (!desc.object()) {
+    // Don't just use getPropertyDescriptor, unlike BaseProxyHandler::set,
+    // because that would call getOwnPropertyDescriptor on ourselves.  Instead,
+    // directly delegate to the proto, if any.
+    JS::Rooted<JSObject*> proto(cx);
+    if (!js::GetObjectProto(cx, proxy, &proto)) {
+      return false;
+    }
+    if (proto && !JS_GetPropertyDescriptorById(cx, proto, id, &desc)) {
+      return false;
+    }
+  }
+
+  return js::SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id,
+                                            &desc, descIsOwn, strict, vp);
 }
 
 bool
 DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
                          JS::Handle<jsid> id, bool* bp) const
 {
   JS::Rooted<JSObject*> expando(cx);
   if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -44,16 +44,19 @@ public:
 
   // Implementations of traps that can be implemented in terms of
   // fundamental traps.
   bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
                  JS::AutoIdVector& props) const MOZ_OVERRIDE;
   bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
                              JS::Handle<jsid> id,
                              JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+  bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
+                                JS::Handle<jsid> id,
+                                JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
 
   bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
              JS::Handle<JSObject*> callable) const MOZ_OVERRIDE;
   bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy,
                JS::Handle<jsid> id) const MOZ_OVERRIDE;
   virtual bool getOwnPropertyNames(JSContext* cx, JS::Handle<JSObject*> proxy,
                                    JS::AutoIdVector &props) const MOZ_OVERRIDE;
   // We override keys() and implement it directly instead of using the
@@ -65,16 +68,26 @@ public:
 
 protected:
   // Hook for subclasses to implement shared getOwnPropertyNames()/keys()
   // functionality.  The "flags" argument is either JSITER_OWNONLY (for keys())
   // or JSITER_OWNONLY | JSITER_HIDDEN (for getOwnPropertyNames()).
   virtual bool ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy,
                             unsigned flags,
                             JS::AutoIdVector& props) const = 0;
+
+  // Hook for subclasses to allow set() to ignore named props while other things
+  // that look at property descriptors see them.  This is intentionally not
+  // named getOwnPropertyDescriptor to avoid subclasses that override it hiding
+  // our public getOwnPropertyDescriptor.
+  virtual bool getOwnPropDescriptor(JSContext* cx,
+                                    JS::Handle<JSObject*> proxy,
+                                    JS::Handle<jsid> id,
+                                    bool ignoreNamedProps,
+                                    JS::MutableHandle<JSPropertyDescriptor> desc) const = 0;
 };
 
 class DOMProxyHandler : public BaseDOMProxyHandler
 {
 public:
   DOMProxyHandler()
     : BaseDOMProxyHandler(ProxyFamily())
   {
new file mode 100644
--- /dev/null
+++ b/dom/bindings/StructuredClone.cpp
@@ -0,0 +1,56 @@
+/* -*- 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 "mozilla/dom/StructuredClone.h"
+
+#include "js/StructuredClone.h"
+#include "mozilla/dom/ImageData.h"
+#include "mozilla/dom/StructuredCloneTags.h"
+
+namespace mozilla {
+namespace dom {
+
+JSObject*
+ReadStructuredCloneImageData(JSContext* aCx, JSStructuredCloneReader* aReader)
+{
+  // Read the information out of the stream.
+  uint32_t width, height;
+  JS::Rooted<JS::Value> dataArray(aCx);
+  if (!JS_ReadUint32Pair(aReader, &width, &height) ||
+      !JS_ReadTypedArray(aReader, &dataArray)) {
+    return nullptr;
+  }
+  MOZ_ASSERT(dataArray.isObject());
+
+  // Protect the result from a moving GC in ~nsRefPtr.
+  JS::Rooted<JSObject*> result(aCx);
+  {
+    // Construct the ImageData.
+    nsRefPtr<ImageData> imageData = new ImageData(width, height,
+                                                  dataArray.toObject());
+    // Wrap it in a JS::Value.
+    result = imageData->WrapObject(aCx);
+  }
+  return result;
+}
+
+bool
+WriteStructuredCloneImageData(JSContext* aCx, JSStructuredCloneWriter* aWriter,
+                              ImageData* aImageData)
+{
+  uint32_t width = aImageData->Width();
+  uint32_t height = aImageData->Height();
+  JS::Rooted<JSObject*> dataArray(aCx, aImageData->GetDataObject());
+
+  JSAutoCompartment ac(aCx, dataArray);
+  JS::Rooted<JS::Value> arrayValue(aCx, JS::ObjectValue(*dataArray));
+  return JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEDATA, 0) &&
+         JS_WriteUint32Pair(aWriter, width, height) &&
+         JS_WriteTypedArray(aWriter, arrayValue);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/bindings/StructuredClone.h
@@ -0,0 +1,25 @@
+/* -*- 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/. */
+
+class JSObject;
+struct JSContext;
+struct JSStructuredCloneReader;
+struct JSStructuredCloneWriter;
+
+namespace mozilla {
+namespace dom {
+
+class ImageData;
+
+JSObject*
+ReadStructuredCloneImageData(JSContext* aCx, JSStructuredCloneReader* aReader);
+
+bool
+WriteStructuredCloneImageData(JSContext* aCx, JSStructuredCloneWriter* aWriter,
+                              ImageData* aImageData);
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -25,16 +25,17 @@ EXPORTS.mozilla.dom += [
     'Exceptions.h',
     'JSSlots.h',
     'MozMap.h',
     'NonRefcountedDOMObject.h',
     'Nullable.h',
     'OwningNonNull.h',
     'PrimitiveConversions.h',
     'RootedDictionary.h',
+    'StructuredClone.h',
     'ToJSValue.h',
     'TypedArray.h',
     'UnionMember.h',
 ]
 
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
@@ -76,16 +77,20 @@ UNIFIED_SOURCES += [
     'CallbackInterface.cpp',
     'CallbackObject.cpp',
     'Date.cpp',
     'DOMJSProxyHandler.cpp',
     'Exceptions.cpp',
     'ToJSValue.cpp',
 ]
 
+SOURCES += [
+    'StructuredClone.cpp',
+]
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 if CONFIG['MOZ_AUDIO_CHANNEL_MANAGER']:
     LOCAL_INCLUDES += [
         '/dom/system/gonk',
     ]
 
 FINAL_LIBRARY = 'xul'
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1374,16 +1374,17 @@ class IDLType(IDLObject):
         'float',
         'unrestricted_double',
         # "double" last primitive type to match IDLBuiltinType
         'double',
         # Other types
         'any',
         'domstring',
         'bytestring',
+        'scalarvaluestring',
         'object',
         'date',
         'void',
         # Funny stuff
         'interface',
         'dictionary',
         'enum',
         'callback',
@@ -1426,16 +1427,19 @@ class IDLType(IDLObject):
         return False
 
     def isByteString(self):
         return False
 
     def isDOMString(self):
         return False
 
+    def isScalarValueString(self):
+        return False
+
     def isVoid(self):
         return self.name == "Void"
 
     def isSequence(self):
         return False
 
     def isMozMap(self):
         return False
@@ -1603,16 +1607,19 @@ class IDLNullableType(IDLType):
         return self.inner.isString()
 
     def isByteString(self):
         return self.inner.isByteString()
 
     def isDOMString(self):
         return self.inner.isDOMString()
 
+    def isScalarValueString(self):
+        return self.inner.isScalarValueString()
+
     def isFloat(self):
         return self.inner.isFloat()
 
     def isUnrestricted(self):
         return self.inner.isUnrestricted()
 
     def includesRestrictedFloat(self):
         return self.inner.includesRestrictedFloat()
@@ -1724,16 +1731,19 @@ class IDLSequenceType(IDLType):
         return False;
 
     def isByteString(self):
         return False
 
     def isDOMString(self):
         return False
 
+    def isScalarValueString(self):
+        return False
+
     def isVoid(self):
         return False
 
     def isSequence(self):
         return True
 
     def isArray(self):
         return False
@@ -1978,16 +1988,19 @@ class IDLArrayType(IDLType):
         return False
 
     def isByteString(self):
         return False
 
     def isDOMString(self):
         return False
 
+    def isScalarValueString(self):
+        return False
+
     def isVoid(self):
         return False
 
     def isSequence(self):
         assert not self.inner.isSequence()
         return False
 
     def isArray(self):
@@ -2073,16 +2086,19 @@ class IDLTypedefType(IDLType, IDLObjectW
         return self.inner.isString()
 
     def isByteString(self):
         return self.inner.isByteString()
 
     def isDOMString(self):
         return self.inner.isDOMString()
 
+    def isScalarValueString(self):
+        return self.inner.isScalarValueString()
+
     def isVoid(self):
         return self.inner.isVoid()
 
     def isSequence(self):
         return self.inner.isSequence()
 
     def isMozMap(self):
         return self.inner.isMozMap()
@@ -2171,16 +2187,19 @@ class IDLWrapperType(IDLType):
         return False
 
     def isByteString(self):
         return False
 
     def isDOMString(self):
         return False
 
+    def isScalarValueString(self):
+        return False
+
     def isVoid(self):
         return False
 
     def isSequence(self):
         return False
 
     def isArray(self):
         return False
@@ -2307,16 +2326,17 @@ class IDLBuiltinType(IDLType):
         'float',
         'unrestricted_double',
         # IMPORTANT: "double" must be the last primitive type listed
         'double',
         # Other types
         'any',
         'domstring',
         'bytestring',
+        'scalarvaluestring',
         'object',
         'date',
         'void',
         # Funny stuff
         'ArrayBuffer',
         'ArrayBufferView',
         'Int8Array',
         'Uint8Array',
@@ -2341,16 +2361,17 @@ class IDLBuiltinType(IDLType):
             Types.boolean: IDLType.Tags.bool,
             Types.unrestricted_float: IDLType.Tags.unrestricted_float,
             Types.float: IDLType.Tags.float,
             Types.unrestricted_double: IDLType.Tags.unrestricted_double,
             Types.double: IDLType.Tags.double,
             Types.any: IDLType.Tags.any,
             Types.domstring: IDLType.Tags.domstring,
             Types.bytestring: IDLType.Tags.bytestring,
+            Types.scalarvaluestring: IDLType.Tags.scalarvaluestring,
             Types.object: IDLType.Tags.object,
             Types.date: IDLType.Tags.date,
             Types.void: IDLType.Tags.void,
             Types.ArrayBuffer: IDLType.Tags.interface,
             Types.ArrayBufferView: IDLType.Tags.interface,
             Types.Int8Array: IDLType.Tags.interface,
             Types.Uint8Array: IDLType.Tags.interface,
             Types.Uint8ClampedArray: IDLType.Tags.interface,
@@ -2373,24 +2394,28 @@ class IDLBuiltinType(IDLType):
     def isBoolean(self):
         return self._typeTag == IDLBuiltinType.Types.boolean
 
     def isNumeric(self):
         return self.isPrimitive() and not self.isBoolean()
 
     def isString(self):
         return self._typeTag == IDLBuiltinType.Types.domstring or \
-               self._typeTag == IDLBuiltinType.Types.bytestring
+               self._typeTag == IDLBuiltinType.Types.bytestring or \
+               self._typeTag == IDLBuiltinType.Types.scalarvaluestring
 
     def isByteString(self):
         return self._typeTag == IDLBuiltinType.Types.bytestring
 
     def isDOMString(self):
         return self._typeTag == IDLBuiltinType.Types.domstring
 
+    def isScalarValueString(self):
+        return self._typeTag == IDLBuiltinType.Types.scalarvaluestring
+
     def isInteger(self):
         return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long
 
     def isArrayBuffer(self):
         return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
 
     def isArrayBufferView(self):
         return self._typeTag == IDLBuiltinType.Types.ArrayBufferView
@@ -2533,16 +2558,19 @@ BuiltinTypes = {
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Any",
                          IDLBuiltinType.Types.any),
       IDLBuiltinType.Types.domstring:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "String",
                          IDLBuiltinType.Types.domstring),
       IDLBuiltinType.Types.bytestring:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "ByteString",
                          IDLBuiltinType.Types.bytestring),
+      IDLBuiltinType.Types.scalarvaluestring:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "ScalarValueString",
+                         IDLBuiltinType.Types.scalarvaluestring),
       IDLBuiltinType.Types.object:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Object",
                          IDLBuiltinType.Types.object),
       IDLBuiltinType.Types.date:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Date",
                          IDLBuiltinType.Types.date),
       IDLBuiltinType.Types.void:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Void",
@@ -2667,16 +2695,23 @@ class IDLValue(IDLObject):
             return self
         elif self.type.isFloat() and type.isFloat():
             if (not type.isUnrestricted() and
                 (self.value == float("inf") or self.value == float("-inf") or
                  math.isnan(self.value))):
                 raise WebIDLError("Trying to convert unrestricted value %s to non-unrestricted"
                                   % self.value, [location]);
             return self
+        elif self.type.isString() and type.isScalarValueString():
+            # Allow ScalarValueStrings to use default value just like
+            # DOMString.  No coercion is required in this case as Codegen.py
+            # treats ScalarValueString just like DOMString, but with an
+            # extra normalization step.
+            assert self.type.isDOMString()
+            return self
         raise WebIDLError("Cannot coerce type %s to type %s." %
                           (self.type, type), [location])
 
     def _getDependentObjects(self):
         return set()
 
 class IDLNullValue(IDLObject):
     def __init__(self, location):
@@ -3829,16 +3864,17 @@ class Tokenizer(object):
         "deleter": "DELETER",
         "legacycaller": "LEGACYCALLER",
         "optional": "OPTIONAL",
         "...": "ELLIPSIS",
         "::": "SCOPE",
         "Date": "DATE",
         "DOMString": "DOMSTRING",
         "ByteString": "BYTESTRING",
+        "ScalarValueString": "SCALARVALUESTRING",
         "any": "ANY",
         "boolean": "BOOLEAN",
         "byte": "BYTE",
         "double": "DOUBLE",
         "float": "FLOAT",
         "long": "LONG",
         "object": "OBJECT",
         "octet": "OCTET",
@@ -4725,16 +4761,17 @@ class Parser(Tokenizer):
                   | SEMICOLON
                   | LT
                   | EQUALS
                   | GT
                   | QUESTIONMARK
                   | DATE
                   | DOMSTRING
                   | BYTESTRING
+                  | SCALARVALUESTRING
                   | ANY
                   | ATTRIBUTE
                   | BOOLEAN
                   | BYTE
                   | LEGACYCALLER
                   | CONST
                   | CREATOR
                   | DELETER
@@ -4997,16 +5034,22 @@ class Parser(Tokenizer):
         p[0] = IDLBuiltinType.Types.domstring
 
     def p_PrimitiveOrStringTypeBytestring(self, p):
         """
             PrimitiveOrStringType : BYTESTRING
         """
         p[0] = IDLBuiltinType.Types.bytestring
 
+    def p_PrimitiveOrStringTypeScalarValueString(self, p):
+        """
+            PrimitiveOrStringType : SCALARVALUESTRING
+        """
+        p[0] = IDLBuiltinType.Types.scalarvaluestring
+
     def p_UnsignedIntegerTypeUnsigned(self, p):
         """
             UnsignedIntegerType : UNSIGNED IntegerType
         """
         p[0] = p[2] + 1 # Adding one to a given signed integer type
                         # gets you the unsigned type.
 
     def p_UnsignedIntegerType(self, p):
--- a/dom/bindings/parser/tests/test_distinguishability.py
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -154,28 +154,29 @@ def WebIDLTest(parser, harness):
                  "boolean?", "DOMString", "ByteString", "Enum", "Enum2",
                  "Interface", "Interface?",
                  "AncestorInterface", "UnrelatedInterface",
                  "ImplementedInterface", "CallbackInterface",
                  "CallbackInterface?", "CallbackInterface2",
                  "object", "Callback", "Callback2", "optional Dict",
                  "optional Dict2", "sequence<long>", "sequence<short>",
                  "MozMap<object>", "MozMap<Dict>", "MozMap<long>",
-                 "long[]", "short[]", "Date", "Date?", "any" ]
+                 "long[]", "short[]", "Date", "Date?", "any",
+                 "ScalarValueString" ]
     # When we can parse Date and RegExp, we need to add them here.
 
     # Try to categorize things a bit to keep list lengths down
     def allBut(list1, list2):
         return [a for a in list1 if a not in list2 and a != "any"]
     numerics = [ "long", "short", "long?", "short?" ]
     booleans = [ "boolean", "boolean?" ]
     primitives = numerics + booleans
     nonNumerics = allBut(argTypes, numerics)
     nonBooleans = allBut(argTypes, booleans)
-    strings = [ "DOMString", "ByteString", "Enum", "Enum2" ]
+    strings = [ "DOMString", "ByteString", "Enum", "Enum2", "ScalarValueString" ]
     nonStrings = allBut(argTypes, strings)
     nonObjects = primitives + strings
     objects = allBut(argTypes, nonObjects )
     interfaces = [ "Interface", "Interface?", "AncestorInterface",
                    "UnrelatedInterface", "ImplementedInterface" ]
     nullables = ["long?", "short?", "boolean?", "Interface?",
                  "CallbackInterface?", "optional Dict", "optional Dict2",
                  "Date?", "any"]
@@ -199,16 +200,17 @@ def WebIDLTest(parser, harness):
     setDistinguishable("long", nonNumerics)
     setDistinguishable("short", nonNumerics)
     setDistinguishable("long?", allBut(nonNumerics, nullables))
     setDistinguishable("short?", allBut(nonNumerics, nullables))
     setDistinguishable("boolean", nonBooleans)
     setDistinguishable("boolean?", allBut(nonBooleans, nullables))
     setDistinguishable("DOMString", nonStrings)
     setDistinguishable("ByteString", nonStrings)
+    setDistinguishable("ScalarValueString", nonStrings)
     setDistinguishable("Enum", nonStrings)
     setDistinguishable("Enum2", nonStrings)
     setDistinguishable("Interface", notRelatedInterfaces)
     setDistinguishable("Interface?", allBut(notRelatedInterfaces, nullables))
     setDistinguishable("AncestorInterface", notRelatedInterfaces)
     setDistinguishable("UnrelatedInterface",
                        allBut(argTypes, ["object", "UnrelatedInterface"]))
     setDistinguishable("ImplementedInterface", notRelatedInterfaces)
new file mode 100644
--- /dev/null
+++ b/dom/bindings/parser/tests/test_scalarvaluestring.py
@@ -0,0 +1,36 @@
+# -*- coding: UTF-8 -*-
+
+import WebIDL
+
+def WebIDLTest(parser, harness):
+    parser.parse("""
+        interface TestScalarValueString {
+          attribute ScalarValueString svs;
+        };
+    """)
+
+    results = parser.finish();
+
+    harness.check(len(results), 1, "Should be one production")
+    harness.ok(isinstance(results[0], WebIDL.IDLInterface),
+               "Should be an IDLInterface")
+    iface = results[0]
+    harness.check(iface.identifier.QName(), "::TestScalarValueString",
+                  "Interface has the right QName")
+    harness.check(iface.identifier.name, "TestScalarValueString",
+                  "Interface has the right name")
+    harness.check(iface.parent, None, "Interface has no parent")
+
+    members = iface.members
+    harness.check(len(members), 1, "Should be one member")
+
+    attr = members[0]
+    harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Should be an IDLAttribute")
+    harness.check(attr.identifier.QName(), "::TestScalarValueString::svs",
+                  "Attr has correct QName")
+    harness.check(attr.identifier.name, "svs", "Attr has correct name")
+    harness.check(str(attr.type), "ScalarValueString",
+                  "Attr type is the correct name")
+    harness.ok(attr.type.isScalarValueString(), "Should be ScalarValueString type")
+    harness.ok(attr.type.isString(), "Should be String collective type")
+    harness.ok(not attr.type.isDOMString(), "Should be not be DOMString type")
--- a/dom/bindings/parser/tests/test_union.py
+++ b/dom/bindings/parser/tests/test_union.py
@@ -58,16 +58,17 @@ def WebIDLTest(parser, harness):
              "unsigned long",
              "long long",
              "unsigned long long",
              "boolean",
              "byte",
              "octet",
              "DOMString",
              "ByteString",
+             "ScalarValueString",
              #"sequence<float>",
              "object",
              "ArrayBuffer",
              #"Date",
              "TestInterface1",
              "TestInterface2"]
 
     testPre = """
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -461,24 +461,35 @@ public:
   // DOMString types
   void PassString(const nsAString&);
   void PassNullableString(const nsAString&);
   void PassOptionalString(const Optional<nsAString>&);
   void PassOptionalStringWithDefaultValue(const nsAString&);
   void PassOptionalNullableString(const Optional<nsAString>&);
   void PassOptionalNullableStringWithDefaultValue(const nsAString&);
   void PassVariadicString(const Sequence<nsString>&);
+  void ReceiveString(DOMString&);
 
   // ByteString types
   void PassByteString(const nsCString&);
   void PassNullableByteString(const nsCString&);
   void PassOptionalByteString(const Optional<nsCString>&);
   void PassOptionalNullableByteString(const Optional<nsCString>&);
   void PassVariadicByteString(const Sequence<nsCString>&);
 
+  // ScalarValueString types
+  void PassSVS(const nsAString&);
+  void PassNullableSVS(const nsAString&);
+  void PassOptionalSVS(const Optional<nsAString>&);
+  void PassOptionalSVSWithDefaultValue(const nsAString&);
+  void PassOptionalNullableSVS(const Optional<nsAString>&);
+  void PassOptionalNullableSVSWithDefaultValue(const nsAString&);
+  void PassVariadicSVS(const Sequence<nsString>&);
+  void ReceiveSVS(DOMString&);
+
   // Enumerated types
   void PassEnum(TestEnum);
   void PassNullableEnum(const Nullable<TestEnum>&);
   void PassOptionalEnum(const Optional<TestEnum>&);
   void PassEnumWithDefault(TestEnum);
   void PassOptionalNullableEnum(const Optional<Nullable<TestEnum> >&);
   void PassOptionalNullableEnumWithDefaultValue(const Nullable<TestEnum>&);
   void PassOptionalNullableEnumWithDefaultValue2(const Nullable<TestEnum>&);
@@ -586,16 +597,17 @@ public:
   void PassUnion20(JSContext*, const ObjectSequenceOrLong&);
   void PassUnion21(const LongMozMapOrLong&);
   void PassUnion22(JSContext*, const ObjectMozMapOrLong&);
   void PassUnionWithCallback(const EventHandlerNonNullOrNullOrLong& arg);
   void PassUnionWithByteString(const ByteStringOrLong&);
   void PassUnionWithMozMap(const StringMozMapOrString&);
   void PassUnionWithMozMapAndSequence(const StringMozMapOrStringSequence&);
   void PassUnionWithSequenceAndMozMap(const StringSequenceOrStringMozMap&);
+  void PassUnionWithSVS(const ScalarValueStringOrLong&);
 #endif
   void PassNullableUnion(JSContext*, const Nullable<ObjectOrLong>&);
   void PassOptionalUnion(JSContext*, const Optional<ObjectOrLong>&);
   void PassOptionalNullableUnion(JSContext*, const Optional<Nullable<ObjectOrLong> >&);
   void PassOptionalNullableUnionWithDefaultValue(JSContext*, const Nullable<ObjectOrLong>&);
   //void PassUnionWithInterfaces(const TestInterfaceOrTestExternalInterface& arg);
   //void PassUnionWithInterfacesAndNullable(const TestInterfaceOrNullOrTestExternalInterface& arg);
   void PassUnionWithArrayBuffer(const ArrayBufferOrLong&);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -418,24 +418,35 @@ interface TestInterface {
   // DOMString types
   void passString(DOMString arg);
   void passNullableString(DOMString? arg);
   void passOptionalString(optional DOMString arg);
   void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
   void passOptionalNullableString(optional DOMString? arg);
   void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
   void passVariadicString(DOMString... arg);
+  DOMString receiveString();
 
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
   void passOptionalNullableByteString(optional ByteString? arg);
   void passVariadicByteString(ByteString... arg);
 
+  // ScalarValueString types
+  void passSVS(ScalarValueString arg);
+  void passNullableSVS(ScalarValueString? arg);
+  void passOptionalSVS(optional ScalarValueString arg);
+  void passOptionalSVSWithDefaultValue(optional ScalarValueString arg = "abc");
+  void passOptionalNullableSVS(optional ScalarValueString? arg);
+  void passOptionalNullableSVSWithDefaultValue(optional ScalarValueString? arg = null);
+  void passVariadicSVS(ScalarValueString... arg);
+  ScalarValueString receiveSVS();
+
   // Enumerated types
   void passEnum(TestEnum arg);
   void passNullableEnum(TestEnum? arg);
   void passOptionalEnum(optional TestEnum arg);
   void passEnumWithDefault(optional TestEnum arg = "a");
   void passOptionalNullableEnum(optional TestEnum? arg);
   void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
   void passOptionalNullableEnumWithDefaultValue2(optional TestEnum? arg = "a");
@@ -528,16 +539,17 @@ interface TestInterface {
   void passUnion20(optional (sequence<object> or long) arg = []);
   void passUnion21((MozMap<long> or long) arg);
   void passUnion22((MozMap<object> or long) arg);
   void passUnionWithCallback((EventHandler or long) arg);
   void passUnionWithByteString((ByteString or long) arg);
   void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
   void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
   void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
+  void passUnionWithSVS((ScalarValueString or long) arg);
 #endif
   void passUnionWithNullable((object? or long) arg);
   void passNullableUnion((object or long)? arg);
   void passOptionalUnion(optional (object or long) arg);
   void passOptionalNullableUnion(optional (object or long)? arg);
   void passOptionalNullableUnionWithDefaultValue(optional (object or long)? arg = null);
   //void passUnionWithInterfaces((TestInterface or TestExternalInterface) arg);
   //void passUnionWithInterfacesAndNullable((TestInterface? or TestExternalInterface) arg);
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -320,16 +320,26 @@ interface TestExampleInterface {
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
   void passOptionalNullableByteString(optional ByteString? arg);
   void passVariadicByteString(ByteString... arg);
   void passUnionByteString((ByteString or long) arg);
 
+  // ScalarValueString types
+  void passSVS(ScalarValueString arg);
+  void passNullableSVS(ScalarValueString? arg);
+  void passOptionalSVS(optional ScalarValueString arg);
+  void passOptionalSVSWithDefaultValue(optional ScalarValueString arg = "abc");
+  void passOptionalNullableSVS(optional ScalarValueString? arg);
+  void passOptionalNullableSVSWithDefaultValue(optional ScalarValueString? arg = null);
+  void passVariadicSVS(ScalarValueString... arg);
+  ScalarValueString receiveSVS();
+
   // Enumerated types
   void passEnum(TestEnum arg);
   void passNullableEnum(TestEnum? arg);
   void passOptionalEnum(optional TestEnum arg);
   void passEnumWithDefault(optional TestEnum arg = "a");
   void passOptionalNullableEnum(optional TestEnum? arg);
   void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
   void passOptionalNullableEnumWithDefaultValue2(optional TestEnum? arg = "a");
@@ -416,19 +426,21 @@ interface TestExampleInterface {
   void passUnion16(optional (sequence<long> or long) arg);
   void passUnion17(optional (sequence<long>? or long) arg = 5);
   void passUnion18((sequence<object> or long) arg);
   void passUnion19(optional (sequence<object> or long) arg);
   void passUnion20(optional (sequence<object> or long) arg = []);
   void passUnion21((MozMap<long> or long) arg);
   void passUnion22((MozMap<object> or long) arg);
   void passUnionWithCallback((EventHandler or long) arg);
+  void passUnionWithByteString((ByteString or long) arg);
   void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
   void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
   void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
+  void passUnionWithSVS((ScalarValueString or long) arg);
 #endif
   void passUnionWithNullable((object? or long) arg);
   void passNullableUnion((object or long)? arg);
   void passOptionalUnion(optional (object or long) arg);
   void passOptionalNullableUnion(optional (object or long)? arg);
   void passOptionalNullableUnionWithDefaultValue(optional (object or long)? arg = null);
   //void passUnionWithInterfaces((TestInterface or TestExternalInterface) arg);
   //void passUnionWithInterfacesAndNullable((TestInterface? or TestExternalInterface) arg);
--- a/dom/bindings/test/TestInterfaceJS.js
+++ b/dom/bindings/test/TestInterfaceJS.js
@@ -40,12 +40,14 @@ TestInterfaceJS.prototype = {
   get objectArg() { return this._objectArg; },
   get anyAttr() { return this._anyAttr; },
   set anyAttr(val) { checkGlobal(val); this._anyAttr = val; },
   get objectAttr() { return this._objectAttr; },
   set objectAttr(val) { checkGlobal(val); this._objectAttr = val; },
   pingPongAny: function(any) { checkGlobal(any); return any; },
   pingPongObject: function(obj) { checkGlobal(obj); return obj; },
 
-  getCallerPrincipal: function() { return Cu.getWebIDLCallerPrincipal().origin; }
+  getCallerPrincipal: function() { return Cu.getWebIDLCallerPrincipal().origin; },
+
+  convertSVS: function(svs) { return svs; }
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS])
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -343,16 +343,26 @@ interface TestJSImplInterface {
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
   void passOptionalNullableByteString(optional ByteString? arg);
   void passVariadicByteString(ByteString... arg);
   void PassUnionByteString((ByteString or long) arg);
 
+  // ScalarValueString types
+  void passSVS(ScalarValueString arg);
+  void passNullableSVS(ScalarValueString? arg);
+  void passOptionalSVS(optional ScalarValueString arg);
+  void passOptionalSVSWithDefaultValue(optional ScalarValueString arg = "abc");
+  void passOptionalNullableSVS(optional ScalarValueString? arg);
+  void passOptionalNullableSVSWithDefaultValue(optional ScalarValueString? arg = null);
+  void passVariadicSVS(ScalarValueString... arg);
+  ScalarValueString receiveSVS();
+
   // Enumerated types
   void passEnum(MyTestEnum arg);
   void passNullableEnum(MyTestEnum? arg);
   void passOptionalEnum(optional MyTestEnum arg);
   void passEnumWithDefault(optional MyTestEnum arg = "a");
   void passOptionalNullableEnum(optional MyTestEnum? arg);
   void passOptionalNullableEnumWithDefaultValue(optional MyTestEnum? arg = null);
   void passOptionalNullableEnumWithDefaultValue2(optional MyTestEnum? arg = "a");
@@ -440,19 +450,21 @@ interface TestJSImplInterface {
   void passUnion16(optional (sequence<long> or long) arg);
   void passUnion17(optional (sequence<long>? or long) arg = 5);
   void passUnion18((sequence<object> or long) arg);
   void passUnion19(optional (sequence<object> or long) arg);
   void passUnion20(optional (sequence<object> or long) arg = []);
   void passUnion21((MozMap<long> or long) arg);
   void passUnion22((MozMap<object> or long) arg);
   void passUnionWithCallback((EventHandler or long) arg);
+  void passUnionWithByteString((ByteString or long) arg);
   void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
   void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
   void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
+  void passUnionWithSVS((ScalarValueString or long) arg);
 #endif
   void passUnionWithNullable((object? or long) arg);
   void passNullableUnion((object or long)? arg);
   void passOptionalUnion(optional (object or long) arg);
   void passOptionalNullableUnion(optional (object or long)? arg);
   void passOptionalNullableUnionWithDefaultValue(optional (object or long)? arg = null);
   //void passUnionWithInterfaces((TestJSImplInterface or TestExternalInterface) arg);
   //void passUnionWithInterfacesAndNullable((TestJSImplInterface? or TestExternalInterface) arg);
--- a/dom/bindings/test/mochitest.ini
+++ b/dom/bindings/test/mochitest.ini
@@ -35,12 +35,15 @@ skip-if = true
 [test_exceptions_from_jsimplemented.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure; bug 926547
 [test_lenientThis.html]
 [test_lookupGetter.html]
 [test_namedNoIndexed.html]
 [test_named_getter_enumerability.html]
 [test_Object.prototype_props.html]
 [test_queryInterface.html]
+[test_scalarvaluestring.html]
+skip-if = debug == false
 [test_sequence_wrapping.html]
+[test_setWithNamedGetterNoNamedSetter.html]
 [test_throwing_method_noDCE.html]
 [test_treat_non_object_as_null.html]
 [test_traceProtos.html]
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_scalarvaluestring.html
@@ -0,0 +1,41 @@
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test ScalarValueString</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() {
+  var testInterfaceJS = new TestInterfaceJS();
+  ok(testInterfaceJS, "got a TestInterfaceJS object");
+  // For expected values, see algorithm definition here:
+  //  http://heycam.github.io/webidl/#dfn-obtain-unicode
+  var testList = [
+    { string:   "foo",
+      expected: "foo" },
+    { string:   "This is U+2070E: \ud841\udf0e",
+      expected: "This is U+2070E: \ud841\udf0e" },
+    { string:   "Missing low surrogate: \ud841",
+      expected: "Missing low surrogate: \ufffd" },
+    { string:   "Missing low surrogate with trailer: \ud841!!",
+      expected: "Missing low surrogate with trailer: \ufffd!!" },
+    { string:   "Missing high surrogate: \udf0e",
+      expected: "Missing high surrogate: \ufffd" },
+    { string:   "Missing high surrogate with trailer: \udf0e!!",
+      expected: "Missing high surrogate with trailer: \ufffd!!" },
+    { string:   "U+2070E after malformed: \udf0e\ud841\udf0e",
+      expected: "U+2070E after malformed: \ufffd\ud841\udf0e" }
+  ];
+  testList.forEach(function(test) {
+    is(testInterfaceJS.convertSVS(test.string), test.expected, "Convert '" + test.string + "'");
+  });
+  SimpleTest.finish();
+});
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_setWithNamedGetterNoNamedSetter.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1043690
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1043690</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=1043690">Mozilla Bug 1043690</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<form>
+  <input name="action">
+</form>
+</div>
+  <script type="application/javascript">
+
+  /** Test for Bug 1043690 **/
+  var f = document.querySelector("form");
+  var i = document.querySelector("input");
+  ise(f.getAttribute("action"), null, "Should have no action attribute");
+  ise(f.action, i, "form.action should be the input");
+  f.action = "http://example.org";
+  ise(f.getAttribute("action"), "http://example.org",
+      "Should have an action attribute now");
+  ise(f.action, i, "form.action should still be the input");
+  i.remove();
+  ise(f.action, "http://example.org/",
+      "form.action should no longer be shadowed");
+
+
+  </script>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -4,16 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CanvasRenderingContext2D.h"
 
 #include "nsXULElement.h"
 
 #include "nsIServiceManager.h"
 #include "nsMathUtils.h"
+#include "SVGPreserveAspectRatio.h"
+#include "SVGImageContext.h"
 
 #include "nsContentUtils.h"
 
 #include "nsIDocument.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "nsSVGEffects.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
@@ -3427,28 +3429,29 @@ CanvasRenderingContext2D::DrawImage(cons
     AdjustedTarget(this, bounds.IsEmpty() ? nullptr : &bounds)->
       DrawSurface(srcSurf,
                   mgfx::Rect(dx, dy, dw, dh),
                   mgfx::Rect(sx, sy, sw, sh),
                   DrawSurfaceOptions(filter),
                   DrawOptions(CurrentState().globalAlpha, UsedOperation()));
   } else {
     DrawDirectlyToCanvas(drawInfo, &bounds, dx, dy, dw, dh,
-                         sx, sy, sw, sh, imgSize);
+                         sx, sy, sw, sh, imgSize, CurrentState().globalAlpha);
   }
 
   RedrawUser(gfxRect(dx, dy, dw, dh));
 }
 
 void
 CanvasRenderingContext2D::DrawDirectlyToCanvas(
                           const nsLayoutUtils::DirectDrawInfo& image,
                           mgfx::Rect* bounds, double dx, double dy,
                           double dw, double dh, double sx, double sy,
-                          double sw, double sh, gfxIntSize imgSize)
+                          double sw, double sh, gfxIntSize imgSize,
+                          gfxFloat opacity)
 {
   gfxMatrix contextMatrix;
 
   AdjustedTarget tempTarget(this, bounds->IsEmpty() ? nullptr: bounds);
 
   // get any already existing transforms on the context. Include transformations used for context shadow
   if (tempTarget) {
     Matrix matrix = tempTarget->GetTransform();
@@ -3464,22 +3467,24 @@ CanvasRenderingContext2D::DrawDirectlyTo
   transformMatrix.Translate(gfxPoint(-dx, -dy));
 
   nsRefPtr<gfxContext> context = new gfxContext(tempTarget);
   context->SetMatrix(contextMatrix);
 
   // FLAG_CLAMP is added for increased performance
   uint32_t modifiedFlags = image.mDrawingFlags | imgIContainer::FLAG_CLAMP;
 
+  SVGImageContext svgContext(SVGPreserveAspectRatio(), opacity);
+
   nsresult rv = image.mImgContainer->
     Draw(context, GraphicsFilter::FILTER_GOOD, transformMatrix,
          gfxRect(gfxPoint(dx, dy), gfxIntSize(dw, dh)),
          nsIntRect(nsIntPoint(0, 0), gfxIntSize(imgSize.width, imgSize.height)),
-         gfxIntSize(imgSize.width, imgSize.height), nullptr, image.mWhichFrame,
-         modifiedFlags);
+         gfxIntSize(imgSize.width, imgSize.height),
+         &svgContext, image.mWhichFrame, modifiedFlags);
 
   NS_ENSURE_SUCCESS_VOID(rv);
 }
 
 static bool
 IsStandardCompositeOp(CompositionOp op)
 {
     return (op == CompositionOp::OP_SOURCE ||
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -662,17 +662,18 @@ protected:
   void DrawImage(const HTMLImageOrCanvasOrVideoElement &imgElt,
                  double sx, double sy, double sw, double sh,
                  double dx, double dy, double dw, double dh,
                  uint8_t optional_argc, mozilla::ErrorResult& error);
 
   void DrawDirectlyToCanvas(const nsLayoutUtils::DirectDrawInfo& image,
                             mozilla::gfx::Rect* bounds, double dx, double dy,
                             double dw, double dh, double sx, double sy,
-                            double sw, double sh, gfxIntSize imgSize);
+                            double sw, double sh, gfxIntSize imgSize,
+                            gfxFloat opacity);
 
   nsString& GetFont()
   {
     /* will initilize the value if not set, else does nothing */
     GetCurrentFontStyle();
 
     return CurrentState().font;
   }
--- a/dom/canvas/WebGLTexelConversions.h
+++ b/dom/canvas/WebGLTexelConversions.h
@@ -57,63 +57,84 @@ packToFloat16(float v)
         float f32Value;
         uint32_t f32Bits;
     };
 
     f32Value = v;
 
     // pull the sign from v into f16bits
     uint16_t f16Bits = uint16_t(f32Bits >> 16) & 0x8000;
+    const uint32_t mantissa = f32Bits & 0x7FFFFF;
+    const uint32_t exp = (f32Bits >> 23) & 0xFF;
 
-    // handle +/- 0
-    if ((f32Bits & 0x7FFFFFFF) == 0x00000000) {
-        return f16Bits;
-    }
-
-    // handle NaN
-    if (f32Value != f32Value) {
-        return f16Bits | kFloat16Value_NaN;
+    // Adapted from: OpenGL ES 2.0 Programming Guide Appx.
+    // Converting Float to Half-Float
+    // 143 = 255 - 127 + 15
+    //     = sp_max - sp_bias + hp_bias
+    if (exp >= 143) {
+        if (mantissa && exp == 0xFF) {
+            // Single precision was NaN
+            return f16Bits | kFloat16Value_NaN;
+        } else {
+            // Outside range, store as infinity
+            return f16Bits | kFloat16Value_Infinity;
+        }
     }
 
-    int32_t exp = int32_t(f32Bits >> 23) - 127;
-
-    // too small, we clamp it to -0 or +0
-    if (exp < -14) {
-        return f16Bits;
+    // too small, try to make a denormalized number
+    // 112 = 255 - 127 - (15 + 1)
+    //     = sp_max - sp_bias - (hp_bias + 1)
+    if (exp <= 112) {
+        return f16Bits | uint16_t(mantissa >> (14 + 112 - exp));
     }
 
-    // too big, we clamp it to -inf/+inf
-    if (exp > 15) {
-        return f16Bits | kFloat16Value_Infinity;
-    }
-
-    f16Bits |= uint16_t(exp + 15) << 10;
-    f16Bits |= uint16_t(f32Bits >> 13) & 0x03FF;
+    f16Bits |= uint16_t(exp - 112) << 10;
+    f16Bits |= uint16_t(mantissa >> 13) & 0x03FF;
 
     return f16Bits;
 }
 
 MOZ_ALWAYS_INLINE float
 unpackFromFloat16(uint16_t v)
 {
-    union
-    {
+    union {
         float f32Value;
         uint32_t f32Bits;
     };
 
     // grab sign bit
     f32Bits = uint32_t(v & 0x8000) << 16;
+    uint16_t exp = (v >> 10) & 0x001F;
+    uint16_t mantissa = v & 0x03FF;
 
-    if ((v & 0x7FFF) == 0x0000) {
-        // +0 or -0
+    if (exp) {
+        // Handle denormalized numbers
+        // Adapted from: OpenGL ES 2.0 Programming Guide Appx.
+        // Converting Float to Half-Float
+        if (mantissa) {
+            exp = 112; // See packToFloat16
+            mantissa <<= 1;
+            // For every leading zero, decrement the exponent
+            // and shift the mantissa to the left
+            while ((mantissa & (1 << 10)) == 0) {
+                mantissa <<= 1;
+                --exp;
+            }
+            mantissa &= 0x03FF;
+
+            f32Bits |= (exp << 23) | (mantissa << 13);
+
+            // Denormalized number
+            return f32Value;
+        }
+
+        // +/- zero
         return f32Value;
     }
 
-    uint16_t exp = (v >> 10) & 0x001F;
     if (exp == 0x001F) {
         if (v & 0x03FF) {
             // this is a NaN
             f32Bits |= 0x7FFFFFFF;
         } else {
             // this is -inf or +inf
             f32Bits |= 0x7F800000;
         }
--- a/dom/datastore/DataStoreCallbacks.h
+++ b/dom/datastore/DataStoreCallbacks.h
@@ -15,17 +15,23 @@ namespace dom {
 class DataStoreDB;
 
 class DataStoreDBCallback
 {
 public:
   NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
   NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
 
-  virtual void Run(DataStoreDB* aDb, bool aSuccess) = 0;
+  enum RunStatus {
+    Success,
+    CreatedSchema,
+    Error
+  };
+
+  virtual void Run(DataStoreDB* aDb, RunStatus aStatus) = 0;
 
 protected:
   virtual ~DataStoreDBCallback()
   {
   }
 };
 
 class DataStoreRevisionCallback
--- a/dom/datastore/DataStoreDB.cpp
+++ b/dom/datastore/DataStoreDB.cpp
@@ -73,16 +73,17 @@ private:
 };
 
 NS_IMPL_ISUPPORTS(VersionChangeListener, nsIDOMEventListener)
 
 NS_IMPL_ISUPPORTS(DataStoreDB, nsIDOMEventListener)
 
 DataStoreDB::DataStoreDB(const nsAString& aManifestURL, const nsAString& aName)
   : mState(Inactive)
+  , mCreatedSchema(false)
 {
   mDatabaseName.Assign(aName);
   mDatabaseName.Append('|');
   mDatabaseName.Append(aManifestURL);
 }
 
 DataStoreDB::~DataStoreDB()
 {
@@ -140,45 +141,60 @@ DataStoreDB::HandleEvent(nsIDOMEvent* aE
   }
 
   if (type.EqualsASCII("success")) {
     RemoveEventListeners();
     mState = Inactive;
 
     rv = DatabaseOpened();
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      mCallback->Run(this, false);
+      mCallback->Run(this, DataStoreDBCallback::Error);
     } else {
-      mCallback->Run(this, true);
+      mCallback->Run(this, mCreatedSchema
+                      ? DataStoreDBCallback::CreatedSchema :
+                        DataStoreDBCallback::Success);
     }
 
     mRequest = nullptr;
     return NS_OK;
   }
 
   if (type.EqualsASCII("upgradeneeded")) {
-    return UpgradeSchema();
+    return UpgradeSchema(aEvent);
   }
 
   if (type.EqualsASCII("error") || type.EqualsASCII("blocked")) {
     RemoveEventListeners();
     mState = Inactive;
-    mCallback->Run(this, false);
+    mCallback->Run(this, DataStoreDBCallback::Error);
     mRequest = nullptr;
     return NS_OK;
   }
 
   MOZ_CRASH("This should not happen");
 }
 
 nsresult
-DataStoreDB::UpgradeSchema()
+DataStoreDB::UpgradeSchema(nsIDOMEvent* aEvent)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  // This DB has been just created and we have to inform the callback about
+  // this.
+  mCreatedSchema = true;
+
+#ifdef DEBUG
+  nsCOMPtr<IDBVersionChangeEvent> event = do_QueryInterface(aEvent);
+  MOZ_ASSERT(event);
+
+  Nullable<uint64_t> version = event->GetNewVersion();
+  MOZ_ASSERT(!version.IsNull());
+  MOZ_ASSERT(version.Value() == DATASTOREDB_VERSION);
+#endif
+
   AutoSafeJSContext cx;
 
   ErrorResult error;
   JS::Rooted<JS::Value> result(cx);
   mRequest->GetResult(&result, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.ErrorCode();
   }
--- a/dom/datastore/DataStoreDB.h
+++ b/dom/datastore/DataStoreDB.h
@@ -45,17 +45,17 @@ public:
   // nsIDOMEventListener
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
 
 private:
   ~DataStoreDB();
 
   nsresult CreateFactoryIfNeeded();
 
-  nsresult UpgradeSchema();
+  nsresult UpgradeSchema(nsIDOMEvent* aEvent);
 
   nsresult DatabaseOpened();
 
   nsresult AddEventListeners();
 
   nsresult RemoveEventListeners();
 
   nsString mDatabaseName;
@@ -70,14 +70,15 @@ private:
   // Internal state to avoid strange use of this class.
   enum StateType {
     Inactive,
     Active
   } mState;
 
   IDBTransactionMode mTransactionMode;
   Sequence<nsString> mObjectStores;
+  bool mCreatedSchema;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_DataStoreDB_h
--- a/dom/datastore/DataStoreService.cpp
+++ b/dom/datastore/DataStoreService.cpp
@@ -513,141 +513,93 @@ public:
 
 private:
   uint32_t mAppId;
   nsString mName;
   nsString mManifestURL;
 };
 
 // This DataStoreDBCallback is called when DataStoreDB opens the DataStore DB.
-// Then the first revision will be created if it doesn't exist yet.
+// Then the first revision will be created if it's needed.
 class FirstRevisionIdCallback MOZ_FINAL : public DataStoreDBCallback
-                                        , public nsIDOMEventListener
 {
 public:
-  NS_DECL_ISUPPORTS
+  NS_INLINE_DECL_REFCOUNTING(FirstRevisionIdCallback)
 
   FirstRevisionIdCallback(uint32_t aAppId, const nsAString& aName,
                           const nsAString& aManifestURL)
     : mAppId(aAppId)
     , mName(aName)
     , mManifestURL(aManifestURL)
   {
     AssertIsInMainProcess();
     MOZ_ASSERT(NS_IsMainThread());
   }
 
   void
-  Run(DataStoreDB* aDb, bool aSuccess)
+  Run(DataStoreDB* aDb, RunStatus aStatus)
   {
     AssertIsInMainProcess();
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aDb);
 
-    if (!aSuccess) {
+    if (aStatus == Error) {
       NS_WARNING("Failed to create the first revision.");
       return;
     }
 
-    mTxn = aDb->Transaction();
+    if (aStatus == Success) {
+      nsRefPtr<DataStoreService> service = DataStoreService::Get();
+      MOZ_ASSERT(service);
 
-    ErrorResult rv;
-    nsRefPtr<IDBObjectStore> store =
-      mTxn->ObjectStore(NS_LITERAL_STRING(DATASTOREDB_REVISION), rv);
-    if (NS_WARN_IF(rv.Failed())) {
-      return;
-    }
+      nsresult rv = service->EnableDataStore(mAppId, mName, mManifestURL);
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Failed to enable a DataStore.");
+      }
 
-    // a Null JSContext is ok because OpenCursor ignores it if the range is
-    // undefined.
-    mRequest = store->OpenCursor(nullptr, JS::UndefinedHandleValue,
-                                 IDBCursorDirection::Prev, rv);
-    if (NS_WARN_IF(rv.Failed())) {
       return;
     }
 
-    nsresult res;
-    res = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("success"),
-                                                  this, false);
-    if (NS_WARN_IF(NS_FAILED(res))) {
-      return;
-    }
-  }
-
-  // nsIDOMEventListener
-  NS_IMETHOD
-  HandleEvent(nsIDOMEvent* aEvent)
-  {
-    AssertIsInMainProcess();
-    MOZ_ASSERT(NS_IsMainThread());
-
-    nsString type;
-    nsresult rv = aEvent->GetType(type);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    if (!type.EqualsASCII("success")) {
-      return NS_ERROR_FAILURE;
-    }
-
-    mRequest->RemoveEventListener(NS_LITERAL_STRING("success"), this, false);
-
-    // Note: this cx is only used for rooting and AddRevision, neither of which
-    // actually care which compartment we're in.
-    AutoSafeJSContext cx;
+    // The DB has just been created.
 
     ErrorResult error;
-    JS::Rooted<JS::Value> result(cx);
-    mRequest->GetResult(cx, &result, error);
-    if (NS_WARN_IF(error.Failed())) {
-      return error.ErrorCode();
-    }
-
-    // This means that the content is a IDBCursor, so the first revision already
-    // exists.
-    if (result.isObject()) {
-      nsRefPtr<DataStoreService> service = DataStoreService::Get();
-      MOZ_ASSERT(service);
-
-      return service->EnableDataStore(mAppId, mName, mManifestURL);
-    }
-
-    MOZ_ASSERT(mTxn);
     nsRefPtr<IDBObjectStore> store =
-      mTxn->ObjectStore(NS_LITERAL_STRING(DATASTOREDB_REVISION), error);
-    if (NS_WARN_IF(error.Failed())) {
-      return error.ErrorCode();
+      aDb->Transaction()->ObjectStore(NS_LITERAL_STRING(DATASTOREDB_REVISION),
+                                      error);
+    if (error.Failed()) {
+      NS_WARNING("Failed to get an ObjectStore object.");
+      return;
     }
     MOZ_ASSERT(store);
 
     nsRefPtr<RevisionAddedEnableStoreCallback> callback =
       new RevisionAddedEnableStoreCallback(mAppId, mName, mManifestURL);
 
+    // Note: this cx is only used for rooting and AddRevision, neither of which
+    // actually care which compartment we're in.
+    AutoSafeJSContext cx;
+
     // If the revision doesn't exist, let's create it.
     nsRefPtr<DataStoreRevision> revision = new DataStoreRevision();
-    return revision->AddRevision(cx, store, 0, DataStoreRevision::RevisionVoid,
-                                 callback);
+    nsresult rv = revision->AddRevision(cx, store, 0,
+                                        DataStoreRevision::RevisionVoid,
+                                        callback);
+    if (NS_FAILED(rv)) {
+      NS_WARNING("Failed to add a revision to a DataStore.");
+    }
   }
 
 private:
   ~FirstRevisionIdCallback() {}
 
-  nsRefPtr<IDBRequest> mRequest;
-
-  nsRefPtr<IDBTransaction> mTxn;
-  nsRefPtr<DataStoreRevision> mRevision;
-
   uint32_t mAppId;
   nsString mName;
   nsString mManifestURL;
 };
 
-NS_IMPL_ISUPPORTS(FirstRevisionIdCallback, nsIDOMEventListener)
-
 // This class calls the 'retrieveRevisionId' method of the DataStore object for
 // any DataStore in the 'mResults' array. When all of them are called, the
 // promise is resolved with 'mResults'.
 // The reson why this has to be done is because DataStore are object that can be
 // created in any thread and in any process. The first revision has been
 // created, but they don't know its value yet.
 class RetrieveRevisionsCounter
 {
--- a/dom/datastore/tests/mochitest.ini
+++ b/dom/datastore/tests/mochitest.ini
@@ -28,31 +28,25 @@ support-files =
   file_transactions.html
   file_basic_common.js
   file_sync_common.js
   file_bug1008044.html
   file_bug957086.html
 
 [test_app_install.html]
 [test_readonly.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure; time out) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_basic.html]
 [test_basic_worker.html]
 [test_changes.html]
-skip-if = (toolkit == 'gonk' && debug) #intermittent failures, bug 961021
 [test_arrays.html]
-skip-if = (toolkit == 'gonk' && debug) #debug-only failure; time out
 [test_oop.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure; time out) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_sync.html]
 [test_sync_worker.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure; time out) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_bug924104.html]
 [test_certifiedApp.html]
-skip-if = (toolkit == 'gonk' && debug) #debug-only failure; time out
 [test_keys.html]
 [test_duplicate.html]
 [test_bug976311.html]
 [test_bug986056.html]
 [test_oop_events.html]
 [test_transactions.html]
 [test_bug1008044.html]
 [test_bug957086.html]
--- a/dom/devicestorage/test/test_dirs.html
+++ b/dom/devicestorage/test/test_dirs.html
@@ -44,27 +44,37 @@ SpecialPowers.pushPrefEnv({
   ok(!navigator.getDeviceStorage("nonexistent-type"), "Should not have nonexistent storage");
 
   ok(navigator.getDeviceStorage("pictures"), "Should have pictures storage");
   ok(navigator.getDeviceStorage("videos"), "Should have videos storage");
   ok(navigator.getDeviceStorage("music"), "Should have music storage");
 
   // Need special permission to access "apps". We always have the permission in B2G
   // mochitests, but on other platforms, we need to manually add the permission.
+  var needAppsPermission = false;;
   if (!SpecialPowers.testPermission(
       "webapps-manage", SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document)) {
     ok(!navigator.getDeviceStorage("apps"), "Should not have apps storage without permission");
-    SpecialPowers.addPermission("webapps-manage", true, document);
+    needAppsPermission = true;
   }
-  ok(navigator.getDeviceStorage("apps"), "Should have apps storage with permission");
 
-  ok(navigator.getDeviceStorage("sdcard"), "Should have sdcard storage");
-  ok(navigator.getDeviceStorage("crashes"), "Should have crashes storage");
+  var testFunction = function() {
+    ok(navigator.getDeviceStorage("apps"), "Should have apps storage with permission");
+    ok(navigator.getDeviceStorage("sdcard"), "Should have sdcard storage");
+    ok(navigator.getDeviceStorage("crashes"), "Should have crashes storage");
+    // The test harness reverts our pref changes automatically.
+    SimpleTest.finish();
+  }
 
-  // The test harness reverts our pref changes automatically.
-  SimpleTest.finish();
+  if (needAppsPermission) {
+    SpecialPowers.pushPermissions(
+      [{ "type":"webapps-manage", "allow": true, "context": document }],
+      testFunction);
+  } else {
+    testFunction();
+  }
 });
 
   </script>
   </pre>
 </body>
 </html>
 
--- a/dom/events/CompositionEvent.cpp
+++ b/dom/events/CompositionEvent.cpp
@@ -12,17 +12,17 @@ namespace mozilla {
 namespace dom {
 
 CompositionEvent::CompositionEvent(EventTarget* aOwner,
                                    nsPresContext* aPresContext,
                                    WidgetCompositionEvent* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent : new WidgetCompositionEvent(false, 0, nullptr))
 {
-  NS_ASSERTION(mEvent->eventStructType == NS_COMPOSITION_EVENT,
+  NS_ASSERTION(mEvent->mClass == eCompositionEventClass,
                "event type mismatch");
 
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
 
--- a/dom/events/DragEvent.cpp
+++ b/dom/events/DragEvent.cpp
@@ -111,17 +111,17 @@ DragEvent::GetDataTransfer(nsIDOMDataTra
 
 DataTransfer*
 DragEvent::GetDataTransfer()
 {
   // the dataTransfer field of the event caches the DataTransfer associated
   // with the drag. It is initialized when an attempt is made to retrieve it
   // rather that when the event is created to avoid duplicating the data when
   // no listener ever uses it.
-  if (!mEvent || mEvent->eventStructType != NS_DRAG_EVENT) {
+  if (!mEvent || mEvent->mClass != eDragEventClass) {
     NS_WARNING("Tried to get dataTransfer from non-drag event!");
     return nullptr;
   }
 
   WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
   // for synthetic events, just use the supplied data transfer object even if null
   if (!mEventIsInternal) {
     nsresult rv = nsContentUtils::SetDataTransferInEvent(dragEvent);
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -152,37 +152,37 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Eve
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
   if (tmp->mEventIsInternal) {
     tmp->mEvent->target = nullptr;
     tmp->mEvent->currentTarget = nullptr;
     tmp->mEvent->originalTarget = nullptr;
-    switch (tmp->mEvent->eventStructType) {
-      case NS_MOUSE_EVENT:
-      case NS_MOUSE_SCROLL_EVENT:
-      case NS_WHEEL_EVENT:
-      case NS_SIMPLE_GESTURE_EVENT:
-      case NS_POINTER_EVENT:
+    switch (tmp->mEvent->mClass) {
+      case eMouseEventClass:
+      case eMouseScrollEventClass:
+      case eWheelEventClass:
+      case eSimpleGestureEventClass:
+      case ePointerEventClass:
         tmp->mEvent->AsMouseEventBase()->relatedTarget = nullptr;
         break;
-      case NS_DRAG_EVENT: {
+      case eDragEventClass: {
         WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
         dragEvent->dataTransfer = nullptr;
         dragEvent->relatedTarget = nullptr;
         break;
       }
-      case NS_CLIPBOARD_EVENT:
+      case eClipboardEventClass:
         tmp->mEvent->AsClipboardEvent()->clipboardData = nullptr;
         break;
-      case NS_MUTATION_EVENT:
+      case eMutationEventClass:
         tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
         break;
-      case NS_FOCUS_EVENT:
+      case eFocusEventClass:
         tmp->mEvent->AsFocusEvent()->relatedTarget = nullptr;
         break;
       default:
         break;
     }
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
@@ -190,42 +190,42 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Ev
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
   if (tmp->mEventIsInternal) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->target)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->currentTarget)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->originalTarget)
-    switch (tmp->mEvent->eventStructType) {
-      case NS_MOUSE_EVENT:
-      case NS_MOUSE_SCROLL_EVENT:
-      case NS_WHEEL_EVENT:
-      case NS_SIMPLE_GESTURE_EVENT:
-      case NS_POINTER_EVENT:
+    switch (tmp->mEvent->mClass) {
+      case eMouseEventClass:
+      case eMouseScrollEventClass:
+      case eWheelEventClass:
+      case eSimpleGestureEventClass:
+      case ePointerEventClass:
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
         cb.NoteXPCOMChild(tmp->mEvent->AsMouseEventBase()->relatedTarget);
         break;
-      case NS_DRAG_EVENT: {
+      case eDragEventClass: {
         WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->dataTransfer");
         cb.NoteXPCOMChild(dragEvent->dataTransfer);
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
         cb.NoteXPCOMChild(dragEvent->relatedTarget);
         break;
       }
-      case NS_CLIPBOARD_EVENT:
+      case eClipboardEventClass:
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->clipboardData");
         cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->clipboardData);
         break;
-      case NS_MUTATION_EVENT:
+      case eMutationEventClass:
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
         cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
         break;
-      case NS_FOCUS_EVENT:
+      case eFocusEventClass:
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
         cb.NoteXPCOMChild(tmp->mEvent->AsFocusEvent()->relatedTarget);
         break;
       default:
         break;
     }
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
@@ -520,17 +520,17 @@ Event::PreventDefaultInternal(bool aCall
 }
 
 void
 Event::SetEventType(const nsAString& aEventTypeArg)
 {
   if (mIsMainThreadEvent) {
     mEvent->typeString.Truncate();
     mEvent->userType =
-      nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType,
+      nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->mClass,
                                         &(mEvent->message));
   } else {
     mEvent->userType = nullptr;
     mEvent->message = NS_USER_DEFINED_EVENT;
     mEvent->typeString = aEventTypeArg;
   }
 }
 
@@ -656,18 +656,18 @@ PopupAllowedForEvent(const char *eventNa
 // static
 PopupControlState
 Event::GetEventPopupControlState(WidgetEvent* aEvent)
 {
   // generally if an event handler is running, new windows are disallowed.
   // check for exceptions:
   PopupControlState abuse = openAbused;
 
-  switch(aEvent->eventStructType) {
-  case NS_EVENT :
+  switch(aEvent->mClass) {
+  case eBasicEventClass:
     // For these following events only allow popups if they're
     // triggered while handling user input. See
     // nsPresShell::HandleEventInternal() for details.
     if (EventStateManager::IsHandlingUserInput()) {
       switch(aEvent->message) {
       case NS_FORM_SELECTED :
         if (PopupAllowedForEvent("select")) {
           abuse = openControlled;
@@ -676,48 +676,48 @@ Event::GetEventPopupControlState(WidgetE
       case NS_FORM_CHANGE :
         if (PopupAllowedForEvent("change")) {
           abuse = openControlled;
         }
         break;
       }
     }
     break;
-  case NS_EDITOR_INPUT_EVENT :
+  case eEditorInputEventClass:
     // For this following event only allow popups if it's triggered
     // while handling user input. See
     // nsPresShell::HandleEventInternal() for details.
     if (EventStateManager::IsHandlingUserInput()) {
       switch(aEvent->message) {
       case NS_EDITOR_INPUT:
         if (PopupAllowedForEvent("input")) {
           abuse = openControlled;
         }
         break;
       }
     }
     break;
-  case NS_INPUT_EVENT :
+  case eInputEventClass:
     // For this following event only allow popups if it's triggered
     // while handling user input. See
     // nsPresShell::HandleEventInternal() for details.
     if (EventStateManager::IsHandlingUserInput()) {
       switch(aEvent->message) {
       case NS_FORM_CHANGE :
         if (PopupAllowedForEvent("change")) {
           abuse = openControlled;
         }
         break;
       case NS_XUL_COMMAND:
         abuse = openControlled;
         break;
       }
     }
     break;
-  case NS_KEY_EVENT :
+  case eKeyboardEventClass:
     if (aEvent->mFlags.mIsTrusted) {
       uint32_t key = aEvent->AsKeyboardEvent()->keyCode;
       switch(aEvent->message) {
       case NS_KEY_PRESS :
         // return key on focused button. see note at NS_MOUSE_CLICK.
         if (key == nsIDOMKeyEvent::DOM_VK_RETURN) {
           abuse = openAllowed;
         } else if (PopupAllowedForEvent("keypress")) {
@@ -735,33 +735,33 @@ Event::GetEventPopupControlState(WidgetE
       case NS_KEY_DOWN :
         if (PopupAllowedForEvent("keydown")) {
           abuse = openControlled;
         }
         break;
       }
     }
     break;
-  case NS_TOUCH_EVENT :
+  case eTouchEventClass:
     if (aEvent->mFlags.mIsTrusted) {
       switch (aEvent->message) {
       case NS_TOUCH_START :
         if (PopupAllowedForEvent("touchstart")) {
           abuse = openControlled;
         }
         break;
       case NS_TOUCH_END :
         if (PopupAllowedForEvent("touchend")) {
           abuse = openControlled;
         }
         break;
       }
     }
     break;
-  case NS_MOUSE_EVENT :
+  case eMouseEventClass:
     if (aEvent->mFlags.mIsTrusted &&
         aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
       switch(aEvent->message) {
       case NS_MOUSE_BUTTON_UP :
         if (PopupAllowedForEvent("mouseup")) {
           abuse = openControlled;
         }
         break;
@@ -782,17 +782,17 @@ Event::GetEventPopupControlState(WidgetE
       case NS_MOUSE_DOUBLECLICK :
         if (PopupAllowedForEvent("dblclick")) {
           abuse = openControlled;
         }
         break;
       }
     }
     break;
-  case NS_FORM_EVENT :
+  case eFormEventClass:
     // For these following events only allow popups if they're
     // triggered while handling user input. See
     // nsPresShell::HandleEventInternal() for details.
     if (EventStateManager::IsHandlingUserInput()) {
       switch(aEvent->message) {
       case NS_FORM_SUBMIT :
         if (PopupAllowedForEvent("submit")) {
           abuse = openControlled;
@@ -842,23 +842,23 @@ Event::GetScreenCoords(nsPresContext* aP
                        WidgetEvent* aEvent,
                        LayoutDeviceIntPoint aPoint)
 {
   if (EventStateManager::sIsPointerLocked) {
     return EventStateManager::sLastScreenPoint;
   }
 
   if (!aEvent || 
-       (aEvent->eventStructType != NS_MOUSE_EVENT &&
-        aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
-        aEvent->eventStructType != NS_WHEEL_EVENT &&
-        aEvent->eventStructType != NS_POINTER_EVENT &&
-        aEvent->eventStructType != NS_TOUCH_EVENT &&
-        aEvent->eventStructType != NS_DRAG_EVENT &&
-        aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
+       (aEvent->mClass != eMouseEventClass &&
+        aEvent->mClass != eMouseScrollEventClass &&
+        aEvent->mClass != eWheelEventClass &&
+        aEvent->mClass != ePointerEventClass &&
+        aEvent->mClass != eTouchEventClass &&
+        aEvent->mClass != eDragEventClass &&
+        aEvent->mClass != eSimpleGestureEventClass)) {
     return nsIntPoint(0, 0);
   }
 
   WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
   if (!guiEvent->widget) {
     return LayoutDeviceIntPoint::ToUntyped(aPoint);
   }
 
@@ -898,23 +898,23 @@ Event::GetClientCoords(nsPresContext* aP
                        LayoutDeviceIntPoint aPoint,
                        CSSIntPoint aDefaultPoint)
 {
   if (EventStateManager::sIsPointerLocked) {
     return EventStateManager::sLastClientPoint;
   }
 
   if (!aEvent ||
-      (aEvent->eventStructType != NS_MOUSE_EVENT &&
-       aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
-       aEvent->eventStructType != NS_WHEEL_EVENT &&
-       aEvent->eventStructType != NS_TOUCH_EVENT &&
-       aEvent->eventStructType != NS_DRAG_EVENT &&
-       aEvent->eventStructType != NS_POINTER_EVENT &&
-       aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
+      (aEvent->mClass != eMouseEventClass &&
+       aEvent->mClass != eMouseScrollEventClass &&
+       aEvent->mClass != eWheelEventClass &&
+       aEvent->mClass != eTouchEventClass &&
+       aEvent->mClass != eDragEventClass &&
+       aEvent->mClass != ePointerEventClass &&
+       aEvent->mClass != eSimpleGestureEventClass) ||
       !aPresContext ||
       !aEvent->AsGUIEvent()->widget) {
     return aDefaultPoint;
   }
 
   nsIPresShell* shell = aPresContext->GetPresShell();
   if (!shell) {
     return CSSIntPoint(0, 0);
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -679,80 +679,80 @@ EventDispatcher::CreateEvent(EventTarget
                              nsPresContext* aPresContext,
                              WidgetEvent* aEvent,
                              const nsAString& aEventType,
                              nsIDOMEvent** aDOMEvent)
 {
   *aDOMEvent = nullptr;
 
   if (aEvent) {
-    switch(aEvent->eventStructType) {
-    case NS_MUTATION_EVENT:
+    switch(aEvent->mClass) {
+    case eMutationEventClass:
       return NS_NewDOMMutationEvent(aDOMEvent, aOwner, aPresContext,
                                     aEvent->AsMutationEvent());
-    case NS_GUI_EVENT:
-    case NS_SCROLLPORT_EVENT:
-    case NS_UI_EVENT:
+    case eGUIEventClass:
+    case eScrollPortEventClass:
+    case eUIEventClass:
       return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext,
                               aEvent->AsGUIEvent());
-    case NS_SCROLLAREA_EVENT:
+    case eScrollAreaEventClass:
       return NS_NewDOMScrollAreaEvent(aDOMEvent, aOwner, aPresContext,
                                       aEvent->AsScrollAreaEvent());
-    case NS_KEY_EVENT:
+    case eKeyboardEventClass:
       return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext,
                                     aEvent->AsKeyboardEvent());
-    case NS_COMPOSITION_EVENT:
+    case eCompositionEventClass:
       return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext,
                                        aEvent->AsCompositionEvent());
-    case NS_MOUSE_EVENT:
+    case eMouseEventClass:
       return NS_NewDOMMouseEvent(aDOMEvent, aOwner, aPresContext,
                                  aEvent->AsMouseEvent());
-    case NS_FOCUS_EVENT:
+    case eFocusEventClass:
       return NS_NewDOMFocusEvent(aDOMEvent, aOwner, aPresContext,
                                  aEvent->AsFocusEvent());
-    case NS_MOUSE_SCROLL_EVENT:
+    case eMouseScrollEventClass:
       return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext,
                                        aEvent->AsMouseScrollEvent());
-    case NS_WHEEL_EVENT:
+    case eWheelEventClass:
       return NS_NewDOMWheelEvent(aDOMEvent, aOwner, aPresContext,
                                  aEvent->AsWheelEvent());
-    case NS_EDITOR_INPUT_EVENT:
+    case eEditorInputEventClass:
       return NS_NewDOMInputEvent(aDOMEvent, aOwner, aPresContext,
                                  aEvent->AsEditorInputEvent());
-    case NS_DRAG_EVENT:
+    case eDragEventClass:
       return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext,
                                 aEvent->AsDragEvent());
-    case NS_TEXT_EVENT:
+    case eTextEventClass:
       return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext,
                               aEvent->AsTextEvent());
-    case NS_CLIPBOARD_EVENT:
+    case eClipboardEventClass:
       return NS_NewDOMClipboardEvent(aDOMEvent, aOwner, aPresContext,
                                      aEvent->AsClipboardEvent());
-    case NS_SVGZOOM_EVENT:
+    case eSVGZoomEventClass:
       return NS_NewDOMSVGZoomEvent(aDOMEvent, aOwner, aPresContext,
                                    aEvent->AsSVGZoomEvent());
-    case NS_SMIL_TIME_EVENT:
+    case eSMILTimeEventClass:
       return NS_NewDOMTimeEvent(aDOMEvent, aOwner, aPresContext,
                                 aEvent->AsSMILTimeEvent());
-    case NS_COMMAND_EVENT:
+    case eCommandEventClass:
       return NS_NewDOMCommandEvent(aDOMEvent, aOwner, aPresContext,
                                    aEvent->AsCommandEvent());
-    case NS_SIMPLE_GESTURE_EVENT:
+    case eSimpleGestureEventClass:
       return NS_NewDOMSimpleGestureEvent(aDOMEvent, aOwner, aPresContext,
                                          aEvent->AsSimpleGestureEvent());
-    case NS_POINTER_EVENT:
+    case ePointerEventClass:
       return NS_NewDOMPointerEvent(aDOMEvent, aOwner, aPresContext,
                                    aEvent->AsPointerEvent());
-    case NS_TOUCH_EVENT:
+    case eTouchEventClass:
       return NS_NewDOMTouchEvent(aDOMEvent, aOwner, aPresContext,
                                  aEvent->AsTouchEvent());
-    case NS_TRANSITION_EVENT:
+    case eTransitionEventClass:
       return NS_NewDOMTransitionEvent(aDOMEvent, aOwner, aPresContext,
                                       aEvent->AsTransitionEvent());
-    case NS_ANIMATION_EVENT:
+    case eAnimationEventClass:
       return NS_NewDOMAnimationEvent(aDOMEvent, aOwner, aPresContext,
                                      aEvent->AsAnimationEvent());
     default:
       // For all other types of events, create a vanilla event object.
       return NS_NewDOMEvent(aDOMEvent, aOwner, aPresContext, aEvent);
     }
   }
 
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -145,772 +145,772 @@
 #ifndef BEFOREUNLOAD_EVENT
 #define BEFOREUNLOAD_EVENT WINDOW_EVENT
 #define DEFINED_BEFOREUNLOAD_EVENT
 #endif /* BEFOREUNLOAD_EVENT */
 
 EVENT(abort,
       NS_IMAGE_ABORT,
       EventNameType_All,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(canplay,
       NS_CANPLAY,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(canplaythrough,
       NS_CANPLAYTHROUGH,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(change,
       NS_FORM_CHANGE,
       EventNameType_HTMLXUL,
-      NS_EVENT )
+      eBasicEventClass)
 EVENT(click,
       NS_MOUSE_CLICK,
       EventNameType_All,
-      NS_MOUSE_EVENT)
+      eMouseEventClass)
 EVENT(contextmenu,
       NS_CONTEXTMENU,
       EventNameType_HTMLXUL,
-      NS_MOUSE_EVENT)
+      eMouseEventClass)
 // Not supported yet
 // EVENT(cuechange)
 EVENT(dblclick,
       NS_MOUSE_DOUBLECLICK,
       EventNameType_HTMLXUL,
-      NS_MOUSE_EVENT)
+      eMouseEventClass)
 EVENT(drag,
       NS_DRAGDROP_DRAG,
       EventNameType_HTMLXUL,
-      NS_DRAG_EVENT)
+      eDragEventClass)
 EVENT(dragend,
       NS_DRAGDROP_END,
       EventNameType_HTMLXUL,
-      NS_DRAG_EVENT)
+      eDragEventClass)
 EVENT(dragenter,
       NS_DRAGDROP_ENTER,
       EventNameType_HTMLXUL,
-      NS_DRAG_EVENT)
+      eDragEventClass)
 EVENT(dragleave,
       NS_DRAGDROP_LEAVE_SYNTH,
       EventNameType_HTMLXUL,
-      NS_DRAG_EVENT)
+      eDragEventClass)
 EVENT(dragover,
       NS_DRAGDROP_OVER_SYNTH,
       EventNameType_HTMLXUL,
-      NS_DRAG_EVENT)
+      eDragEventClass)
 EVENT(dragstart,
       NS_DRAGDROP_START,
       EventNameType_HTMLXUL,
-      NS_DRAG_EVENT)
+      eDragEventClass)
 EVENT(drop,
       NS_DRAGDROP_DROP,
       EventNameType_HTMLXUL,
-      NS_DRAG_EVENT)
+      eDragEventClass)
 EVENT(durationchange,
       NS_DURATIONCHANGE,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(emptied,
       NS_EMPTIED,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(ended,
       NS_ENDED,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(input,
       NS_EDITOR_INPUT,
       EventNameType_HTMLXUL,
-      NS_EDITOR_INPUT_EVENT)
+      eEditorInputEventClass)
 EVENT(invalid,
       NS_FORM_INVALID,
       EventNameType_HTMLXUL,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(keydown,
       NS_KEY_DOWN,
       EventNameType_HTMLXUL,
-      NS_KEY_EVENT)
+      eKeyboardEventClass)
 EVENT(keypress,
       NS_KEY_PRESS,
       EventNameType_HTMLXUL,
-      NS_KEY_EVENT)
+      eKeyboardEventClass)
 EVENT(keyup,
       NS_KEY_UP,
       EventNameType_HTMLXUL,
-      NS_KEY_EVENT)
+      eKeyboardEventClass)
 EVENT(loadeddata,
       NS_LOADEDDATA,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(loadedmetadata,
       NS_LOADEDMETADATA,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(loadstart,
       NS_LOADSTART,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(mousedown,
       NS_MOUSE_BUTTON_DOWN,
       EventNameType_All,
-      NS_MOUSE_EVENT)
+      eMouseEventClass)
 EVENT(mouseenter,
       NS_MOUSEENTER,
       EventNameType_All,
-      NS_MOUSE_EVENT)
+      eMouseEventClass)
 EVENT(mouseleave,
       NS_MOUSELEAVE,
       EventNameType_All,
-      NS_MOUSE_EVENT)
+      eMouseEventClass)
 EVENT(mousemove,
       NS_MOUSE_MOVE,
       EventNameType_All,
-      NS_MOUSE_EVENT)
+      eMouseEventClass)
 EVENT(mouseout,
       NS_MOUSE_EXIT_SYNTH,
       EventNameType_All,
-      NS_MOUSE_EVENT)
+      eMouseEventClass)
 EVENT(mouseover,
       NS_MOUSE_ENTER_SYNTH,
       EventNameType_All,
-      NS_MOUSE_EVENT)
+      eMouseEventClass)
 EVENT(mouseup,
       NS_MOUSE_BUTTON_UP,
       EventNameType_All,
-      NS_MOUSE_EVENT)
+      eMouseEventClass)
 EVENT(mozfullscreenchange,
       NS_FULLSCREENCHANGE,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(mozfullscreenerror,
       NS_FULLSCREENERROR,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(mozpointerlockchange,
       NS_POINTERLOCKCHANGE,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(mozpointerlockerror,
       NS_POINTERLOCKERROR,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(pointerdown,
       NS_POINTER_DOWN,
       EventNameType_All,
-      NS_POINTER_EVENT)
+      ePointerEventClass)
 EVENT(pointermove,
       NS_POINTER_MOVE,
       EventNameType_All,
-      NS_POINTER_EVENT)
+      ePointerEventClass)
 EVENT(pointerup,
       NS_POINTER_UP,
       EventNameType_All,
-      NS_POINTER_EVENT)
+      ePointerEventClass)
 EVENT(pointercancel,
       NS_POINTER_CANCEL,
       EventNameType_All,
-      NS_POINTER_EVENT)
+      ePointerEventClass)
 EVENT(pointerover,
       NS_POINTER_OVER,
       EventNameType_All,
-      NS_POINTER_EVENT)
+      ePointerEventClass)
 EVENT(pointerout,
       NS_POINTER_OUT,
       EventNameType_All,
-      NS_POINTER_EVENT)
+      ePointerEventClass)
 EVENT(pointerenter,
       NS_POINTER_ENTER,
       EventNameType_All,
-      NS_POINTER_EVENT)
+      ePointerEventClass)
 EVENT(pointerleave,
       NS_POINTER_LEAVE,
       EventNameType_All,
-      NS_POINTER_EVENT)
+      ePointerEventClass)
 EVENT(gotpointercapture,
       NS_POINTER_GOT_CAPTURE,
       EventNameType_All,
-      NS_POINTER_EVENT)
+      ePointerEventClass)
 EVENT(lostpointercapture,
       NS_POINTER_LOST_CAPTURE,
       EventNameType_All,
-      NS_POINTER_EVENT)
+      ePointerEventClass)
 
 // Not supported yet; probably never because "wheel" is a better idea.
 // EVENT(mousewheel)
 EVENT(pause,
       NS_PAUSE,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(play,
       NS_PLAY,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(playing,
       NS_PLAYING,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(progress,
       NS_PROGRESS,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(ratechange,
       NS_RATECHANGE,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(reset,
       NS_FORM_RESET,
       EventNameType_HTMLXUL,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(seeked,
       NS_SEEKED,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(seeking,
       NS_SEEKING,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(select,
       NS_FORM_SELECTED,
       EventNameType_HTMLXUL,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(show,
       NS_SHOW_EVENT,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(stalled,
       NS_STALLED,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(submit,
       NS_FORM_SUBMIT,
       EventNameType_HTMLXUL,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(suspend,
       NS_SUSPEND,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(timeupdate,
       NS_TIMEUPDATE,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(volumechange,
       NS_VOLUMECHANGE,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(waiting,
       NS_WAITING,
       EventNameType_HTML,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(wheel,
       NS_WHEEL_WHEEL,
       EventNameType_All,
-      NS_WHEEL_EVENT)
+      eWheelEventClass)
 EVENT(copy,
       NS_COPY,
       EventNameType_HTMLXUL,
-      NS_CLIPBOARD_EVENT)
+      eClipboardEventClass)
 EVENT(cut,
       NS_CUT,
       EventNameType_HTMLXUL,
-      NS_CLIPBOARD_EVENT)
+      eClipboardEventClass)
 EVENT(paste,
       NS_PASTE,
       EventNameType_HTMLXUL,
-      NS_CLIPBOARD_EVENT)
+      eClipboardEventClass)
 // Gecko-specific extensions that apply to elements
 EVENT(beforescriptexecute,
       NS_BEFORE_SCRIPT_EXECUTE,
       EventNameType_HTMLXUL,
-      NS_EVENT)
+      eBasicEventClass)
 EVENT(afterscriptexecute,
       NS_AFTER_SCRIPT_EXECUTE,
       EventNameType_HTMLXUL,
-      NS_EVENT)
+      eBasicEventClass)
 
 FORWARDED_EVENT(blur,
                 NS_BLUR_CONTENT,
                 EventNameType_HTMLXUL,
-                NS_FOCUS_EVENT)
+                eFocusEventClass)
 ERROR_EVENT(error,
             NS_LOAD_ERROR,
             EventNameType_All,
-            NS_EVENT)
+            eBasicEventClass)
 FORWARDED_EVENT(focus,
                 NS_FOCUS_CONTENT,
                 EventNameType_HTMLXUL,
-                NS_FOCUS_EVENT)
+                eFocusEventClass)
 FORWARDED_EVENT(load,
                 NS_LOAD,
                 EventNameType_All,
-                NS_EVENT)
+                eBasicEventClass)
 FORWARDED_EVENT(scroll,
                 NS_SCROLL_EVENT,
                 (EventNameType_HTMLXUL | EventNameType_SVGSVG),
-                NS_EVENT)
+                eBasicEventClass)
 
 WINDOW_EVENT(afterprint,
              NS_AFTERPRINT,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
-             NS_EVENT)
+             eBasicEventClass)
 WINDOW_EVENT(beforeprint,
              NS_BEFOREPRINT,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
-             NS_EVENT)
+             eBasicEventClass)
 BEFOREUNLOAD_EVENT(beforeunload,
                    NS_BEFORE_PAGE_UNLOAD,
                    EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
-                   NS_EVENT)
+                   eBasicEventClass)
 WINDOW_EVENT(hashchange,
              NS_HASHCHANGE,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
-             NS_EVENT)
+             eBasicEventClass)
 WINDOW_EVENT(languagechange,
              NS_LANGUAGECHANGE,
              EventNameType_HTMLBodyOrFramesetOnly,
-             NS_EVENT)
+             eBasicEventClass)
 // XXXbz Should the onmessage attribute on <body> really not work?  If so, do we
 // need a different macro to flag things like that (IDL, but not content
 // attributes on body/frameset), or is just using EventNameType_None enough?
 WINDOW_EVENT(message,
              NS_MESSAGE,
              EventNameType_None,
-             NS_EVENT)
+             eBasicEventClass)
 WINDOW_EVENT(offline,
              NS_OFFLINE,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
-             NS_EVENT)
+             eBasicEventClass)
 WINDOW_EVENT(online,
              NS_ONLINE,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
-             NS_EVENT)
+             eBasicEventClass)
 WINDOW_EVENT(pagehide,
              NS_PAGE_HIDE,
              EventNameType_HTMLBodyOrFramesetOnly,
-             NS_EVENT)
+             eBasicEventClass)
 WINDOW_EVENT(pageshow,
              NS_PAGE_SHOW,
              EventNameType_HTMLBodyOrFramesetOnly,
-             NS_EVENT)
+             eBasicEventClass)
 WINDOW_EVENT(popstate,
              NS_POPSTATE,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
-             NS_EVENT)
+             eBasicEventClass)
 // Not supported yet
 // WINDOW_EVENT(redo)
 WINDOW_EVENT(resize,
              NS_RESIZE_EVENT,
              (EventNameType_XUL | EventNameType_SVGSVG |
               EventNameType_HTMLBodyOrFramesetOnly),
-             NS_EVENT)
+             eBasicEventClass)
 // Not supported yet
 // WINDOW_EVENT(storage)
 // Not supported yet
 // WINDOW_EVENT(undo)
 WINDOW_EVENT(unload,
              NS_PAGE_UNLOAD,
              (EventNameType_XUL | EventNameType_SVGSVG |
               EventNameType_HTMLBodyOrFramesetOnly),
-             NS_EVENT)
+             eBasicEventClass)
 
 WINDOW_ONLY_EVENT(devicemotion,
                   NS_DEVICE_MOTION,
                   EventNameType_None,
-                  NS_EVENT)
+                  eBasicEventClass)
 WINDOW_ONLY_EVENT(deviceorientation,
                   NS_DEVICE_ORIENTATION,
                   EventNameType_None,
-                  NS_EVENT)
+                  eBasicEventClass)
 WINDOW_ONLY_EVENT(deviceproximity,
                   NS_DEVICE_PROXIMITY,
                   EventNameType_None,
-                  NS_EVENT)
+                  eBasicEventClass)
 WINDOW_ONLY_EVENT(userproximity,
                   NS_USER_PROXIMITY,
                   EventNameType_None,
-                  NS_EVENT)
+                  eBasicEventClass)
 WINDOW_ONLY_EVENT(devicelight,
                   NS_DEVICE_LIGHT,
                   EventNameType_None,
-                  NS_EVENT)
+                  eBasicEventClass)
 
 #ifdef MOZ_B2G
 WINDOW_ONLY_EVENT(moztimechange,
                   NS_MOZ_TIME_CHANGE_EVENT,
                   EventNameType_None,
-                  NS_EVENT)
+                  eBasicEventClass)
 WINDOW_ONLY_EVENT(moznetworkupload,
                   NS_NETWORK_UPLOAD_EVENT,
                   EventNameType_None,
-                  NS_EVENT)
+                  eBasicEventClass)
 WINDOW_ONLY_EVENT(moznetworkdownload,
                   NS_NETWORK_DOWNLOAD_EVENT,
                   EventNameType_None,
-                  NS_EVENT)
+                  eBasicEventClass)
 #endif // MOZ_B2G
 
 TOUCH_EVENT(touchstart,
             NS_TOUCH_START,
             EventNameType_All,
-            NS_TOUCH_EVENT)
+            eTouchEventClass)
 TOUCH_EVENT(touchend,
             NS_TOUCH_END,
             EventNameType_All,
-            NS_TOUCH_EVENT)
+            eTouchEventClass)
 TOUCH_EVENT(touchmove,
             NS_TOUCH_MOVE,
             EventNameType_All,
-            NS_TOUCH_EVENT )
+            eTouchEventClass )
 TOUCH_EVENT(touchcancel,
             NS_TOUCH_CANCEL,
             EventNameType_All,
-            NS_TOUCH_EVENT)
+            eTouchEventClass)
 
 DOCUMENT_ONLY_EVENT(readystatechange,
                     NS_READYSTATECHANGE,
                     EventNameType_HTMLXUL,
-                    NS_EVENT)
+                    eBasicEventClass)
 
 NON_IDL_EVENT(MozMouseHittest,
               NS_MOUSE_MOZHITTEST,
               EventNameType_None,
-              NS_MOUSE_EVENT)
+              eMouseEventClass)
 
 NON_IDL_EVENT(DOMAttrModified,
               NS_MUTATION_ATTRMODIFIED,
               EventNameType_HTMLXUL,
-              NS_MUTATION_EVENT)
+              eMutationEventClass)
 NON_IDL_EVENT(DOMCharacterDataModified,
               NS_MUTATION_CHARACTERDATAMODIFIED,
               EventNameType_HTMLXUL,
-              NS_MUTATION_EVENT)
+              eMutationEventClass)
 NON_IDL_EVENT(DOMNodeInserted,
               NS_MUTATION_NODEINSERTED,
               EventNameType_HTMLXUL,
-              NS_MUTATION_EVENT)
+              eMutationEventClass)
 NON_IDL_EVENT(DOMNodeRemoved,
               NS_MUTATION_NODEREMOVED,
               EventNameType_HTMLXUL,
-              NS_MUTATION_EVENT)
+              eMutationEventClass)
 NON_IDL_EVENT(DOMNodeInsertedIntoDocument,
               NS_MUTATION_NODEINSERTEDINTODOCUMENT,
               EventNameType_HTMLXUL,
-              NS_MUTATION_EVENT)
+              eMutationEventClass)
 NON_IDL_EVENT(DOMNodeRemovedFromDocument,
               NS_MUTATION_NODEREMOVEDFROMDOCUMENT,
               EventNameType_HTMLXUL,
-              NS_MUTATION_EVENT)
+              eMutationEventClass)
 NON_IDL_EVENT(DOMSubtreeModified,
               NS_MUTATION_SUBTREEMODIFIED,
               EventNameType_HTMLXUL,
-              NS_MUTATION_EVENT)
+              eMutationEventClass)
 
 NON_IDL_EVENT(DOMActivate,
               NS_UI_ACTIVATE,
               EventNameType_HTMLXUL,
-              NS_UI_EVENT)
+              eUIEventClass)
 NON_IDL_EVENT(DOMFocusIn,
               NS_UI_FOCUSIN,
               EventNameType_HTMLXUL,
-              NS_UI_EVENT)
+              eUIEventClass)
 NON_IDL_EVENT(DOMFocusOut,
               NS_UI_FOCUSOUT,
               EventNameType_HTMLXUL,
-              NS_UI_EVENT)
+              eUIEventClass)
                                   
 NON_IDL_EVENT(DOMMouseScroll,
               NS_MOUSE_SCROLL,
               EventNameType_HTMLXUL,
-              NS_MOUSE_SCROLL_EVENT)
+              eMouseScrollEventClass)
 NON_IDL_EVENT(MozMousePixelScroll,
               NS_MOUSE_PIXEL_SCROLL,
               EventNameType_HTMLXUL,
-              NS_MOUSE_SCROLL_EVENT)
+              eMouseScrollEventClass)
                                                 
 NON_IDL_EVENT(open,
               NS_OPEN,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 
 NON_IDL_EVENT(dataavailable,
               NS_MEDIARECORDER_DATAAVAILABLE,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 
 NON_IDL_EVENT(stop,
               NS_MEDIARECORDER_STOP,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 
 NON_IDL_EVENT(warning,
               NS_MEDIARECORDER_WARNING,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 
 NON_IDL_EVENT(speakerforcedchange,
               NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 
 // Events that only have on* attributes on XUL elements
 NON_IDL_EVENT(text,
               NS_TEXT_TEXT,
               EventNameType_XUL,
-              NS_TEXT_EVENT)
+              eTextEventClass)
 NON_IDL_EVENT(compositionstart,
               NS_COMPOSITION_START,
               EventNameType_XUL,
-              NS_COMPOSITION_EVENT)
+              eCompositionEventClass)
 NON_IDL_EVENT(compositionupdate,
               NS_COMPOSITION_UPDATE,
               EventNameType_XUL,
-              NS_COMPOSITION_EVENT)
+              eCompositionEventClass)
 NON_IDL_EVENT(compositionend,
               NS_COMPOSITION_END,
               EventNameType_XUL,
-              NS_COMPOSITION_EVENT)
+              eCompositionEventClass)
 NON_IDL_EVENT(command,
               NS_XUL_COMMAND,
               EventNameType_XUL,
-              NS_INPUT_EVENT)
+              eInputEventClass)
 NON_IDL_EVENT(close,
               NS_XUL_CLOSE,
               EventNameType_XUL,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(popupshowing,
               NS_XUL_POPUP_SHOWING,
               EventNameType_XUL,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(popupshown,
               NS_XUL_POPUP_SHOWN,
               EventNameType_XUL,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(popuphiding,
               NS_XUL_POPUP_HIDING,
               EventNameType_XUL,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(popuphidden,
               NS_XUL_POPUP_HIDDEN,
               EventNameType_XUL,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(broadcast,
               NS_XUL_BROADCAST,
               EventNameType_XUL,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(commandupdate,
               NS_XUL_COMMAND_UPDATE,
               EventNameType_XUL,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(dragexit,
               NS_DRAGDROP_EXIT_SYNTH,
               EventNameType_XUL,
-              NS_DRAG_EVENT)
+              eDragEventClass)
 NON_IDL_EVENT(dragdrop,
               NS_DRAGDROP_DRAGDROP,
               EventNameType_XUL,
-              NS_DRAG_EVENT)
+              eDragEventClass)
 NON_IDL_EVENT(draggesture,
               NS_DRAGDROP_GESTURE,
               EventNameType_XUL,
-              NS_DRAG_EVENT)
+              eDragEventClass)
 NON_IDL_EVENT(overflow,
               NS_SCROLLPORT_OVERFLOW,
               EventNameType_XUL,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(underflow,
               NS_SCROLLPORT_UNDERFLOW,
               EventNameType_XUL,
-              NS_EVENT)
+              eBasicEventClass)
 
 // Various SVG events
 NON_IDL_EVENT(SVGLoad,
               NS_SVG_LOAD,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(SVGUnload,
               NS_SVG_UNLOAD,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(SVGResize,
               NS_SVG_RESIZE,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(SVGScroll,
               NS_SVG_SCROLL,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 
 NON_IDL_EVENT(SVGZoom,
               NS_SVG_ZOOM,
               EventNameType_None,
-              NS_SVGZOOM_EVENT)
+              eSVGZoomEventClass)
 
 // Only map the ID to the real event name when ID_TO_EVENT is defined.
 #ifndef ID_TO_EVENT
 // This is a bit hackish, but SVG's event names are weird.
 NON_IDL_EVENT(zoom,
               NS_SVG_ZOOM,
               EventNameType_SVGSVG,
-              NS_EVENT)
+              eBasicEventClass)
 #endif
 // Only map the ID to the real event name when ID_TO_EVENT is defined.
 #ifndef ID_TO_EVENT
 NON_IDL_EVENT(begin,
               NS_SMIL_BEGIN,
               EventNameType_SMIL,
-              NS_EVENT)
+              eBasicEventClass)
 #endif
 NON_IDL_EVENT(beginEvent,
               NS_SMIL_BEGIN,
               EventNameType_None,
-              NS_SMIL_TIME_EVENT)
+              eSMILTimeEventClass)
 // Only map the ID to the real event name when ID_TO_EVENT is defined.
 #ifndef ID_TO_EVENT
 NON_IDL_EVENT(end,
               NS_SMIL_END,
               EventNameType_SMIL,
-              NS_EVENT)
+              eBasicEventClass)
 #endif
 NON_IDL_EVENT(endEvent,
               NS_SMIL_END,
               EventNameType_None,
-              NS_SMIL_TIME_EVENT)
+              eSMILTimeEventClass)
 // Only map the ID to the real event name when ID_TO_EVENT is defined.
 #ifndef ID_TO_EVENT
 NON_IDL_EVENT(repeat,
               NS_SMIL_REPEAT,
               EventNameType_SMIL,
-              NS_EVENT)
+              eBasicEventClass)
 #endif
 NON_IDL_EVENT(repeatEvent,
               NS_SMIL_REPEAT,
               EventNameType_None,
-              NS_SMIL_TIME_EVENT)
+              eSMILTimeEventClass)
 
 NON_IDL_EVENT(MozAfterPaint,
               NS_AFTERPAINT,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 
 NON_IDL_EVENT(MozScrolledAreaChanged,
               NS_SCROLLEDAREACHANGED,
               EventNameType_None,
-              NS_SCROLLAREA_EVENT)
+              eScrollAreaEventClass)
 
 #ifdef MOZ_GAMEPAD
 NON_IDL_EVENT(gamepadbuttondown,
               NS_GAMEPAD_BUTTONDOWN,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(gamepadbuttonup,
               NS_GAMEPAD_BUTTONUP,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(gamepadaxismove,
               NS_GAMEPAD_AXISMOVE,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(gamepadconnected,
               NS_GAMEPAD_CONNECTED,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 NON_IDL_EVENT(gamepaddisconnected,
               NS_GAMEPAD_DISCONNECTED,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 #endif
 
 // Simple gesture events
 NON_IDL_EVENT(MozSwipeGestureStart,
               NS_SIMPLE_GESTURE_SWIPE_START,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozSwipeGestureUpdate,
               NS_SIMPLE_GESTURE_SWIPE_UPDATE,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozSwipeGestureEnd,
               NS_SIMPLE_GESTURE_SWIPE_END,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozSwipeGesture,
               NS_SIMPLE_GESTURE_SWIPE,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozMagnifyGestureStart,
               NS_SIMPLE_GESTURE_MAGNIFY_START,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozMagnifyGestureUpdate,
               NS_SIMPLE_GESTURE_MAGNIFY_UPDATE,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozMagnifyGesture,
               NS_SIMPLE_GESTURE_MAGNIFY,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozRotateGestureStart,
               NS_SIMPLE_GESTURE_ROTATE_START,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozRotateGestureUpdate,
               NS_SIMPLE_GESTURE_ROTATE_UPDATE,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozRotateGesture,
               NS_SIMPLE_GESTURE_ROTATE,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozTapGesture,
               NS_SIMPLE_GESTURE_TAP,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozPressTapGesture,
               NS_SIMPLE_GESTURE_PRESSTAP,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozEdgeUIStarted,
               NS_SIMPLE_GESTURE_EDGE_STARTED,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozEdgeUICanceled,
               NS_SIMPLE_GESTURE_EDGE_CANCELED,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 NON_IDL_EVENT(MozEdgeUICompleted,
               NS_SIMPLE_GESTURE_EDGE_COMPLETED,
               EventNameType_None,
-              NS_SIMPLE_GESTURE_EVENT)
+              eSimpleGestureEventClass)
 
 NON_IDL_EVENT(transitionend,
               NS_TRANSITION_END,
               EventNameType_None,
-              NS_TRANSITION_EVENT)
+              eTransitionEventClass)
 NON_IDL_EVENT(animationstart,
               NS_ANIMATION_START,
               EventNameType_None,
-              NS_ANIMATION_EVENT)
+              eAnimationEventClass)
 NON_IDL_EVENT(animationend,
               NS_ANIMATION_END,
               EventNameType_None,
-              NS_ANIMATION_EVENT)
+              eAnimationEventClass)
 NON_IDL_EVENT(animationiteration,
               NS_ANIMATION_ITERATION,
               EventNameType_None,
-              NS_ANIMATION_EVENT)
+              eAnimationEventClass)
 
 NON_IDL_EVENT(audioprocess,
               NS_AUDIO_PROCESS,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 
 NON_IDL_EVENT(complete,
               NS_AUDIO_COMPLETE,
               EventNameType_None,
-              NS_EVENT)
+              eBasicEventClass)
 
 #ifdef DEFINED_FORWARDED_EVENT
 #undef DEFINED_FORWARDED_EVENT
 #undef FORWARDED_EVENT
 #endif /* DEFINED_FORWARDED_EVENT */
 
 #ifdef DEFINED_WINDOW_EVENT
 #undef DEFINED_WINDOW_EVENT
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -492,32 +492,32 @@ EventStateManager::PreHandleEvent(nsPres
       "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.
   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
   if (aEvent->mFlags.mIsTrusted &&
       ((mouseEvent && mouseEvent->IsReal()) ||
-       aEvent->eventStructType == NS_WHEEL_EVENT) &&
+       aEvent->mClass == eWheelEventClass) &&
       !sIsPointerLocked) {
     sLastScreenPoint =
       UIEvent::CalculateScreenPoint(aPresContext, aEvent);
     sLastClientPoint =
       UIEvent::CalculateClientPoint(aPresContext, aEvent, nullptr);
   }
 
   // Do not take account NS_MOUSE_ENTER/EXIT so that loading a page
   // when user is not active doesn't change the state to active.
   if (aEvent->mFlags.mIsTrusted &&
       ((mouseEvent && mouseEvent->IsReal() &&
         mouseEvent->message != NS_MOUSE_ENTER &&
         mouseEvent->message != NS_MOUSE_EXIT) ||
-       aEvent->eventStructType == NS_WHEEL_EVENT ||
-       aEvent->eventStructType == NS_KEY_EVENT)) {
+       aEvent->mClass == eWheelEventClass ||
+       aEvent->mClass == eKeyboardEventClass)) {
     if (gMouseOrKeyboardEventCounter == 0) {
       nsCOMPtr<nsIObserverService> obs =
         mozilla::services::GetObserverService();
       if (obs) {
         obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
         UpdateUserActivityTimer();
       }
     }
@@ -1084,27 +1084,27 @@ EventStateManager::DispatchCrossProcessE
                                              nsFrameLoader* aFrameLoader,
                                              nsEventStatus *aStatus) {
   PBrowserParent* remoteBrowser = aFrameLoader->GetRemoteBrowser();
   TabParent* remote = static_cast<TabParent*>(remoteBrowser);
   if (!remote) {
     return false;
   }
 
-  switch (aEvent->eventStructType) {
-  case NS_MOUSE_EVENT: {
+  switch (aEvent->mClass) {
+  case eMouseEventClass: {
     return remote->SendRealMouseEvent(*aEvent->AsMouseEvent());
   }
-  case NS_KEY_EVENT: {
+  case eKeyboardEventClass: {
     return remote->SendRealKeyEvent(*aEvent->AsKeyboardEvent());
   }
-  case NS_WHEEL_EVENT: {
+  case eWheelEventClass: {
     return remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
   }
-  case NS_TOUCH_EVENT: {
+  case eTouchEventClass: {
     // Let the child process synthesize a mouse event if needed, and
     // ensure we don't synthesize one in this process.
     *aStatus = nsEventStatus_eConsumeNoDefault;
     return remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
   }
   default: {
     MOZ_CRASH("Attempt to send non-whitelisted event?");
   }
@@ -1151,32 +1151,32 @@ EventStateManager::GetChildProcessOffset
   nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(&aEvent,
                                                             targetFrame);
   return LayoutDeviceIntPoint::FromAppUnitsToNearest(pt, presContext->AppUnitsPerDevPixel());
 }
 
 bool
 CrossProcessSafeEvent(const WidgetEvent& aEvent)
 {
-  switch (aEvent.eventStructType) {
-  case NS_KEY_EVENT:
-  case NS_WHEEL_EVENT:
+  switch (aEvent.mClass) {
+  case eKeyboardEventClass:
+  case eWheelEventClass:
     return true;
-  case NS_MOUSE_EVENT:
+  case eMouseEventClass:
     switch (aEvent.message) {
     case NS_MOUSE_BUTTON_DOWN:
     case NS_MOUSE_BUTTON_UP:
     case NS_MOUSE_MOVE:
     case NS_CONTEXTMENU:
     case NS_MOUSE_EXIT:
       return true;
     default:
       return false;
     }
-  case NS_TOUCH_EVENT:
+  case eTouchEventClass:
     switch (aEvent.message) {
     case NS_TOUCH_START:
     case NS_TOUCH_MOVE:
     case NS_TOUCH_END:
     case NS_TOUCH_CANCEL:
       return true;
     default:
       return false;
@@ -1195,17 +1195,17 @@ EventStateManager::HandleCrossProcessEve
     return false;
   }
 
   // Collect the remote event targets we're going to forward this
   // event to.
   //
   // NB: the elements of |targets| must be unique, for correctness.
   nsAutoTArray<nsCOMPtr<nsIContent>, 1> targets;
-  if (aEvent->eventStructType != NS_TOUCH_EVENT ||
+  if (aEvent->mClass != eTouchEventClass ||
       aEvent->message == NS_TOUCH_START) {
     // If this event only has one target, and it's remote, add it to
     // the array.
     nsIFrame* frame = GetEventTarget();
     nsIContent* target = frame ? frame->GetContent() : nullptr;
     if (IsRemoteTarget(target)) {
       targets.AppendElement(target);
     }
@@ -3008,17 +3008,17 @@ EventStateManager::PostHandleEvent(nsPre
         DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget);
       }
     }
     break;
 
   case NS_DRAGDROP_ENTER:
   case NS_DRAGDROP_OVER:
     {
-      NS_ASSERTION(aEvent->eventStructType == NS_DRAG_EVENT, "Expected a drag event");
+      NS_ASSERTION(aEvent->mClass == eDragEventClass, "Expected a drag event");
 
       nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
       if (!dragSession)
         break;
 
       // Reset the flag.
       dragSession->SetOnlyChromeDrop(false);
       if (mPresContext) {
@@ -3782,17 +3782,17 @@ EventStateManager::NotifyMouseOut(Widget
   // Store the first mouseOut event we fire and don't refire mouseOut
   // to that element while the first mouseOut is still ongoing.
   wrapper->mFirstOutEventElement = wrapper->mLastOverElement;
 
   // Don't touch hover state if aMovingInto is non-null.  Caller will update
   // hover state itself, and we have optimizations for hover switching between
   // two nearby elements both deep in the DOM tree that would be defeated by
   // switching the hover state to null here.
-  bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT;
+  bool isPointer = aMouseEvent->mClass == ePointerEventClass;
   if (!aMovingInto && !isPointer) {
     // Unset :hover
     SetContentState(nullptr, NS_EVENT_STATE_HOVER);
   }
 
   EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
                                        aMovingInto, aMouseEvent,
                                        isPointer ? NS_POINTER_LEAVE :
@@ -3845,17 +3845,17 @@ EventStateManager::NotifyMouseOver(Widge
   // of havoc.  Reverify and take care.
   if (wrapper->mLastOverElement == aContent && dispatch)
     return;
 
   // Remember mLastOverElement as the related content for the
   // DispatchMouseOrPointerEvent() call below, since NotifyMouseOut() resets it, bug 298477.
   nsCOMPtr<nsIContent> lastOverElement = wrapper->mLastOverElement;
 
-  bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT;
+  bool isPointer = aMouseEvent->mClass == ePointerEventClass;
   
   Maybe<EnterLeaveDispatcher> enterDispatcher;
   if (dispatch) {
     enterDispatcher.construct(this, aContent, lastOverElement, aMouseEvent,
                               isPointer ? NS_POINTER_ENTER : NS_MOUSEENTER);
   }
 
   NotifyMouseOut(aMouseEvent, aContent);
@@ -5111,17 +5111,17 @@ EventStateManager::DeltaAccumulator::Ini
   mX += aEvent->deltaX;
   mY += aEvent->deltaY;
 
   if (mHandlingDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
     // Records pixel delta values and init lineOrPageDeltaX and
     // lineOrPageDeltaY for wheel events which are caused by pixel only
     // devices.  Ignore mouse wheel transaction for computing this.  The
     // lineOrPageDelta values will be used by dispatching legacy
-    // NS_MOUSE_SCROLL_EVENT (DOMMouseScroll) but not be used for scrolling
+    // eMouseScrollEventClass (DOMMouseScroll) but not be used for scrolling
     // of default action.  The transaction should be used only for the default
     // action.
     nsIScrollableFrame* scrollTarget =
       aESM->ComputeScrollTarget(aTargetFrame, aEvent,
                                 COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET);
     nsIFrame* frame = do_QueryFrame(scrollTarget);
     nsPresContext* pc =
       frame ? frame->PresContext() : aTargetFrame->PresContext();
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -125,23 +125,23 @@ GetIMEStateSetOpenName(IMEState::Open aO
     case IMEState::CLOSED:
       return "CLOSED";
     default:
       return "illegal value";
   }
 }
 
 static const char*
-GetEventStructName(nsEventStructType aEventStructType)
+GetEventClassIDName(EventClassID aEventClassID)
 {
-  switch (aEventStructType) {
-    case NS_COMPOSITION_EVENT:
-      return "NS_COMPOSITION_EVENT";
-    case NS_TEXT_EVENT:
-      return "NS_TEXT_EVENT";
+  switch (aEventClassID) {
+    case eCompositionEventClass:
+      return "eCompositionEventClass";
+    case eTextEventClass:
+      return "eTextEventClass";
     default:
       return "unacceptable event struct type";
   }
 }
 
 static const char*
 GetEventMessageName(uint32_t aMessage)
 {
@@ -845,26 +845,26 @@ void
 IMEStateManager::DispatchCompositionEvent(nsINode* aEventTargetNode,
                                           nsPresContext* aPresContext,
                                           WidgetEvent* aEvent,
                                           nsEventStatus* aStatus,
                                           EventDispatchingCallback* aCallBack)
 {
   PR_LOG(sISMLog, PR_LOG_ALWAYS,
     ("ISM: IMEStateManager::DispatchCompositionEvent(aNode=0x%p, "
-     "aPresContext=0x%p, aEvent={ eventStructType=%s, message=%s, "
+     "aPresContext=0x%p, aEvent={ mClass=%s, message=%s, "
      " mFlags={ mIsTrusted=%s, mPropagationStopped=%s } })",
      aEventTargetNode, aPresContext,
-     GetEventStructName(aEvent->eventStructType),
+     GetEventClassIDName(aEvent->mClass),
      GetEventMessageName(aEvent->message),
      GetBoolName(aEvent->mFlags.mIsTrusted),
      GetBoolName(aEvent->mFlags.mPropagationStopped)));
 
-  MOZ_ASSERT(aEvent->eventStructType == NS_COMPOSITION_EVENT ||
-             aEvent->eventStructType == NS_TEXT_EVENT);
+  MOZ_ASSERT(aEvent->mClass == eCompositionEventClass ||
+             aEvent->mClass == eTextEventClass);
   if (!aEvent->mFlags.mIsTrusted || aEvent->mFlags.mPropagationStopped) {
     return;
   }
 
   EnsureTextCompositionArray();
 
   WidgetGUIEvent* GUIEvent = aEvent->AsGUIEvent();
 
--- a/dom/events/InputEvent.cpp
+++ b/dom/events/InputEvent.cpp
@@ -11,17 +11,17 @@ namespace mozilla {
 namespace dom {
 
 InputEvent::InputEvent(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        InternalEditorInputEvent* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent : new InternalEditorInputEvent(false, 0, nullptr))
 {
-  NS_ASSERTION(mEvent->eventStructType == NS_EDITOR_INPUT_EVENT,
+  NS_ASSERTION(mEvent->mClass == eEditorInputEventClass,
                "event type mismatch");
 
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
   }
--- a/dom/events/InternalMutationEvent.h
+++ b/dom/events/InternalMutationEvent.h
@@ -13,26 +13,26 @@
 
 namespace mozilla {
 
 class InternalMutationEvent : public WidgetEvent
 {
 public:
   virtual InternalMutationEvent* AsMutationEvent() MOZ_OVERRIDE { return this; }
 
-  InternalMutationEvent(bool aIsTrusted, uint32_t aMessage) :
-    WidgetEvent(aIsTrusted, aMessage, NS_MUTATION_EVENT),
-    mAttrChange(0)
+  InternalMutationEvent(bool aIsTrusted, uint32_t aMessage)
+    : WidgetEvent(aIsTrusted, aMessage, eMutationEventClass)
+    , mAttrChange(0)
   {
     mFlags.mCancelable = false;
   }
 
   virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
   {
-    MOZ_ASSERT(eventStructType == NS_MUTATION_EVENT,
+    MOZ_ASSERT(mClass == eMutationEventClass,
                "Duplicate() must be overridden by sub class");
     InternalMutationEvent* result = new InternalMutationEvent(false, message);
     result->AssignMutationEventData(*this, true);
     result->mFlags = mFlags;
     return result;
   }
 
   nsCOMPtr<nsIDOMNode> mRelatedNode;
--- a/dom/events/KeyboardEvent.cpp
+++ b/dom/events/KeyboardEvent.cpp
@@ -14,17 +14,17 @@ namespace dom {
 KeyboardEvent::KeyboardEvent(EventTarget* aOwner,
                              nsPresContext* aPresContext,
                              WidgetKeyboardEvent* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent : new WidgetKeyboardEvent(false, 0, nullptr))
   , mInitializedByCtor(false)
   , mInitialzedWhichValue(0)
 {
-  NS_ASSERTION(mEvent->eventStructType == NS_KEY_EVENT, "event type mismatch");
+  NS_ASSERTION(mEvent->mClass == eKeyboardEventClass, "event type mismatch");
 
   if (aEvent) {
     mEventIsInternal = false;
   }
   else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
     mEvent->AsKeyboardEvent()->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
--- a/dom/events/MouseEvent.cpp
+++ b/dom/events/MouseEvent.cpp
@@ -64,23 +64,23 @@ MouseEvent::InitMouseEvent(const nsAStri
                            bool aMetaKey,
                            uint16_t aButton,
                            nsIDOMEventTarget* aRelatedTarget)
 {
   nsresult rv =
     UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  switch(mEvent->eventStructType) {
-    case NS_MOUSE_EVENT:
-    case NS_MOUSE_SCROLL_EVENT:
-    case NS_WHEEL_EVENT:
-    case NS_DRAG_EVENT:
-    case NS_POINTER_EVENT:
-    case NS_SIMPLE_GESTURE_EVENT: {
+  switch(mEvent->mClass) {
+    case eMouseEventClass:
+    case eMouseScrollEventClass:
+    case eWheelEventClass:
+    case eDragEventClass:
+    case ePointerEventClass:
+    case eSimpleGestureEventClass: {
       WidgetMouseEventBase* mouseEventBase = mEvent->AsMouseEventBase();
       mouseEventBase->relatedTarget = aRelatedTarget;
       mouseEventBase->button = aButton;
       mouseEventBase->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
       mClientPoint.x = aClientX;
       mClientPoint.y = aClientY;
       mouseEventBase->refPoint.x = aScreenX;
       mouseEventBase->refPoint.y = aScreenY;
@@ -118,23 +118,23 @@ MouseEvent::InitMouseEvent(const nsAStri
                                aDetail, aScreenX, aScreenY, aClientX, aClientY,
                                (modifiers & MODIFIER_CONTROL) != 0,
                                (modifiers & MODIFIER_ALT) != 0,
                                (modifiers & MODIFIER_SHIFT) != 0,
                                (modifiers & MODIFIER_META) != 0,
                                aButton, aRelatedTarget);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  switch(mEvent->eventStructType) {
-    case NS_MOUSE_EVENT:
-    case NS_MOUSE_SCROLL_EVENT:
-    case NS_WHEEL_EVENT:
-    case NS_DRAG_EVENT:
-    case NS_POINTER_EVENT:
-    case NS_SIMPLE_GESTURE_EVENT:
+  switch(mEvent->mClass) {
+    case eMouseEventClass:
+    case eMouseScrollEventClass:
+    case eWheelEventClass:
+    case eDragEventClass:
+    case ePointerEventClass:
+    case eSimpleGestureEventClass:
       mEvent->AsInputEvent()->modifiers = modifiers;
       return NS_OK;
     default:
       MOZ_CRASH("There is no space to store the modifiers");
   }
 }
 
 already_AddRefed<MouseEvent>
@@ -149,23 +149,23 @@ MouseEvent::Constructor(const GlobalObje
   e->InitMouseEvent(aType, aParam.mBubbles, aParam.mCancelable,
                     aParam.mView, aParam.mDetail, aParam.mScreenX,
                     aParam.mScreenY, aParam.mClientX, aParam.mClientY,
                     aParam.mCtrlKey, aParam.mAltKey, aParam.mShiftKey,
                     aParam.mMetaKey, aParam.mButton, aParam.mRelatedTarget,
                     aRv);
   e->SetTrusted(trusted);
 
-  switch (e->mEvent->eventStructType) {
-    case NS_MOUSE_EVENT:
-    case NS_MOUSE_SCROLL_EVENT:
-    case NS_WHEEL_EVENT:
-    case NS_DRAG_EVENT:
-    case NS_POINTER_EVENT:
-    case NS_SIMPLE_GESTURE_EVENT:
+  switch (e->mEvent->mClass) {
+    case eMouseEventClass:
+    case eMouseScrollEventClass:
+    case eWheelEventClass:
+    case eDragEventClass:
+    case ePointerEventClass:
+    case eSimpleGestureEventClass:
       e->mEvent->AsMouseEventBase()->buttons = aParam.mButtons;
       break;
     default:
       break;
   }
 
   return e.forget();
 }
@@ -208,24 +208,23 @@ MouseEvent::GetButton(int16_t* aButton)
   NS_ENSURE_ARG_POINTER(aButton);
   *aButton = Button();
   return NS_OK;
 }
 
 int16_t
 MouseEvent::Button()
 {
-  switch(mEvent->eventStructType)
-  {
-    case NS_MOUSE_EVENT:
-    case NS_MOUSE_SCROLL_EVENT:
-    case NS_WHEEL_EVENT:
-    case NS_DRAG_EVENT:
-    case NS_POINTER_EVENT:
-    case NS_SIMPLE_GESTURE_EVENT:
+  switch(mEvent->mClass) {
+    case eMouseEventClass:
+    case eMouseScrollEventClass:
+    case eWheelEventClass:
+    case eDragEventClass:
+    case ePointerEventClass:
+    case eSimpleGestureEventClass:
       return mEvent->AsMouseEventBase()->button;
     default:
       NS_WARNING("Tried to get mouse button for non-mouse event!");
       return WidgetMouseEvent::eLeftButton;
   }
 }
 
 NS_IMETHODIMP
@@ -234,24 +233,23 @@ MouseEvent::GetButtons(uint16_t* aButton
   NS_ENSURE_ARG_POINTER(aButtons);
   *aButtons = Buttons();
   return NS_OK;
 }
 
 uint16_t
 MouseEvent::Buttons()
 {
-  switch(mEvent->eventStructType)
-  {
-    case NS_MOUSE_EVENT:
-    case NS_MOUSE_SCROLL_EVENT:
-    case NS_WHEEL_EVENT:
-    case NS_DRAG_EVENT:
-    case NS_POINTER_EVENT:
-    case NS_SIMPLE_GESTURE_EVENT:
+  switch(mEvent->mClass) {
+    case eMouseEventClass:
+    case eMouseScrollEventClass:
+    case eWheelEventClass:
+    case eDragEventClass:
+    case ePointerEventClass:
+    case eSimpleGestureEventClass:
       return mEvent->AsMouseEventBase()->buttons;
     default:
       MOZ_CRASH("Tried to get mouse buttons for non-mouse event!");
   }
 }
 
 NS_IMETHODIMP
 MouseEvent::GetRelatedTarget(nsIDOMEventTarget** aRelatedTarget)
@@ -260,24 +258,23 @@ MouseEvent::GetRelatedTarget(nsIDOMEvent
   *aRelatedTarget = GetRelatedTarget().take();
   return NS_OK;
 }
 
 already_AddRefed<EventTarget>
 MouseEvent::GetRelatedTarget()
 {
   nsCOMPtr<EventTarget> relatedTarget;
-  switch(mEvent->eventStructType)
-  {
-    case NS_MOUSE_EVENT:
-    case NS_MOUSE_SCROLL_EVENT:
-    case NS_WHEEL_EVENT:
-    case NS_DRAG_EVENT:
-    case NS_POINTER_EVENT:
-    case NS_SIMPLE_GESTURE_EVENT:
+  switch(mEvent->mClass) {
+    case eMouseEventClass:
+    case eMouseScrollEventClass:
+    case eWheelEventClass:
+    case eDragEventClass:
+    case ePointerEventClass:
+    case eSimpleGestureEventClass:
       relatedTarget =
         do_QueryInterface(mEvent->AsMouseEventBase()->relatedTarget);
       break;
     default:
       break;
   }
 
   if (relatedTarget) {
--- a/dom/events/PointerEvent.cpp
+++ b/dom/events/PointerEvent.cpp
@@ -13,18 +13,18 @@ namespace mozilla {
 namespace dom {
 
 PointerEvent::PointerEvent(EventTarget* aOwner,
                            nsPresContext* aPresContext,
                            WidgetPointerEvent* aEvent)
   : MouseEvent(aOwner, aPresContext,
                aEvent ? aEvent : new WidgetPointerEvent(false, 0, nullptr))
 {
-  NS_ASSERTION(mEvent->eventStructType == NS_POINTER_EVENT,
-               "event type mismatch NS_POINTER_EVENT");
+  NS_ASSERTION(mEvent->mClass == ePointerEventClass,
+               "event type mismatch ePointerEventClass");
 
   WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
     mEvent->refPoint.x = mEvent->refPoint.y = 0;
--- a/dom/events/SimpleGestureEvent.cpp
+++ b/dom/events/SimpleGestureEvent.cpp
@@ -12,17 +12,18 @@ namespace dom {
 
 SimpleGestureEvent::SimpleGestureEvent(EventTarget* aOwner,
                                        nsPresContext* aPresContext,
                                        WidgetSimpleGestureEvent* aEvent)
   : MouseEvent(aOwner, aPresContext,
                aEvent ? aEvent :
                         new WidgetSimpleGestureEvent(false, 0, nullptr))
 {
-  NS_ASSERTION(mEvent->eventStructType == NS_SIMPLE_GESTURE_EVENT, "event type mismatch");
+  NS_ASSERTION(mEvent->mClass == eSimpleGestureEventClass,
+               "event type mismatch");
 
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
     mEvent->refPoint.x = mEvent->refPoint.y = 0;
     static_cast<WidgetMouseEventBase*>(mEvent)->inputSource =
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -105,17 +105,17 @@ TextComposition::NotityUpdateComposition
     if (selectedTextEvent.mSucceeded) {
       mCompositionStartOffset = selectedTextEvent.mReply.mOffset;
     } else {
       // Unknown offset
       NS_WARNING("Cannot get start offset of IME composition");
       mCompositionStartOffset = 0;
     }
     mCompositionTargetOffset = mCompositionStartOffset;
-  } else if (aEvent->eventStructType != NS_TEXT_EVENT) {
+  } else if (aEvent->mClass != eTextEventClass) {
     return;
   } else {
     mCompositionTargetOffset =
       mCompositionStartOffset + aEvent->AsTextEvent()->TargetClauseOffset();
   }
 
   NotifyIME(NOTIFY_IME_OF_COMPOSITION_UPDATE);
 }
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -41,25 +41,24 @@ UIEvent::UIEvent(EventTarget* aOwner,
   }
   else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
   }
   
   // Fill mDetail and mView according to the mEvent (widget-generated
   // event) we've got
-  switch(mEvent->eventStructType)
-  {
-    case NS_UI_EVENT:
+  switch(mEvent->mClass) {
+    case eUIEventClass:
     {
       mDetail = mEvent->AsUIEvent()->detail;
       break;
     }
 
-    case NS_SCROLLPORT_EVENT:
+    case eScrollPortEventClass:
     {
       InternalScrollPortEvent* scrollEvent = mEvent->AsScrollPortEvent();
       mDetail = (int32_t)scrollEvent->orient;
       break;
     }
 
     default:
       mDetail = 0;
@@ -114,22 +113,22 @@ DevPixelsToCSSPixels(const LayoutDeviceI
 nsIntPoint
 UIEvent::GetMovementPoint()
 {
   if (mPrivateDataDuplicated) {
     return mMovementPoint;
   }
 
   if (!mEvent ||
-      (mEvent->eventStructType != NS_MOUSE_EVENT &&
-       mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
-       mEvent->eventStructType != NS_WHEEL_EVENT &&
-       mEvent->eventStructType != NS_DRAG_EVENT &&
-       mEvent->eventStructType != NS_POINTER_EVENT &&
-       mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
+      (mEvent->mClass != eMouseEventClass &&
+       mEvent->mClass != eMouseScrollEventClass &&
+       mEvent->mClass != eWheelEventClass &&
+       mEvent->mClass != eDragEventClass &&
+       mEvent->mClass != ePointerEventClass &&
+       mEvent->mClass != eSimpleGestureEventClass) ||
        !mEvent->AsGUIEvent()->widget) {
     return nsIntPoint(0, 0);
   }
 
   // Calculate the delta between the last screen point and the current one.
   nsIntPoint current = DevPixelsToCSSPixels(mEvent->refPoint, mPresContext);
   nsIntPoint last = DevPixelsToCSSPixels(mEvent->lastRefPoint, mPresContext);
   return current - last;
@@ -292,23 +291,23 @@ UIEvent::SetCancelBubble(bool aCancelBub
   mEvent->mFlags.mPropagationStopped = aCancelBubble;
   return NS_OK;
 }
 
 nsIntPoint
 UIEvent::GetLayerPoint() const
 {
   if (!mEvent ||
-      (mEvent->eventStructType != NS_MOUSE_EVENT &&
-       mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
-       mEvent->eventStructType != NS_WHEEL_EVENT &&
-       mEvent->eventStructType != NS_POINTER_EVENT &&
-       mEvent->eventStructType != NS_TOUCH_EVENT &&
-       mEvent->eventStructType != NS_DRAG_EVENT &&
-       mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
+      (mEvent->mClass != eMouseEventClass &&
+       mEvent->mClass != eMouseScrollEventClass &&
+       mEvent->mClass != eWheelEventClass &&
+       mEvent->mClass != ePointerEventClass &&
+       mEvent->mClass != eTouchEventClass &&
+       mEvent->mClass != eDragEventClass &&
+       mEvent->mClass != eSimpleGestureEventClass) ||
       !mPresContext ||
       mEventIsInternal) {
     return mLayerPoint;
   }
   // XXX I'm not really sure this is correct; it's my best shot, though
   nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
   if (!targetFrame)
     return mLayerPoint;
--- a/dom/events/UIEvent.h
+++ b/dom/events/UIEvent.h
@@ -38,22 +38,22 @@ public:
   NS_IMETHOD DuplicatePrivateData() MOZ_OVERRIDE;
   NS_IMETHOD_(void) Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType) MOZ_OVERRIDE;
   NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg, void** aIter) MOZ_OVERRIDE;
 
   static nsIntPoint CalculateScreenPoint(nsPresContext* aPresContext,
                                          WidgetEvent* aEvent)
   {
     if (!aEvent ||
-        (aEvent->eventStructType != NS_MOUSE_EVENT &&
-         aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
-         aEvent->eventStructType != NS_WHEEL_EVENT &&
-         aEvent->eventStructType != NS_DRAG_EVENT &&
-         aEvent->eventStructType != NS_POINTER_EVENT &&
-         aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
+        (aEvent->mClass != eMouseEventClass &&
+         aEvent->mClass != eMouseScrollEventClass &&
+         aEvent->mClass != eWheelEventClass &&
+         aEvent->mClass != eDragEventClass &&
+         aEvent->mClass != ePointerEventClass &&
+         aEvent->mClass != eSimpleGestureEventClass)) {
       return nsIntPoint(0, 0);
     }
 
     WidgetGUIEvent* event = aEvent->AsGUIEvent();
     if (!event->widget) {
       return LayoutDeviceIntPoint::ToUntyped(aEvent->refPoint);
     }
 
@@ -65,22 +65,22 @@ public:
                       nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
   }
 
   static CSSIntPoint CalculateClientPoint(nsPresContext* aPresContext,
                                           WidgetEvent* aEvent,
                                           CSSIntPoint* aDefaultClientPoint)
   {
     if (!aEvent ||
-        (aEvent->eventStructType != NS_MOUSE_EVENT &&
-         aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
-         aEvent->eventStructType != NS_WHEEL_EVENT &&
-         aEvent->eventStructType != NS_DRAG_EVENT &&
-         aEvent->eventStructType != NS_POINTER_EVENT &&
-         aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
+        (aEvent->mClass != eMouseEventClass &&
+         aEvent->mClass != eMouseScrollEventClass &&
+         aEvent->mClass != eWheelEventClass &&
+         aEvent->mClass != eDragEventClass &&
+         aEvent->mClass != ePointerEventClass &&
+         aEvent->mClass != eSimpleGestureEventClass) ||
         !aPresContext ||
         !aEvent->AsGUIEvent()->widget) {
       return aDefaultClientPoint
              ? *aDefaultClientPoint
              : CSSIntPoint(0, 0);
     }
 
     nsIPresShell* shell = aPresContext->GetPresShell();
@@ -127,19 +127,19 @@ public:
     return GetLayerPoint().y;
   }
 
   int32_t PageX() const;
   int32_t PageY() const;
 
   virtual uint32_t Which()
   {
-    MOZ_ASSERT(mEvent->eventStructType != NS_KEY_EVENT,
+    MOZ_ASSERT(mEvent->mClass != eKeyboardEventClass,
                "Key events should override Which()");
-    MOZ_ASSERT(mEvent->eventStructType != NS_MOUSE_EVENT,
+    MOZ_ASSERT(mEvent->mClass != eMouseEventClass,
                "Mouse events should override Which()");
     return 0;
   }
 
   already_AddRefed<nsINode> GetRangeParent();
 
   int32_t RangeOffset() const;
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -774,17 +774,17 @@ TabParent::MapEventCoordinatesForChildPr
   MapEventCoordinatesForChildProcess(offset, aEvent);
   return true;
 }
 
 void
 TabParent::MapEventCoordinatesForChildProcess(
   const LayoutDeviceIntPoint& aOffset, WidgetEvent* aEvent)
 {
-  if (aEvent->eventStructType != NS_TOUCH_EVENT) {
+  if (aEvent->mClass != eTouchEventClass) {
     aEvent->refPoint = aOffset;
   } else {
     aEvent->refPoint = LayoutDeviceIntPoint();
     // Then offset all the touch points by that distance, to put them
     // in the space where top-left is 0,0.
     const WidgetTouchEvent::TouchArray& touches =
       aEvent->AsTouchEvent()->touches;
     for (uint32_t i = 0; i < touches.Length(); ++i) {
@@ -1010,17 +1010,17 @@ TabParent::GetEventCapturer()
   return sEventCapturer;
 }
 
 bool
 TabParent::TryCapture(const WidgetGUIEvent& aEvent)
 {
   MOZ_ASSERT(sEventCapturer == this && mEventCaptureDepth > 0);
 
-  if (aEvent.eventStructType != NS_TOUCH_EVENT) {
+  if (aEvent.mClass != eTouchEventClass) {
     // Only capture of touch events is implemented, for now.
     return false;
   }
 
   WidgetTouchEvent event(*aEvent.AsTouchEvent());
 
   bool isTouchPointUp = (event.message == NS_TOUCH_END ||
                          event.message == NS_TOUCH_CANCEL);
@@ -2077,17 +2077,17 @@ TabParent::InjectTouchEvent(const nsAStr
                             uint32_t* aRxs,
                             uint32_t* aRys,
                             float* aRotationAngles,
                             float* aForces,
                             uint32_t aCount,
                             int32_t aModifiers)
 {
   uint32_t msg;
-  nsContentUtils::GetEventIdAndAtom(aType, NS_TOUCH_EVENT, &msg);
+  nsContentUtils::GetEventIdAndAtom(aType, eTouchEventClass, &msg);
   if (msg != NS_TOUCH_START && msg != NS_TOUCH_MOVE &&
       msg != NS_TOUCH_END && msg != NS_TOUCH_CANCEL) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return NS_ERROR_FAILURE;
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -49,16 +49,23 @@
 #include "MediaEngineWebRTC.h"
 #include "browser_logging/WebRtcLog.h"
 #endif
 
 #ifdef MOZ_B2G
 #include "MediaPermissionGonk.h"
 #endif
 
+#if defined(XP_MACOSX)
+#include "nsCocoaFeatures.h"
+#endif
+#if defined (XP_WIN)
+#include "mozilla/WindowsVersion.h"
+#endif
+
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount() and conflicts with MediaStream::GetCurrentTime.
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 
 // XXX Workaround for bug 986974 to maintain the existing broken semantics
 template<>
@@ -1569,17 +1576,25 @@ MediaManager::GetUserMedia(bool aPrivile
         if (!Preferences::GetBool("media.getusermedia.browser.enabled", false)) {
           return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
         }
       } else if (!Preferences::GetBool("media.getusermedia.screensharing.enabled", false)) {
         return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
       }
       /* Deny screensharing if the requesting document is not from a host
        on the whitelist. */
-      if (!aPrivileged && !HostHasPermission(*docURI)) {
+      // Block screen/window sharing on Mac OSX 10.6 and WinXP until proved that they work
+      if (
+#if defined(XP_MACOSX)
+          !nsCocoaFeatures::OnLionOrLater() ||
+#endif
+#if defined (XP_WIN)
+          !IsVistaOrLater() ||
+#endif
+          (!aPrivileged && !HostHasPermission(*docURI))) {
         return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
       }
     }
   }
 
 #ifdef MOZ_B2G_CAMERA
   if (mCameraManager == nullptr) {
     mCameraManager = nsDOMCameraManager::CreateInstance(aWindow);
--- a/dom/media/tests/mochitest/head.js
+++ b/dom/media/tests/mochitest/head.js
@@ -128,17 +128,19 @@ function runTest(aCallback) {
   if (window.SimpleTest) {
     // Running as a Mochitest.
     SimpleTest.waitForExplicitFinish();
     SpecialPowers.pushPrefEnv({'set': [
       ['dom.messageChannel.enabled', true],
       ['media.peerconnection.enabled', true],
       ['media.peerconnection.identity.enabled', true],
       ['media.peerconnection.identity.timeout', 12000],
-      ['media.navigator.permission.disabled', true]]
+      ['media.navigator.permission.disabled', true],
+      ['media.getusermedia.screensharing.enabled', true],
+      ['media.getusermedia.screensharing.allowed_domains', "mochi.test"]]
     }, function () {
       try {
         aCallback();
       }
       catch (err) {
         generateErrorCallback()(err);
       }
     });
@@ -265,8 +267,24 @@ function unexpectedEventAndFinish(messag
   stack.shift(); // Don't include this instantiation frame
 
   return function () {
     ok(false, "Unexpected event '" + eventName + "' fired with message = '" +
        message + "' at: " + JSON.stringify(stack));
     SimpleTest.finish();
   }
 }
+
+function IsMacOSX10_6orOlder() {
+    var is106orOlder = false;
+
+    if (navigator.platform.indexOf("Mac") == 0) {
+        var version = Cc["@mozilla.org/system-info;1"]
+                        .getService(SpecialPowers.Ci.nsIPropertyBag2)
+                        .getProperty("version");
+        // the next line is correct: Mac OS 10.6 corresponds to Darwin version 10.x !
+        // Mac OS 10.7 is Darwin version 11.x. the |version| string we've got here
+        // is the Darwin version.
+        is106orOlder = (parseFloat(version) < 11.0);
+    }
+    return is106orOlder;
+}
+
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -21,19 +21,19 @@ skip-if = toolkit == 'gonk' # b2g(Bug 96
 [test_dataChannel_bug1013809.html]
 skip-if = (toolkit == 'gonk' && debug) # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
 [test_dataChannel_noOffer.html]
 [test_getUserMedia_basicAudio.html]
 skip-if = (toolkit == 'gonk' && debug) # debug-only failure
 [test_getUserMedia_basicVideo.html]
 skip-if = (toolkit == 'gonk' && debug) # debug-only failure
 [test_getUserMedia_basicScreenshare.html]
-skip-if = toolkit == 'gonk' || toolkit == 'android' # no screenshare on b2g/android
+skip-if = buildapp == 'b2g' || toolkit == 'android' # no screenshare on b2g/android
 [test_getUserMedia_basicWindowshare.html]
-skip-if = toolkit == 'gonk' || toolkit == 'android' # no windowshare on b2g/android
+skip-if = buildapp == 'b2g' || toolkit == 'android' # no windowshare on b2g/android
 [test_getUserMedia_basicVideoAudio.html]
 skip-if = (toolkit == 'gonk' && debug) # debug-only failure, turned an intermittent (bug 962579) into a permanant orange
 [test_getUserMedia_constraints.html]
 skip-if = toolkit == 'gonk' || toolkit == 'android' # Bug 907352, backwards-compatible behavior on mobile only
 [test_getUserMedia_constraints_mobile.html]
 skip-if = toolkit != 'gonk' && toolkit != 'android' # Bug 907352, backwards-compatible behavior on mobile only
 [test_getUserMedia_exceptions.html]
 [test_getUserMedia_gumWithinGum.html]
@@ -55,19 +55,23 @@ skip-if = toolkit == 'gonk' # b2g(Bug 10
 skip-if = (toolkit == 'gonk' && debug) # Bug 962984, test fail on b2g debug build
 [test_peerConnection_basicAudioVideo.html]
 skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_basicAudioVideoCombined.html]
 skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_basicVideo.html]
 skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_basicScreenshare.html]
-skip-if = toolkit == 'gonk' || toolkit == 'android' # no screenshare on b2g/android
+# no screenshare on b2g/android
+# frequent timeouts/crashes on e10s (bug 1048455)
+skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
 [test_peerConnection_basicWindowshare.html]
-skip-if = toolkit == 'gonk' || toolkit == 'android' # no windowshare on b2g/android
+# no screenshare on b2g/android
+# frequent timeouts/crashes on e10s (bug 1048455)
+skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
 [test_peerConnection_basicH264Video.html]
 skip-if = buildapp == 'b2g' || os == 'android' # bug 1043403
 [test_peerConnection_bug822674.html]
 [test_peerConnection_bug825703.html]
 [test_peerConnection_bug827843.html]
 skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_bug834153.html]
 [test_peerConnection_bug835370.html]
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
+const LOOPBACK_ADDR = "127.0.0.";
 
 const iceStateTransitions = {
   "new": ["checking", "closed"], //Note: 'failed' might need to added here
                                  //      even though it is not in the standard
   "checking": ["new", "connected", "failed", "closed"], //Note: do we need to
                                                         // allow 'completed' in
                                                         // here as well?
   "connected": ["new", "completed", "disconnected", "closed"],
@@ -750,19 +751,19 @@ PeerConnectionTest.prototype.setMediaCon
 function PCT_setMediaConstraints(constraintsLocal, constraintsRemote) {
   if (this.pcLocal)
     this.pcLocal.constraints = constraintsLocal;
   if (this.pcRemote)
     this.pcRemote.constraints = constraintsRemote;
 };
 
 /**
- * Sets the media constraints used on a createOffer call in the test.
+ * Sets the media options used on a createOffer call in the test.
  *
- * @param {object} constraints the media constraints to use on createOffer
+ * @param {object} options the media constraints to use on createOffer
  */
 PeerConnectionTest.prototype.setOfferOptions =
 function PCT_setOfferOptions(options) {
   if (this.pcLocal)
     this.pcLocal.offerOptions = options;
 };
 
 /**
@@ -1891,16 +1892,34 @@ PeerConnectionWrapper.prototype = {
       if (constraints[i].audio) {
         audioTracks++;
       }
     }
     return audioTracks;
   },
 
   /**
+   * Checks for audio in given offer options.
+   *
+   * @param options
+   *        The options to be examined.
+   */
+  audioInOfferOptions : function
+    PCW_audioInOfferOptions(options) {
+    if (!options) {
+      return 0;
+    }
+    if (options.offerToReceiveAudio) {
+      return 1;
+    } else {
+      return 0;
+    }
+  },
+
+  /**
    * Counts the amount of video tracks in a given media constraint.
    *
    * @param constraint
    *        The contraint to be examined.
    */
   countVideoTracksInMediaConstraint : function
     PCW_countVideoTracksInMediaConstraint(constraints) {
     if ((!constraints) || (constraints.length === 0)) {
@@ -1910,16 +1929,34 @@ PeerConnectionWrapper.prototype = {
     for (var i = 0; i < constraints.length; i++) {
       if (constraints[i].video) {
         videoTracks++;
       }
     }
     return videoTracks;
   },
 
+  /**
+   * Checks for video in given offer options.
+   *
+   * @param options
+   *        The options to be examined.
+   */
+  videoInOfferOptions : function
+    PCW_videoInOfferOptions(options) {
+    if (!options) {
+      return 0;
+    }
+    if (options.offerToReceiveVideo) {
+      return 1;
+    } else {
+      return 0;
+    }
+  },
+
   /*
    * Counts the amount of audio tracks in a given set of streams.
    *
    * @param streams
    *        An array of streams (as returned by getLocalStreams()) to be
    *        examined.
    */
   countAudioTracksInStreams : function PCW_countAudioTracksInStreams(streams) {
@@ -2015,16 +2052,69 @@ PeerConnectionWrapper.prototype = {
         ok(self.onAddStreamFired, self + " checkMediaTracks() timed out waiting for onaddstream event to fire");
         if (!self.onAddStreamFired) {
           onSuccess();
         }
       }, 60000);
     }
   },
 
+  verifySdp : function PCW_verifySdp(desc, expectedType, constraints, offerOptions) {
+    info("Examining this SessionDescription: " + JSON.stringify(desc));
+    info("constraints: " + JSON.stringify(constraints));
+    info("offerOptions: " + JSON.stringify(offerOptions));
+    ok(desc, "SessionDescription is not null");
+    is(desc.type, expectedType, "SessionDescription type is " + expectedType);
+    ok(desc.sdp.length > 10, "SessionDescription body length is plausible");
+    ok(desc.sdp.contains("a=ice-ufrag"), "ICE username is present in SDP");
+    ok(desc.sdp.contains("a=ice-pwd"), "ICE password is present in SDP");
+    ok(desc.sdp.contains("a=fingerprint"), "ICE fingerprint is present in SDP");
+    //TODO: update this for loopback support bug 1027350
+    ok(!desc.sdp.contains(LOOPBACK_ADDR), "loopback interface is absent from SDP");
+    //TODO: update this for trickle ICE bug 1041832
+    ok(desc.sdp.contains("a=candidate"), "at least one ICE candidate is present in SDP");
+    //TODO: how can we check for absence/presence of m=application?
+
+    //TODO: how to handle media contraints + offer options
+    var audioTracks = this.countAudioTracksInMediaConstraint(constraints);
+    if (constraints.length === 0) {
+      audioTracks = this.audioInOfferOptions(offerOptions);
+    }
+    info("expected audio tracks: " + audioTracks);
+    if (audioTracks == 0) {
+      ok(!desc.sdp.contains("m=audio"), "audio m-line is absent from SDP");
+    } else {
+      ok(desc.sdp.contains("m=audio"), "audio m-line is present in SDP");
+      ok(desc.sdp.contains("a=rtpmap:109 opus/48000/2"), "OPUS codec is present in SDP");
+      //TODO: ideally the rtcp-mux should be for the m=audio, and not just
+      //      anywhere in the SDP (JS SDP parser bug 1045429)
+      ok(desc.sdp.contains("a=rtcp-mux"), "RTCP Mux is offered in SDP");
+
+    }
+
+    //TODO: how to handle media contraints + offer options
+    var videoTracks = this.countVideoTracksInMediaConstraint(constraints);
+    if (constraints.length === 0) {
+      videoTracks = this.videoInOfferOptions(offerOptions);
+    }
+    info("expected video tracks: " + videoTracks);
+    if (videoTracks == 0) {
+      ok(!desc.sdp.contains("m=video"), "video m-line is absent from SDP");
+    } else {
+      ok(desc.sdp.contains("m=video"), "video m-line is present in SDP");
+      if (this.h264) {
+        ok(desc.sdp.contains("a=rtpmap:126 H264/90000"), "H.264 codec is present in SDP");
+      } else {
+        ok(desc.sdp.contains("a=rtpmap:120 VP8/90000"), "VP8 codec is present in SDP");
+      }
+      ok(desc.sdp.contains("a=rtcp-mux"), "RTCP Mux is offered in SDP");
+    }
+
+  },
+
   /**
    * Check that media flow is present on all media elements involved in this
    * test by waiting for confirmation that media flow is present.
    *
    * @param {Function} onSuccess the success callback when media flow
    *                             is confirmed on all media elements
    */
   checkMediaFlowPresent : function PCW_checkMediaFlowPresent(onSuccess) {
--- a/dom/media/tests/mochitest/templates.js
+++ b/dom/media/tests/mochitest/templates.js
@@ -120,22 +120,23 @@ var commandsPeerConnection = [
       is(test.pcRemote.iceConnectionState, ICE_NEW,
         "Initial remote ICE connection state is 'new'");
       test.next();
     }
   ],
   [
     'PC_LOCAL_CREATE_OFFER',
     function (test) {
-      test.createOffer(test.pcLocal, function () {
+      test.createOffer(test.pcLocal, function (offer) {
         is(test.pcLocal.signalingState, STABLE,
            "Local create offer does not change signaling state");
         if (!test.pcRemote) {
           send_message({"offer": test.pcLocal._last_offer,
-                        "media_constraints": test.pcLocal.constraints});
+                        "offer_constraints": test.pcLocal.constraints,
+                        "offer_options": test.pcLocal.offerOptions});
         }
         test.next();
       });
     }
   ],
   [
     'PC_LOCAL_SET_LOCAL_DESCRIPTION',
     function (test) {
@@ -146,47 +147,63 @@ var commandsPeerConnection = [
       });
     }
   ],
   [
     'PC_REMOTE_GET_OFFER',
     function (test) {
       if (test.pcLocal) {
         test._local_offer = test.pcLocal._last_offer;
-        test._local_constraints = test.pcLocal.constraints;
+        test._offer_constraints = test.pcLocal.constraints;
+        test._offer_options = test.pcLocal.offerOptions;
         test.next();
       } else {
         wait_for_message().then(function(message) {
           ok("offer" in message, "Got an offer message");
           test._local_offer = new mozRTCSessionDescription(message.offer);
-          test._local_constraints = message.media_constraints;
+          test._offer_constraints = message.offer_constraints;
+          test._offer_options = message.offer_options;
           test.next();
         });
       }
     }
   ],
   [
     'PC_REMOTE_SET_REMOTE_DESCRIPTION',
     function (test) {
       test.setRemoteDescription(test.pcRemote, test._local_offer, HAVE_REMOTE_OFFER, function () {
         is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
            "signalingState after remote setRemoteDescription is 'have-remote-offer'");
         test.next();
       });
     }
   ],
   [
+    'PC_LOCAL_SANE_LOCAL_SDP',
+    function (test) {
+      test.pcLocal.verifySdp(test.pcLocal.localDescription, "offer", test._offer_constraints, test._offer_options);
+      test.next();
+    }
+  ],
+  [
+    'PC_REMOTE_SANE_REMOTE_SDP',
+    function (test) {
+      test.pcRemote.verifySdp(test.pcRemote.remoteDescription, "offer", test._offer_constraints, test._offer_options);
+      test.next();
+    }
+  ],
+  [
     'PC_REMOTE_CREATE_ANSWER',
     function (test) {
-      test.createAnswer(test.pcRemote, function () {
+      test.createAnswer(test.pcRemote, function (answer) {
         is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
            "Remote createAnswer does not change signaling state");
         if (!test.pcLocal) {
           send_message({"answer": test.pcRemote._last_answer,
-                        "media_constraints": test.pcRemote.constraints});
+                        "answer_constraints": test.pcRemote.constraints});
         }
         test.next();
       });
     }
   ],
   [
     'PC_REMOTE_CHECK_FOR_DUPLICATED_PORTS_IN_SDP',
     function (test) {
@@ -241,39 +258,53 @@ var commandsPeerConnection = [
       });
     }
   ],
   [
     'PC_LOCAL_GET_ANSWER',
     function (test) {
       if (test.pcRemote) {
         test._remote_answer = test.pcRemote._last_answer;
-        test._remote_constraints = test.pcRemote.constraints;
+        test._answer_constraints = test.pcRemote.constraints;
         test.next();
       } else {
         wait_for_message().then(function(message) {
           ok("answer" in message, "Got an answer message");
           test._remote_answer = new mozRTCSessionDescription(message.answer);
-          test._remote_constraints = message.media_constraints;
+          test._answer_constraints = message.answer_constraints;
           test.next();
         });
       }
     }
   ],
   [
     'PC_LOCAL_SET_REMOTE_DESCRIPTION',
     function (test) {
       test.setRemoteDescription(test.pcLocal, test._remote_answer, STABLE, function () {
         is(test.pcLocal.signalingState, STABLE,
            "signalingState after local setRemoteDescription is 'stable'");
         test.next();
       });
     }
   ],
   [
+    'PC_REMOTE_SANE_LOCAL_SDP',
+    function (test) {
+      test.pcRemote.verifySdp(test.pcRemote.localDescription, "answer", test._answer_constraints, test._offer_options);
+      test.next();
+    }
+  ],
+  [
+    'PC_LOCAL_SANE_REMOTE_SDP',
+    function (test) {
+      test.pcLocal.verifySdp(test.pcLocal.remoteDescription, "answer", test._answer_constraints, test._offer_options);
+      test.next();
+    }
+  ],
+  [
     'PC_LOCAL_WAIT_FOR_ICE_CONNECTED',
     function (test) {
       var myTest = test;
       var myPc = myTest.pcLocal;
 
       function onIceConnectedSuccess () {
         info("pcLocal ICE connection state log: " + test.pcLocal.iceConnectionLog);
         ok(true, "pc_local: ICE switched to 'connected' state");
@@ -326,25 +357,25 @@ var commandsPeerConnection = [
         ok(false, "pc_remote: ICE is already in bad state: " + myPc.iceConnectionState);
         myTest.next();
       }
     }
   ],
   [
     'PC_LOCAL_CHECK_MEDIA_TRACKS',
     function (test) {
-      test.pcLocal.checkMediaTracks(test._remote_constraints, function () {
+      test.pcLocal.checkMediaTracks(test._answer_constraints, function () {
         test.next();
       });
     }
   ],
   [
     'PC_REMOTE_CHECK_MEDIA_TRACKS',
     function (test) {
-      test.pcRemote.checkMediaTracks(test._local_constraints, function () {
+      test.pcRemote.checkMediaTracks(test._offer_constraints, function () {
         test.next();
       });
     }
   ],
   [
     'PC_LOCAL_CHECK_MEDIA_FLOW_PRESENT',
     function (test) {
       test.pcLocal.checkMediaFlowPresent(function () {
@@ -476,16 +507,18 @@ var commandsDataChannel = [
     }
   ],
   [
     'PC_LOCAL_CREATE_OFFER',
     function (test) {
       test.pcLocal.createOffer(function (offer) {
         is(test.pcLocal.signalingState, STABLE,
            "Local create offer does not change signaling state");
+        ok(!offer.sdp.contains(LOOPBACK_ADDR),
+           "loopback interface is absent from SDP");
         ok(offer.sdp.contains("m=application"),
            "m=application is contained in the SDP");
         test.next();
       });
     }
   ],
   [
     'PC_LOCAL_SET_LOCAL_DESCRIPTION',
@@ -505,21 +538,37 @@ var commandsDataChannel = [
         function () {
         is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
            "signalingState after remote setRemoteDescription is 'have-remote-offer'");
         test.next();
       });
     }
   ],
   [
+    'PC_LOCAL_SANE_LOCAL_SDP',
+    function (test) {
+      test.pcLocal.verifySdp(test.pcLocal.localDescription, "offer", test.pcLocal.constraints);
+      test.next();
+    }
+  ],
+  [
+    'PC_REMOTE_SANE_REMOTE_SDP',
+    function (test) {
+      test.pcRemote.verifySdp(test.pcRemote.remoteDescription, "offer", test.pcLocal.constraints);
+      test.next();
+    }
+  ],
+  [
     'PC_REMOTE_CREATE_ANSWER',
     function (test) {
-      test.createAnswer(test.pcRemote, function () {
+      test.createAnswer(test.pcRemote, function (answer) {
         is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
            "Remote create offer does not change signaling state");
+        ok(!answer.sdp.contains(LOOPBACK_ADDR),
+           "loopback interface is absent in SDP");
         test.next();
       });
     }
   ],
   [
     'PC_LOCAL_SETUP_DATA_CHANNEL_CALLBACK',
     function (test) {
       test.waitForInitialDataChannel(test.pcLocal, function () {
@@ -560,16 +609,30 @@ var commandsDataChannel = [
         function () {
         is(test.pcLocal.signalingState, STABLE,
            "signalingState after local setRemoteDescription is 'stable'");
         test.next();
       });
     }
   ],
   [
+    'PC_REMOTE_SANE_LOCAL_SDP',
+    function (test) {
+      test.pcRemote.verifySdp(test.pcRemote.localDescription, "answer", test.pcRemote.constraints);
+      test.next();
+    }
+  ],
+  [
+    'PC_LOCAL_SANE_REMOTE_SDP',
+    function (test) {
+      test.pcLocal.verifySdp(test.pcLocal.remoteDescription, "answer", test.pcRemote.constraints);
+      test.next();
+    }
+  ],
+  [
     'PC_LOCAL_WAIT_FOR_ICE_CONNECTED',
     function (test) {
       var myTest = test;
       var myPc = myTest.pcLocal;
 
       function onIceConnectedSuccess () {
         info("pcLocal ICE connection state log: " + test.pcLocal.iceConnectionLog);
         ok(true, "pc_local: ICE switched to 'connected' state");
--- a/dom/media/tests/mochitest/test_getUserMedia_basicScreenshare.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicScreenshare.html
@@ -18,27 +18,32 @@ https://bugzilla.mozilla.org/show_bug.cg
   <video id="testVideo"></video>
 </div>
 <pre id="test">
 <script type="application/javascript">
   /**
    * Run a test to verify that we can complete a start and stop media playback
    * cycle for an screenshare LocalMediaStream on a video HTMLMediaElement.
    */
+  SimpleTest.expectAssertions(0, 1); // Bug 1047842
+
   runTest(function () {
+    const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
+    if (IsMacOSX10_6orOlder() || isWinXP) {
+        ok(true, "Screensharing disabled for OSX10.6 and WinXP");
+        SimpleTest.finish();
+        return;
+    }
     var testVideo = document.getElementById('testVideo');
     var constraints = {
       video: {
-        mandatory:{
-          chromeMediaSource:'screen',
-          maxWidth:screen.availWidth,
-          maxHeight:screen.availHeight
-        },
-        optional:[]
-      }
+         mozMediaSource: "screen",
+         mediaSource: "screen"
+      },
+      fake: false
     };
 
     getUserMedia(constraints, function (aStream) {
       checkMediaStreamTracks(constraints, aStream);
 
       var playback = new LocalMediaStreamPlayback(testVideo, aStream);
       playback.playMediaWithStreamStop(false, function () {
         aStream.stop();
--- a/dom/media/tests/mochitest/test_getUserMedia_basicWindowshare.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicWindowshare.html
@@ -18,27 +18,32 @@ https://bugzilla.mozilla.org/show_bug.cg
   <video id="testVideo"></video>
 </div>
 <pre id="test">
 <script type="application/javascript">
   /**
    * Run a test to verify that we can complete a start and stop media playback
    * cycle for an screenshare LocalMediaStream on a video HTMLMediaElement.
    */
+  SimpleTest.expectAssertions(0, 1); // Bug 1047842
+
   runTest(function () {
+    const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
+    if (IsMacOSX10_6orOlder() || isWinXP) {
+        ok(true, "Screensharing disabled for OSX10.6 and WinXP");
+        SimpleTest.finish();
+        return;
+    }
     var testVideo = document.getElementById('testVideo');
     var constraints = {
       video: {
-        mandatory:{
-          chromeMediaSource:'window',
-          maxWidth:screen.availWidth,
-          maxHeight:screen.availHeight
-        },
-        optional:[]
-      }
+         mozMediaSource: "window",
+         mediaSource: "window"
+      },
+      fake: false
     };
 
     getUserMedia(constraints, function (aStream) {
       checkMediaStreamTracks(constraints, aStream);
 
       var playback = new LocalMediaStreamPlayback(testVideo, aStream);
       playback.playMediaWithStreamStop(false, function () {
         aStream.stop();
--- a/dom/media/tests/mochitest/test_peerConnection_basicScreenshare.html
+++ b/dom/media/tests/mochitest/test_peerConnection_basicScreenshare.html
@@ -12,28 +12,33 @@
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "1039666",
     title: "Basic screenshare-only peer connection"
   });
 
+  SimpleTest.expectAssertions(0, 1); // Bug 1047842
+
   var test;
   runNetworkTest(function (options) {
+    const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
+    if (IsMacOSX10_6orOlder() || isWinXP) {
+        ok(true, "Screensharing disabled for OSX10.6 and WinXP");
+        SimpleTest.finish();
+        return;
+    }
     test = new PeerConnectionTest(options);
     var constraints = {
       video: {
-        mandatory:{
-          chromeMediaSource:'screen',
-          maxWidth:screen.availWidth,
-          maxHeight:screen.availHeight
-        },
-        optional:[]
-      }
+         mozMediaSource: "screen",
+         mediaSource: "screen"
+      },
+      fake: false
     };
     test.setMediaConstraints([constraints], [constraints]);
     test.run();
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_peerConnection_basicWindowshare.html
+++ b/dom/media/tests/mochitest/test_peerConnection_basicWindowshare.html
@@ -12,28 +12,33 @@
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "1038926",
     title: "Basic windowshare-only peer connection"
   });
 
+  SimpleTest.expectAssertions(0, 1); // Bug 1047842
+
   var test;
   runNetworkTest(function (options) {
+    const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
+    if (IsMacOSX10_6orOlder() || isWinXP) {
+        ok(true, "Screensharing disabled for OSX10.6 and WinXP");
+        SimpleTest.finish();
+        return;
+    }
     test = new PeerConnectionTest(options);
     var constraints = {
       video: {
-        mandatory:{
-          chromeMediaSource:'window',
-          maxWidth:screen.availWidth,
-          maxHeight:screen.availHeight
-        },
-        optional:[]
-      }
+         mozMediaSource: "window",
+         mediaSource: "window"
+      },
+      fake: false
     };
     test.setMediaConstraints([constraints], [constraints]);
     test.run();
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_peerConnection_bug827843.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug827843.html
@@ -13,50 +13,16 @@
 <script type="application/javascript">
   createHTML({
     bug: "827843",
     title: "Ensure that localDescription and remoteDescription are null after close"
   });
 
   var steps = [
     [
-      "CHECK_FOR_SANE_SDP",
-      function (test) {
-        // TODO: We might want to move those checks into the default chain
-        ok(test.pcLocal.localDescription,
-           "test.pcLocal.localDescription is not null");
-        is(test.pcLocal.localDescription.type, "offer",
-           "test.pcLocal.localDescription type is offer");
-        ok(test.pcLocal.localDescription.sdp.length > 10,
-           "test.pcLocal.localDescription body length is plausible");
-
-        ok(test.pcLocal.remoteDescription,
-           "test.pcLocal.remoteDescription is not null");
-        is(test.pcLocal.remoteDescription.type, "answer",
-            "test.pcLocal.remoteDescription type is answer");
-        ok(test.pcLocal.remoteDescription.sdp.length > 10,
-           "test.pcLocal.remoteDescription body length is plausible");
-
-        ok(test.pcRemote.localDescription,
-           "test.pcRemote.localDescription is not null");
-        is(test.pcRemote.localDescription.type, "answer",
-           "test.pcRemote.localDescription type is answer");
-        ok(test.pcRemote.localDescription.sdp.length > 10,
-           "test.pcRemote.localDescription body length is plausible");
-
-        ok(test.pcRemote.remoteDescription,
-           "test.pcRemote.remoteDescription is not null");
-        is(test.pcRemote.remoteDescription.type, "offer",
-           "test.pcRemote.remoteDescription type is offer");
-        ok(test.pcRemote.remoteDescription.sdp.length > 10,
-           "test.pcRemote.remoteDescription body length is plausible");
-
-        test.next();
-      }
-    ], [
       "CHECK_SDP_ON_CLOSED_PC",
       function (test) {
         var description;
         var exception = null;
 
         // handle the event which the close() triggers
         test.pcLocal.onsignalingstatechange = function (state) {
           is(state, "closed", "Received expected onsignalingstatechange event 'closed'");
--- a/dom/media/tests/mochitest/test_peerConnection_bug835370.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug835370.html
@@ -5,17 +5,17 @@
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
-    bug: "825703",
+    bug: "835370",
     title: "PeerConnection.createOffer valid/invalid constraints permutations"
   });
 
   runNetworkTest(function () {
     var pconnect  = new mozRTCPeerConnection();
     var pconnects = new mozRTCPeerConnection();
 
     function step1(offer) {}
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1633,17 +1633,17 @@ nsresult nsPluginInstanceOwner::Dispatch
   if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
     return aKeyEvent->PreventDefault(); // consume event
   // continue only for cases without child window
 #endif
 
   if (mInstance) {
     WidgetKeyboardEvent* keyEvent =
       aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
-    if (keyEvent && keyEvent->eventStructType == NS_KEY_EVENT) {
+    if (keyEvent && keyEvent->mClass == eKeyboardEventClass) {
       nsEventStatus rv = ProcessEvent(*keyEvent);
       if (nsEventStatus_eConsumeNoDefault == rv) {
         aKeyEvent->PreventDefault();
         aKeyEvent->StopPropagation();
       }
     }
   }
 
@@ -1668,17 +1668,17 @@ nsPluginInstanceOwner::ProcessMouseDown(
     if (fm) {
       nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mContent);
       fm->SetFocus(elem, 0);
     }
   }
 
   WidgetMouseEvent* mouseEvent =
     aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
-  if (mouseEvent && mouseEvent->eventStructType == NS_MOUSE_EVENT) {
+  if (mouseEvent && mouseEvent->mClass == eMouseEventClass) {
     mLastMouseDownButtonType = mouseEvent->button;
     nsEventStatus rv = ProcessEvent(*mouseEvent);
     if (nsEventStatus_eConsumeNoDefault == rv) {
       return aMouseEvent->PreventDefault(); // consume event
     }
   }
 
   return NS_OK;
@@ -1693,17 +1693,17 @@ nsresult nsPluginInstanceOwner::Dispatch
   // continue only for cases without child window
 #endif
   // don't send mouse events if we are hidden
   if (!mWidgetVisible)
     return NS_OK;
 
   WidgetMouseEvent* mouseEvent =
     aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
-  if (mouseEvent && mouseEvent->eventStructType == NS_MOUSE_EVENT) {
+  if (mouseEvent && mouseEvent->mClass == eMouseEventClass) {
     nsEventStatus rv = ProcessEvent(*mouseEvent);
     if (nsEventStatus_eConsumeNoDefault == rv) {
       aMouseEvent->PreventDefault();
       if (!aAllowPropagate) {
         aMouseEvent->StopPropagation();
       }
     }
     if (mouseEvent->message == NS_MOUSE_BUTTON_UP) {
@@ -1899,17 +1899,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
 #endif
 
 #ifdef XP_WIN
   // this code supports windowless plugins
   const NPEvent *pPluginEvent = static_cast<const NPEvent*>(anEvent.mPluginEvent);
   // we can get synthetic events from the EventStateManager... these
   // have no pluginEvent
   NPEvent pluginEvent;
-  if (anEvent.eventStructType == NS_MOUSE_EVENT) {
+  if (anEvent.mClass == eMouseEventClass) {
     if (!pPluginEvent) {
       // XXX Should extend this list to synthesize events for more event
       // types
       pluginEvent.event = 0;
       const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
       switch (anEvent.message) {
       case NS_MOUSE_MOVE:
         pluginEvent.event = WM_MOUSEMOVE;
@@ -2006,19 +2006,18 @@ nsEventStatus nsPluginInstanceOwner::Pro
 #endif
 
 #ifdef MOZ_X11
   // this code supports windowless plugins
   nsIWidget* widget = anEvent.widget;
   XEvent pluginEvent = XEvent();
   pluginEvent.type = 0;
 
-  switch(anEvent.eventStructType)
-    {
-    case NS_MOUSE_EVENT:
+  switch(anEvent.mClass) {
+    case eMouseEventClass:
       {
         switch (anEvent.message)
           {
           case NS_MOUSE_CLICK:
           case NS_MOUSE_DOUBLECLICK:
             // Button up/down events sent instead.
             return rv;
           }
@@ -2113,19 +2112,19 @@ nsEventStatus nsPluginInstanceOwner::Pro
               event.subwindow = None;
               event.same_screen = True;
             }
             break;
           }
       }
       break;
 
-   //XXX case NS_MOUSE_SCROLL_EVENT: not received.
-
-   case NS_KEY_EVENT:
+   //XXX case eMouseScrollEventClass: not received.
+
+   case eKeyboardEventClass:
       if (anEvent.mPluginEvent)
         {
           XKeyEvent &event = pluginEvent.xkey;
 #ifdef MOZ_WIDGET_GTK
           event.root = GDK_ROOT_WINDOW();
           event.time = anEvent.time;
           const GdkEventKey* gdkEvent =
             static_cast<const GdkEventKey*>(anEvent.mPluginEvent);
@@ -2208,19 +2207,18 @@ nsEventStatus nsPluginInstanceOwner::Pro
   {
     // The plugin needs focus to receive keyboard and touch events
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     if (fm) {
       nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mContent);
       fm->SetFocus(elem, 0);
     }
   }
-  switch(anEvent.eventStructType)
-    {
-    case NS_MOUSE_EVENT:
+  switch(anEvent.mClass) {
+    case eMouseEventClass:
       {
         switch (anEvent.message)
           {
           case NS_MOUSE_CLICK:
           case NS_MOUSE_DOUBLECLICK:
             // Button up/down events sent instead.
             return rv;
           }
@@ -2263,20 +2261,21 @@ nsEventStatus nsPluginInstanceOwner::Pro
               event.data.mouse.y = pluginPoint.y;
               mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
             }
             break;
           }
       }
       break;
 
-    case NS_KEY_EVENT:
+    case eKeyboardEventClass:
      {
        const WidgetKeyboardEvent& keyEvent = *anEvent.AsKeyboardEvent();
-       LOG("Firing NS_KEY_EVENT %d %d\n", keyEvent.keyCode, keyEvent.charCode);
+       LOG("Firing eKeyboardEventClass %d %d\n",
+           keyEvent.keyCode, keyEvent.charCode);
        // pluginEvent is initialized by nsWindow::InitKeyEvent().
        const ANPEvent* pluginEvent = static_cast<const ANPEvent*>(keyEvent.mPluginEvent);
        if (pluginEvent) {
          MOZ_ASSERT(pluginEvent->inSize == sizeof(ANPEvent));
          MOZ_ASSERT(pluginEvent->eventType == kKey_ANPEventType);
          mInstance->HandleEvent(const_cast<ANPEvent*>(pluginEvent),
                                 nullptr,
                                 NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
--- a/dom/tests/mochitest/general/test_paste_selection.html
+++ b/dom/tests/mochitest/general/test_paste_selection.html
@@ -100,15 +100,17 @@ function pastedSelection(event)
 function pastedGlobal(event)
 {
   // The data transfer should contain the global data.
   is(event.clipboardData.getData("text/plain"), "CLIPBOARD", "data correct in global clipboard data transfer");
   globalPasted = true;
 }
 
 SimpleTest.waitForExplicitFinish();
-SimpleTest.waitForFocus(selectArea);
+SimpleTest.waitForFocus(function() {
+  SpecialPowers.pushPrefEnv({"set": [["general.autoScroll", false]]}, selectArea);
+});
 </script>
 
 </pre>
 </body>
 </html>
 
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -75,20 +75,21 @@ interface AudioContext : EventTarget {
 
 };
 
 // Mozilla extensions
 partial interface AudioContext {
   // Read AudioChannel.webidl for more information about this attribute.
   [Pref="media.useAudioChannelService", SetterThrows]
   attribute AudioChannel mozAudioChannelType;
-};
 
-partial interface AudioContext {
   // These 2 events are dispatched when the AudioContext object is muted by
   // the AudioChannelService. It's call 'interrupt' because when this event is
   // dispatched on a HTMLMediaElement, the audio stream is paused.
   [Pref="media.useAudioChannelService"]
   attribute EventHandler onmozinterruptbegin;
 
   [Pref="media.useAudioChannelService"]
   attribute EventHandler onmozinterruptend;
+
+  // This method is for test only.
+  [ChromeOnly] AudioChannel testAudioChannelInAudioNodeStream();
 };
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -47,16 +47,19 @@ interface Element : Node {
   void removeAttribute(DOMString name);
   [Throws]
   void removeAttributeNS(DOMString? namespace, DOMString localName);
   [Pure]
   boolean hasAttribute(DOMString name);
   [Pure]
   boolean hasAttributeNS(DOMString? namespace, DOMString localName);
 
+  [Throws, Pure]
+  boolean matches(DOMString selector);
+
   [Pure]
   HTMLCollection getElementsByTagName(DOMString localName);
   [Throws, Pure]
   HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
   [Pure]
   HTMLCollection getElementsByClassName(DOMString classNames);
 
   /**
--- a/dom/webidl/TestInterfaceJS.webidl
+++ b/dom/webidl/TestInterfaceJS.webidl
@@ -12,9 +12,11 @@ interface TestInterfaceJS {
   readonly attribute object objectArg;
   attribute any anyAttr;
   attribute object objectAttr;
   any pingPongAny(any arg);
   object pingPongObject(any obj);
 
   // For testing bug 968335.
   DOMString getCallerPrincipal();
+
+  DOMString convertSVS(ScalarValueString svs);
 };
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -43,16 +43,17 @@
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ImageDataBinding.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePortList.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/dom/StructuredClone.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/Preferences.h"
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsError.h"
 #include "nsDOMJSUtils.h"
 #include "nsHostObjectProtocolHandler.h"
@@ -347,35 +348,17 @@ struct WorkerStructuredCloneCallbacks
           result = file::CreateBlob(aCx, blob);
         }
         return result;
       }
     }
     // See if the object is an ImageData.
     else if (aTag == SCTAG_DOM_IMAGEDATA) {
       MOZ_ASSERT(!aData);
-
-      // Read the information out of the stream.
-      uint32_t width, height;
-      JS::Rooted<JS::Value> dataArray(aCx);
-      if (!JS_ReadUint32Pair(aReader, &width, &height) ||
-          !JS_ReadTypedArray(aReader, &dataArray))
-      {
-        return nullptr;
-      }
-      MOZ_ASSERT(dataArray.isObject());
-
-      {
-        // Construct the ImageData.
-        nsRefPtr<ImageData> imageData = new ImageData(width, height,
-                                                      dataArray.toObject());
-        // Wrap it in a JS::Value, protected from a moving GC during ~nsRefPtr.
-        result = imageData->WrapObject(aCx);
-      }
-      return result;
+      return ReadStructuredCloneImageData(aCx, aReader);
     }
 
     Error(aCx, 0);
     return nullptr;
   }
 
   static bool
   Write(JSContext* aCx, JSStructuredCloneWriter* aWriter,
@@ -413,27 +396,17 @@ struct WorkerStructuredCloneCallbacks
         }
       }
     }
 
     // See if this is an ImageData object.
     {
       ImageData* imageData = nullptr;
       if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, aObj, imageData))) {
-        // Prepare the ImageData internals.
-        uint32_t width = imageData->Width();
-        uint32_t height = imageData->Height();
-        JS::Rooted<JSObject*> dataArray(aCx, imageData->GetDataObject());
-
-        // Write the internals to the stream.
-        JSAutoCompartment ac(aCx, dataArray);
-        JS::Rooted<JS::Value> arrayValue(aCx, JS::ObjectValue(*dataArray));
-        return JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEDATA, 0) &&
-               JS_WriteUint32Pair(aWriter, width, height) &&
-               JS_WriteTypedArray(aWriter, arrayValue);
+        return WriteStructuredCloneImageData(aCx, aWriter, imageData);
       }
     }
 
     Error(aCx, 0);
     return false;
   }
 
   static void
--- a/dom/xbl/nsXBLEventHandler.cpp
+++ b/dom/xbl/nsXBLEventHandler.cpp
@@ -8,16 +8,17 @@
 #include "nsIDOMEventListener.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsXBLPrototypeHandler.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
 #include "mozilla/dom/EventTarget.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 nsXBLEventHandler::nsXBLEventHandler(nsXBLPrototypeHandler* aHandler)
   : mProtoHandler(aHandler)
 {
 }
 
 nsXBLEventHandler::~nsXBLEventHandler()
@@ -142,22 +143,22 @@ nsXBLKeyEventHandler::HandleEvent(nsIDOM
 
 ///////////////////////////////////////////////////////////////////////////////////
 
 nsresult
 NS_NewXBLEventHandler(nsXBLPrototypeHandler* aHandler,
                       nsIAtom* aEventType,
                       nsXBLEventHandler** aResult)
 {
-  switch (nsContentUtils::GetEventCategory(nsDependentAtomString(aEventType))) {
-    case NS_DRAG_EVENT:
-    case NS_MOUSE_EVENT:
-    case NS_MOUSE_SCROLL_EVENT:
-    case NS_WHEEL_EVENT:
-    case NS_SIMPLE_GESTURE_EVENT:
+  switch (nsContentUtils::GetEventClassID(nsDependentAtomString(aEventType))) {
+    case eDragEventClass:
+    case eMouseEventClass:
+    case eMouseScrollEventClass:
+    case eWheelEventClass:
+    case eSimpleGestureEventClass:
       *aResult = new nsXBLMouseEventHandler(aHandler);
       break;
     default:
       *aResult = new nsXBLEventHandler(aHandler);
       break;
   }
 
   if (!*aResult)
--- a/extensions/gnomevfs/moz.build
+++ b/extensions/gnomevfs/moz.build
@@ -10,17 +10,16 @@ SOURCES += [
 
 LIBRARY_NAME = 'nkgnomevfs'
 
 IS_COMPONENT = True
 
 # make sure this component is never statically linked into the main
 # application.  this is necessary since we don't want to force users
 # to install gnome-vfs2 in order to use the rest of mozilla ;-)
-FORCE_SHARED_LIB = True
 
 USE_LIBS += [
     'mozalloc',
     'xpcomglue_s',
     'xul',
 ]
 
 CXXFLAGS += CONFIG['MOZ_GNOMEVFS_CFLAGS']
--- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
+++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
@@ -10207,1188 +10207,1194 @@ 29216a34925
 > intern/GDL
 29266a34976
 > interruptible/U
 29272a34983,34986
 > intersex
 > intersexual/MS
 > intersexualism
 > intersexuality
-29724c35438
+29446c35160
+< ironic
+---
+> ironic/U
+29447a35162
+> ironically/U
+29724c35439
 < jewellery's
 ---
 > jewellery/M
-29733,29734c35447
+29733,29734c35448
 < jig's
 < jig/AS
 ---
 > jig/ASM
-29736,29737c35449
+29736,29737c35450
 < jigger's
 < jigger/ASDG
 ---
 > jigger/ASDGM
-29799,29800c35511
+29799,29800c35512
 < join's
 < join/AFDSG
 ---
 > join/AFDSGM
-29803,29804c35514
+29803,29804c35515
 < joint's
 < joint/EGSD
 ---
 > joint/EGSDM
-29869,29870c35579,35580
+29869,29870c35580,35581
 < judge's
 < judge/ADSG
 ---
 > judge/ADSGM
 > judgement/MS
-30035a35746,35747
+30035a35747,35748
 > keylogger/MS
 > keylogging/MS
-30066c35778
+30066c35779
 < kiddie/M
 ---
 > kiddie/SM
-30102,30103c35814
+30102,30103c35815
 < kind's
 < kind/UPRYT
 ---
 > kind/UPRYTM
-30262,30263c35973
+30262,30263c35974
 < kraut's
 < kraut/S!
 ---
 > kraut/MS!
-30283,30284c35993
+30283,30284c35994
 < label's
 < label/ASDG
 ---
 > label/ASDGM
-30302,30303c36011
+30302,30303c36012
 < lace's
 < lace/UGDS
 ---
 > lace/UGDSM
-30497,30498c36205
+30497,30498c36206
 < latch's
 < latch/UDSG
 ---
 > latch/UDSGM
-30637c36344
+30637c36345
 < learning's
 ---
 > learning/M
-30643,30644c36350
+30643,30644c36351
 < leash's
 < leash/UDSG
 ---
 > leash/UDSGM
-30665a36372
+30665a36373
 > lector/MS
-30700c36407
+30700c36408
 < legation's/AC
 ---
 > legation/ACM
-30927,30928c36634
+30927,30928c36635
 < light's/C
 < light/CASTGD
 ---
 > light/CASTGDM
-30938c36644
+30938c36645
 < lighting's
 ---
 > lighting/M
-30981,30982c36687
+30981,30982c36688
 < limit's
 < limit/CSZGDR
 ---
 > limit/CSZGDRM
-30986c36691
+30986c36692
 < limiter's
 ---
 > limiter/M
-30990a36696,36698
+30990a36697,36699
 > limnological
 > limnologist/MS
 > limnology/M
-31031c36739
+31031c36740
 < linguini's
 ---
 > linguini/M
-31034c36742
+31034c36743
 < linguistically
 ---
 > linguistical/Y
-31047,31048c36755
+31047,31048c36756
 < lint's
 < lint/CDSG
 ---
 > lint/CDSGM
-31058a36766
+31058a36767
 > lepidopterist/SM
-31151,31152c36859
+31151,31152c36860
 < liver's
 < liver/S
 ---
 > liver/MS
-31170,31171c36877
+31170,31171c36878
 < load's
 < load/AUGSD
 ---
 > load/AUGSDM
-31211,31212c36917
+31211,31212c36918
 < location's/A
 < location/ESM
 ---
 > location/ESMA
-31291,31292c36996
+31291,31292c36997
 < long's
 < long/KDSTG
 ---
 > long/KDSTGM
-31379,31380c37083
+31379,31380c37084
 < louse's
 < louse/CDSG
 ---
 > louse/CDSGM
-31639a37343
+31639a37344
 > mage/SM
-31741,31742c37445
+31741,31742c37446
 < make's/A
 < make/UAGS
 ---
 > make/UAGSM
-31806a37510
+31806a37511
 > malware/MS
-31822,31823c37526
+31822,31823c37527
 < man's/F
 < man/USY
 ---
 > man/USYMF
-31924,31925c37627
+31924,31925c37628
 < mantle's
 < mantle/EGDS
 ---
 > mantle/EGDSM
-31940,31941c37642
+31940,31941c37643
 < map's
 < map/AS
 ---
 > map/ASM
-32061,32062c37762
+32061,32062c37763
 < mask's
 < mask/UDSG
 ---
 > mask/UDSGM
-32084,32085c37784
+32084,32085c37785
 < master's
 < master/ADGS
 ---
 > master/ADGSM
-32230c37929
+32230c37930
 < meanie/M
 ---
 > meanie/MS
-32246,32247c37945
+32246,32247c37946
 < measure's
 < measure/ADSG
 ---
 > measure/ADSGM
-32317,32318c38015
+32317,32318c38016
 < megadeath/M
 < megadeaths
 ---
 > megadeath/SM
-32320c38017
+32320c38018
 < megajoules
 ---
 > megajoule/SM
-32329c38026
+32329c38027
 < megapixel/S
 ---
 > megapixel/MS
-32361,32362c38058
+32361,32362c38059
 < melt's
 < melt/ADSG
 ---
 > melt/ADSGM
-32365,32366c38061
+32365,32366c38062
 < member's
 < member/EAS
 ---
 > member/EASM
-32708a38404
+32708a38405
 > might've
-32717a38414
+32717a38415
 > migrator/SM
-32760a38458
+32760a38459
 > millennia
-32777d38474
+32777d38475
 < millionnaire/M
-32806,32807c38503
+32806,32807c38504
 < mind's
 < mind/ADRSZG
 ---
 > mind/ADRSZGM
-32934a38631
+32934a38632
 > miscommunication/S
-32991a38689
+32991a38690
 > misjudgement/MS
-33027,33028c38725
+33027,33028c38726
 < miss's
 < miss/EDSGV
 ---
 > miss/EDSGVM
-33051,33052c38748
+33051,33052c38749
 < mist's
 < mist/CDRSZG
 ---
 > mist/CDRSZGM
-33056c38752
+33056c38753
 < mister's
 ---
 > mister/M
-33107,33108c38803
+33107,33108c38804
 < mob's
 < mob/CS
 ---
 > mob/CSM
-33448,33449c39143
+33448,33449c39144
 < mortgage's
 < mortgage/AGDS
 ---
 > mortgage/AGDSM
-33471,33472c39165
+33471,33472c39166
 < mote's
 < mote/KCXSVN
 ---
 > mote/KCXSVNM
-33539,33540c39232
+33539,33540c39233
 < mounting's
 < mountings
 ---
 > mounting/MS
-33784a39477
+33784a39478
 > must've
-33887,33888c39580
+33887,33888c39581
 < name's
 < name/AGDS
 ---
 > name/AGDSM
-33963c39655
+33963c39656
 < native/MS
 ---
 > native/MSY
-33970,33971c39662
+33970,33971c39663
 < natural's
 < natural/UPY
 ---
 > natural/UPYM
-33979,33980c39670
+33979,33980c39671
 < nature's
 < nature/CS
 ---
 > nature/CSM
-34133,34134c39823
+34133,34134c39824
 < nerve's
 < nerve/UDSG
 ---
 > nerve/UDSGM
-34169,34171c39858,39860
+34169,34171c39859,39861
 < neurone/S
 < neurophysiology
 < neuroscience
 ---
 > neurophysiology/M
 > neuroscience/MS
 > neuroscientist/MS
-34175a39865
+34175a39866
 > neurosurgical
-34275c39965
+34275c39966
 < nightie/M
 ---
 > nightie/SM
-34388,34389c40078
+34388,34389c40079
 < nomination's/A
 < nomination/CSM
 ---
 > nomination/CSMA
-34755,34756c40444
+34755,34756c40445
 < note's
 < note/FCSDG
 ---
 > note/FCSDGM
-34840,34841c40528
+34840,34841c40529
 < number's
 < number/ASDG
 ---
 > number/ASDGM
-35104a40792
+35104a40793
 > octopi
-35137,35138c40825
+35137,35138c40826
 < offensive's
 < offensive/IYP
 ---
 > offensive/IYPM
-35219d40905
+35219d40906
 < oleomargarin/M
-35226a40913
+35226a40914
 > oligo
-35345c41032
+35345c41033
 < oppose/DSG
 ---
 > oppose/DSGRB
-35452,35453c41139
+35452,35453c41140
 < orient's
 < orient/AEDGS
 ---
 > orient/AEDGSM
-35913c41599
+35913c41600
 < oversize/D
 ---
 > oversize
-36031,36032c41717
+36031,36032c41718
 < pack's
 < pack/UADSG
 ---
 > pack/UADSGM
-36034,36035c41719
+36034,36035c41720
 < package's
 < package/AGDS
 ---
 > package/AGDSM
-36041c41725
+36041c41726
 < packing's
 ---
 > packing/M
-36056,36059d41739
+36056,36059d41740
 < paederast/S
 < paediatrician's
 < paediatricians
 < paediatrics/M
-36290a41971,41972
+36290a41972,41973
 > parallelization/SM
 > parallelize/SGD
-36291a41974
+36291a41975
 > paralyses
-36377a42061
+36377a42062
 > parkour
-36403d42086
+36403d42087
 < parrakeet/MS
-36418,36419c42101
+36418,36419c42102
 < part's
 < part/CDSG
 ---
 > part/CDSGM
-36445,36447c42127
+36445,36447c42128
 < partition's
 < partition/ADG
 < partitions
 ---
 > partition/ADGMS
-36449d42128
+36449d42129
 < partizan/SM
-36621,36622c42300
+36621,36622c42301
 < pay's
 < pay/ASGBL
 ---
 > pay/ASGBLM
-37093a42772
+37093a42773
 > petabyte/MS
-37102c42781
+37102c42782
 < petitioner/M
 ---
 > petitioner/MS
-37221a42901,42902
+37221a42902,42903
 > phlebotomist/SM
 > phlebotomize/SGD
-37228a42910
+37228a42911
 > pho
-37264a42947
+37264a42948
 > phosphorylate/DSGN
-37310,37311c42993
+37310,37311c42994
 < phrase's
 < phrase/AGDS
 ---
 > phrase/AGDSM
-37316d42997
+37316d42998
 < phrenetic
-37469,37470c43150
+37469,37470c43151
 < pine's
 < pine/AGDS
 ---
 > pine/AGDSM
-37596,37597c43276
+37596,37597c43277
 < place's
 < place/EAGLDS
 ---
 > place/EAGLDSM
-37630a43310
+37630a43311
 > plaintext
-37636,37637c43316
+37636,37637c43317
 < plane's
 < plane/CGDS
 ---
 > plane/CGDSM
-37786,37787c43465
+37786,37787c43466
 < ploy's
 < ploy/S
 ---
 > ploy/SM
-37792,37793c43470
+37792,37793c43471
 < plug's
 < plug/US
 ---
 > plug/USM
-37796a43474
+37796a43475
 > plugin/MS
-37987c43665
+37987c43666
 < polypeptide/S
 ---
 > polypeptide/MS
-38106,38107c43784
+38106,38107c43785
 < port's
 < port/CAEGDS
 ---
 > port/CAEGDSM
-38134,38135c43811
+38134,38135c43812
 < pose's/A
 < pose/CAKEGDS
 ---
 > pose/CAKEGDSM
-38140,38141c43816
+38140,38141c43817
 < position's/KC
 < position/ACKES
 ---
 > position/ACKESM
-38260,38261c43935
+38260,38261c43936
 < pound's
 < pound/KDSG
 ---
 > pound/KDSGM
-38266a43941
+38266a43942
 > poutine/S
-38291d43965
+38291d43966
 < practise's
-38451a44126
+38451a44127
 > prejudgement/MS
-38568,38569c44243
+38568,38569c44244
 < press's
 < press/ACGSD
 ---
 > press/ACGSDM
-38638,38639c44312
+38638,38639c44313
 < price's
 < price/AGDS
 ---
 > price/AGDSM
-38756,38757c44429
+38756,38757c44430
 < process's
 < process/AGDS
 ---
 > process/AGDSM
-38780,38781c44452
+38780,38781c44453
 < produce's
 < produce/AZGDRS
 ---
 > produce/AZGDRSM
-38805a44477
+38805a44478
 > profiler/SM
-38835a44508
+38835a44509
 > programmatically
-38891a44565,44566
+38891a44566,44567
 > pronate/DSGN
 > pronator/MS
-38951c44626
+38951c44627
 < proprietorship/M
 ---
 > proprietorship/MS
-39039a44715
+39039a44716
 > provender/M
-39095a44772
+39095a44773
 > pseudorandom/Y
-39564a45242
+39564a45243
 > quinoa
-39581,39582c45259
+39581,39582c45260
 < quire's
 < quire/IAS
 ---
 > quire/IASM
-39614,39615c45291
+39614,39615c45292
 < quote's
 < quote/UDSG
 ---
 > quote/UDSGM
-39653,39654c45329
+39653,39654c45330
 < racoon's
 < racoons
 ---
 > racoon/MS
-39738,39739c45413
+39738,39739c45414
 < rail's
 < rail/CGDS
 ---
 > rail/CGDSM
-39816,39817c45490
+39816,39817c45491
 < range's
 < range/CGDS
 ---
 > range/CGDSM
-39873a45547,45548
+39873a45548,45549
 > rasterization/M
 > rasterize/SGDR
-39925,39926c45600
+39925,39926c45601
 < ravel's
 < ravel/UDSG
 ---
 > ravel/UDSGM
-40036a45711
+40036a45712
 > recency
-40140a45816
+40140a45817
 > recurse/DGSV
-40141a45818
+40141a45819
 > recuse/DGS
-40204,40205c45881
+40204,40205c45882
 < reel's
 < reel/UGDS
 ---
 > reel/UGDSM
-40208a45885
+40208a45886
 > refactor/SMDG
-40244d45920
+40244d45921
 < reflexion/SM
-40659d46334
+40659d46335
 < resizing
-40829c46504
+40829c46505
 < reverie/M
 ---
 > reverie/MS
-40895a46571,46573
+40895a46572,46574
 > rheumatological
 > rheumatology/M
 > rheumatologist/SM
-40944,40945c46622
+40944,40945c46623
 < ride's
 < ride/CZGS
 ---
 > ride/CZGSM
-41104,41105c46781
+41104,41105c46782
 < robe's
 < robe/EGDS
 ---
 > robe/EGDSM
-41132,41133c46808
+41132,41133c46809
 < rogue's
 < rogue/KS
 ---
 > rogue/KSM
-41185a46861
+41185a46862
 > rootkit/MS
-41258,41259c46934
+41258,41259c46935
 < route's
 < route/ADSG
 ---
 > route/ADSGM
-41415a47091
+41415a47092
 > sabre/MS
-41447,41448c47123
+41447,41448c47124
 < saddle's
 < saddle/UDSG
 ---
 > saddle/UDSGM
-41463,41464c47138
+41463,41464c47139
 < safe's
 < safe/UYTPR
 ---
 > safe/UYTPRM
-41544,41545c47218
+41544,41545c47219
 < salt's
 < salt/CTGDS
 ---
 > salt/CTGDSM
-41765,41766c47438
+41765,41766c47439
 < say's
 < say/USG
 ---
 > say/USGM
-41787,41788c47459
+41787,41788c47460
 < scale's
 < scale/ACSDG
 ---
 > scale/ACSDGM
-41806,41807c47477
+41806,41807c47478
 < scan's
 < scan/AS
 ---
 > scan/ASM
-41880,41881c47550
+41880,41881c47551
 < schedule's
 < schedule/ADSG
 ---
 > schedule/ADSGM
-41914c47583
+41914c47584
 < schnaps's
 ---
 > schnaps/M
-41949c47618
+41949c47619
 < schrod's
 ---
 > schrod/SM
-41998a47668
+41998a47669
 > scot-free
-42016,42017c47686
+42016,42017c47687
 < scramble's
 < scramble/UGDS
 ---
 > scramble/UGDSM
-42055,42056c47724
+42055,42056c47725
 < screw's
 < screw/UDSG
 ---
 > screw/UDSGM
-42065,42066c47733
+42065,42066c47734
 < scribe's
 < scribe/IKCGSD
 ---
 > scribe/IKCGSDM
-42170,42171c47837
+42170,42171c47838
 < seal's
 < seal/AUSDG
 ---
 > seal/AUSDGM
-42204,42205c47870
+42204,42205c47871
 < seat's
 < seat/UGDS
 ---
 > seat/UGDSM
-42288,42289c47953
+42288,42289c47954
 < seed's
 < seed/AGDS
 ---
 > seed/AGDSM
-42359c48023,48024
+42359c48024,48025
 < self/M
 ---
 > self/MG
 > selfie/S
-42361a48027,48028
+42361a48028,48029
 > selfism
 > selfist/S
-42365,42367c48032,48033
+42365,42367c48033,48034
 < sell's
 < sell/AZGRS
 < seller's
 ---
 > sell/AZGRSM
 > seller/M
-42524c48190
+42524c48191
 < seraphim's
 ---
 > seraphim/M
-42558,42559c48224
+42558,42559c48225
 < serve's/AF
 < serve/FACGDS
 ---
 > serve/FACGDSM
-42574,42575c48239
+42574,42575c48240
 < serving's
 < servings
 ---
 > serving/MS
-42594,42595c48258
+42594,42595c48259
 < settle's
 < settle/AUGDS
 ---
 > settle/AUGDSM
-42647,42648c48310
+42647,42648c48311
 < shackle's
 < shackle/UGDS
 ---
 > shackle/UGDSM
-42716,42717c48378
+42716,42717c48379
 < shape's
 < shape/AGDS
 ---
 > shape/AGDSM
-42851,42852c48512
+42851,42852c48513
 < ship's
 < ship/ALS
 ---
 > ship/ALSM
-42883,42885c48543
+42883,42885c48544
 < shit's
 < shit/S!
 < shite/S!
 ---
 > shit/MS!
-42887,42888c48545,48546
+42887,42888c48546,48547
 < shithead/S!
 < shitload/!
 ---
 > shithead/MS!
 > shitload/MS!
-42891c48549
+42891c48550
 < shitty/RT!
 ---
 > shitty/TR!
-42976a48635
+42976a48636
 > should've
-43008c48667
+43008c48668
 < showtime
 ---
 > showtime/MS
-43090,43091c48749
+43090,43091c48750
 < side's
 < side/AGDS
 ---
 > side/AGDSM
-43143,43144c48801
+43143,43144c48802
 < sign's
 < sign/AFCGDS
 ---
 > sign/AFCGDSM
-43163,43164c48820
+43163,43164c48821
 < signing's/C
 < signings
 ---
 > signing/MCS
-43328c48984
+43328c48985
 < size/MGBDRS
 ---
 > size/AMGBDRS
-43368,43369c49024
+43368,43369c49025
 < skill's
 < skill/CSD
 ---
 > skill/CSDM
-43724,43726c49379
+43724,43726c49380
 < smoulder's
 < smouldered
 < smoulders
 ---
 > smoulder/GSMD
-43752,43753c49405
+43752,43753c49406
 < snap's
 < snap/US
 ---
 > snap/USM
-43767,43768c49419,49421
+43767,43768c49420,49422
 < snarl's
 < snarl/USDG
 ---
 > snarkily
 > snarky/TR
 > snarl/USDGM
-44012,44013c49665
+44012,44013c49666
 < solute's
 < solute/XN
 ---
 > solute/XNM
-44015c49667
+44015c49668
 < solution's/EA
 ---
 > solution/EAM
-44021c49673
+44021c49674
 < solver's
 ---
 > solver/M
-44041a49694
+44041a49695
 > sommelier/SM
-44062c49715
+44062c49716
 < sonofabitch
 ---
 > sonofabitch/!
-44177,44178c49830
+44177,44178c49831
 < sow's
 < sow/ASGD
 ---
 > sow/ASGDM
-44346a49999
+44346a50000
 > spelled
-44348a50002
+44348a50003
 > spelt
-44371a50026
+44371a50027
 > spick/S!
-44383c50038
+44383c50039
 < spik/S
 ---
 > spik/S!
-44413,44414c50068
+44413,44414c50069
 < spire's
 < spire/IFAS
 ---
 > spire/IFASM
-44416,44417c50070
+44416,44417c50071
 < spirit's
 < spirit/ISGD
 ---
 > spirit/ISGDM
-44475,44476c50128
+44475,44476c50129
 < spoil's
 < spoil/CSDRZG
 ---
 > spoil/CSDRZGM
-44549,44550c50201
+44549,44550c50202
 < spray's
 < spray/ASDG
 ---
 > spray/ASDGM
-44688,44689c50339
+44688,44689c50340
 < staff's
 < staff/ASDG
 ---
 > staff/ASDGM
-44729,44730c50379
+44729,44730c50380
 < stall's
 < stall/SDG
 ---
 > stall/SDGM
-44871a50521
+44871a50522
 > steampunk
-44985,44986c50635
+44985,44986c50636
 < still's
 < still/ITGSD
 ---
 > still/ITGSDM
-45024,45025c50673
+45024,45025c50674
 < stitch's
 < stitch/ADSG
 ---
 > stitch/ADSGM
-45030,45031c50678
+45030,45031c50679
 < stock's
 < stock/AGSD
 ---
 > stock/AGSDM
-45090,45091c50737
+45090,45091c50738
 < stop's
 < stop/US
 ---
 > stop/USM
-45105,45106c50751
+45105,45106c50752
 < store's
 < store/ADSG
 ---
 > store/ADSGM
-45148,45149c50793
+45148,45149c50794
 < strain's
 < strain/FADSG
 ---
 > strain/FADSGM
-45164,45165c50808
+45164,45165c50809
 < strap's
 < strap/US
 ---
 > strap/USM
-45290,45291c50933
+45290,45291c50934
 < structure's
 < structure/AGDS
 ---
 > structure/AGDSM
-45330,45331c50972
+45330,45331c50973
 < study's
 < study/AGDS
 ---
 > study/AGDSM
-45368,45369c51009
+45368,45369c51010
 < style's
 < style/ADSG
 ---
 > style/ADSGM
-45455,45456c51095
+45455,45456c51096
 < submission's
 < submission/AS
 ---
 > submission/ASM
-45872,45873c51511
+45872,45873c51512
 < surface's
 < surface/AGDS
 ---
 > surface/AGDSM
-45918,45919c51556
+45918,45919c51557
 < survey's
 < survey/ADGS
 ---
 > survey/ADGSM
-46106a51744
+46106a51745
 > syllabi
-46160c51798
+46160c51799
 < synch/GMD
 ---
 > synch/GMDS
-46167d51804
+46167d51805
 < synchs
-46178a51816,51818
+46178a51817,51819
 > synesthesia
 > synesthete/S
 > synesthetic
-46203,46204c51843,51844
+46203,46204c51844,51845
 < sysadmin/S
 < sysop/S
 ---
 > sysadmin/MS
 > sysop/MS
-46363,46364c52003
+46363,46364c52004
 < tangle's
 < tangle/UDSG
 ---
 > tangle/UDSGM
-46632a52272,52273
+46632a52273,52274
 > teleport/SGD
 > teleportation
-46675,46676c52316
+46675,46676c52317
 < template's
 < template/S
 ---
 > template/SM
-46752a52393
+46752a52394
 > terabit/MS
-46753a52395,52396
+46753a52396,52397
 > terahertz/M
 > terapixel/MS
-46806,46807c52449
+46806,46807c52450
 < test's/AFK
 < test/AKFCDGS
 ---
 > test/AKFCDGSM
-46817a52460
+46817a52461
 > testcase/MS
-46831a52475
+46831a52476
 > testsuite/MS
-46845a52490
+46845a52491
 > textbox/SM
-46925a52571
+46925a52572
 > theremin/MS
-46999c52645
+46999c52646
 < thinking's
 ---
 > thinking/M
-47095,47096c52741
+47095,47096c52742
 < throne's
 < throne/CDS
 ---
 > throne/CDSM
-47188,47189c52833
+47188,47189c52834
 < tie's
 < tie/AUSD
 ---
 > tie/AUSDM
-47213,47214c52857
+47213,47214c52858
 < till's
 < till/EDRZGS
 ---
 > till/EDRZGSM
-47303,47304c52946
+47303,47304c52947
 < tire's
 < tire/AGDS
 ---
 > tire/AGDSM
-47433,47434c53075
+47433,47434c53076
 < tone's
 < tone/IZGDRS
 ---
 > tone/IZGDRSM
-47453,47455c53094,53095
+47453,47455c53095,53096
 < tool's
 < tool/ADGS
 < toolbar
 ---
 > tool/ADGSM
 > toolbar/MS
-47540,47541c53180
+47540,47541c53181
 < tort's
 < tort/FEAS
 ---
 > tort/FEASM
-47644a53284
+47644a53285
 > traceur/SM
-47657,47658c53297
+47657,47658c53298
 < tract's
 < tract/CEKFAS
 ---
 > tract/CEKFASM
-47755a53395
+47755a53396
 > transfect/DSMG
-47774a53415,53416
+47774a53416,53417
 > transgenderism
 > transgene/MS
-47807,47808c53449
+47807,47808c53450
 < transmission's
 < transmission/AS
 ---
 > transmission/ASM
-47928,47929c53569
+47928,47929c53570
 < trench's
 < trench/AIGSD
 ---
 > trench/AIGSDM
-47951c53591
+47951c53592
 < triage/M
 ---
 > triage/MGS
-47976,47977c53616
+47976,47977c53617
 < tribute's
 < tribute/FS
 ---
 > tribute/FSM
-47997a53637
+47997a53638
 > trifecta/S
-48165,48166c53805
+48165,48166c53806
 < trust's/E
 < trust/IESGD
 ---
 > trust/IESGDM
-48180,48181c53819
+48180,48181c53820
 < try's
 < try/AGDS
 ---
 > try/AGDSM
-48271a53910
+48271a53911
 > turducken
-48334a53974
+48334a53975
 > tweep/S
-48371,48372c54011
+48371,48372c54012
 < twist's
 < twist/USDG
 ---
 > twist/USDGM
-48396,48397c54035
+48396,48397c54036
 < type's
 < type/AGDS
 ---
 > type/AGDSM
-48869a54508
+48869a54509
 > unlikeable
-49163,49164c54802
+49163,49164c54803
 < usual's
 < usual/UY
 ---
 > usual/UYM
-49211c54849
+49211c54850
 < vagina/M
 ---
 > vagina/MS
-49249,49250c54887
+49249,49250c54888
 < value's
 < value/CAGSD
 ---
 > value/CAGSDM
-49292,49293c54929
+49292,49293c54930
 < variant's
 < variant/IS
 ---
 > variant/ISM
-49356,49357c54992
+49356,49357c54993
 < veil's
 < veil/UDGS
 ---
 > veil/UDGSM
-49368,49369c55003
+49368,49369c55004
 < velour's
 < velours's
 ---
 > velour/MS
-49398,49399c55032
+49398,49399c55033
 < vent's
 < vent/DGS
 ---
 > vent/DGSM
-49435,49436c55068
+49435,49436c55069
 < verge's
 < verge/FDSG
 ---
 > verge/FDSGM
-49478a55111
+49478a55112
 > vertices
-49488,49489c55121
+49488,49489c55122
 < vest's
 < vest/ILDGS
 ---
 > vest/ILDGSM
-49681,49682c55313
+49681,49682c55314
 < visit's
 < visit/ASGD
 ---
 > visit/ASGDM
-49772a55404,55406
+49772a55405,55407
 > volcanological
 > volcanologist/MS
 > volcanology/M
-49807,49808c55441
+49807,49808c55442
 < vote's
 < vote/CGVDS
 ---
 > vote/CGVDSM
-50148a55782
+50148a55783
 > weaponize/DSG
-50215,50216c55849
+50215,50216c55850
 < weigh's
 < weigh/AGD
 ---
 > weigh/AGDM