Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 12 Aug 2015 15:16:16 -0700
changeset 257498 7649ffe28b67aa2dad0f67ea01500c0ff91b2bac
parent 257497 cf932fc931dcd19f425934db79bec641ebe2a8a9 (current diff)
parent 257473 8e248632025d5455148a604f6e63f7f167e299ca (diff)
child 257499 6af0674d374e5af4c55d12206670346f81cd666e
child 257564 c609d91f04d9422a803c51a47a988fc759738d77
child 257581 1c1d97b563f410d571e4925dab3f53fcae6c5272
push id63637
push userkwierso@gmail.com
push dateWed, 12 Aug 2015 22:19:42 +0000
treeherdermozilla-inbound@7649ffe28b67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone43.0a1
first release with
nightly linux32
7649ffe28b67 / 43.0a1 / 20150813030208 / files
nightly linux64
7649ffe28b67 / 43.0a1 / 20150813030208 / files
nightly mac
7649ffe28b67 / 43.0a1 / 20150813030208 / files
nightly win32
7649ffe28b67 / 43.0a1 / 20150813030208 / files
nightly win64
7649ffe28b67 / 43.0a1 / 20150813030208 / 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 central, a=merge
build/package/mac_osx/pkg-dmg
js/src/jit/mips/Architecture-mips.cpp
js/src/jit/mips/Architecture-mips.h
js/src/jit/mips/Assembler-mips.cpp
js/src/jit/mips/Assembler-mips.h
js/src/jit/mips/AtomicOperations-mips.h
js/src/jit/mips/Bailouts-mips.cpp
js/src/jit/mips/Bailouts-mips.h
js/src/jit/mips/BaselineCompiler-mips.cpp
js/src/jit/mips/BaselineCompiler-mips.h
js/src/jit/mips/BaselineIC-mips.cpp
js/src/jit/mips/CodeGenerator-mips.cpp
js/src/jit/mips/CodeGenerator-mips.h
js/src/jit/mips/LIR-mips.h
js/src/jit/mips/LOpcodes-mips.h
js/src/jit/mips/Lowering-mips.cpp
js/src/jit/mips/Lowering-mips.h
js/src/jit/mips/MacroAssembler-mips.cpp
js/src/jit/mips/MacroAssembler-mips.h
js/src/jit/mips/MoveEmitter-mips.cpp
js/src/jit/mips/MoveEmitter-mips.h
js/src/jit/mips/SharedICHelpers-mips.h
js/src/jit/mips/SharedICRegisters-mips.h
js/src/jit/mips/Simulator-mips.cpp
js/src/jit/mips/Simulator-mips.h
js/src/jit/mips/Trampoline-mips.cpp
js/src/jsapi-tests/testJitMoveEmitterCycles-mips.cpp
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -857,20 +857,20 @@ Accessible::HandleAccEvent(AccEvent* aEv
           break;
         case nsIAccessibleEvent::EVENT_STATE_CHANGE: {
                                                        AccStateChangeEvent* event = downcast_accEvent(aEvent);
                                                        ipcDoc->SendStateChangeEvent(id, event->GetState(),
                                                                                     event->IsStateEnabled());
                                                        break;
                                                      }
         case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: {
-                                                           AccCaretMoveEvent* event = downcast_accEvent(aEvent);
-                                                           ipcDoc->SendEvent(id, event->GetCaretOffset());
-                                                           break;
-                                                         }
+          AccCaretMoveEvent* event = downcast_accEvent(aEvent);
+          ipcDoc->SendCaretMoveEvent(id, event->GetCaretOffset());
+          break;
+        }
         case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
         case nsIAccessibleEvent::EVENT_TEXT_REMOVED: {
           AccTextChangeEvent* event = downcast_accEvent(aEvent);
           ipcDoc->SendTextChangeEvent(id, event->ModifiedText(),
                                       event->GetStartOffset(),
                                       event->GetLength(),
                                       event->IsTextInserted(),
                                       event->IsFromUserInput());
--- a/b2g/branding/official/Makefile.in
+++ b/b2g/branding/official/Makefile.in
@@ -8,16 +8,19 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 BRANDING_FILES := \
 	app.ico \
 	$(NULL)
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 BRANDING_FILES := \
 	app.icns \
+	background.png \
+	disk.icns \
+	dsstore \
 	$(NULL)
 endif
 
 ifdef MOZ_WIDGET_GTK
 BRANDING_FILES := \
 	default.png \
 	$(NULL)
 endif
copy from browser/branding/nightly/background.png
copy to b2g/branding/official/background.png
copy from browser/branding/nightly/disk.icns
copy to b2g/branding/official/disk.icns
copy from browser/branding/nightly/dsstore
copy to b2g/branding/official/dsstore
--- a/b2g/branding/unofficial/Makefile.in
+++ b/b2g/branding/unofficial/Makefile.in
@@ -8,16 +8,19 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 BRANDING_FILES := \
 	app.ico \
 	$(NULL)
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 BRANDING_FILES := \
 	app.icns \
+	background.png \
+	disk.icns \
+	dsstore \
 	$(NULL)
 endif
 
 ifdef MOZ_WIDGET_GTK
 BRANDING_FILES := \
 	default.png \
 	$(NULL)
 endif
copy from browser/branding/nightly/background.png
copy to b2g/branding/unofficial/background.png
copy from browser/branding/nightly/disk.icns
copy to b2g/branding/unofficial/disk.icns
copy from browser/branding/nightly/dsstore
copy to b2g/branding/unofficial/dsstore
deleted file mode 100755
--- a/build/package/mac_osx/pkg-dmg
+++ /dev/null
@@ -1,1488 +0,0 @@
-#!/usr/bin/perl
-# 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;
-use warnings;
-
-=pod
-
-=head1 NAME
-
-B<pkg-dmg> - Mac OS X disk image (.dmg) packager
-
-=head1 SYNOPSIS
-
-B<pkg-dmg>
-B<--source> I<source-folder>
-B<--target> I<target-image>
-[B<--format> I<format>]
-[B<--volname> I<volume-name>]
-[B<--tempdir> I<temp-dir>]
-[B<--mkdir> I<directory>]
-[B<--copy> I<source>[:I<dest>]]
-[B<--symlink> I<source>[:I<dest>]]
-[B<--license> I<file>]
-[B<--resource> I<file>]
-[B<--icon> I<icns-file>]
-[B<--attribute> I<a>:I<file>[:I<file>...]
-[B<--idme>]
-[B<--sourcefile>]
-[B<--verbosity> I<level>]
-[B<--dry-run>]
-
-=head1 DESCRIPTION
-
-I<pkg-dmg> takes a directory identified by I<source-folder> and transforms
-it into a disk image stored as I<target-image>.  The disk image will
-occupy the least space possible for its format, or the least space that the
-authors have been able to figure out how to achieve.
-
-=head1 OPTIONS
-
-=over 5
-
-==item B<--source> I<source-folder>
-
-Identifies the directory that will be packaged up.  This directory is not
-touched, a copy will be made in a temporary directory for staging purposes.
-See B<--tempdir>.
-
-==item B<--target> I<target-image>
-
-The disk image to create.  If it exists and is not in use, it will be
-overwritten.  If I<target-image> already contains a suitable extension,
-it will be used unmodified.  If no extension is present, or the extension
-is incorrect for the selected format, the proper extension will be added.
-See B<--format>.
-
-==item B<--format> I<format>
-
-The format to create the disk image in.  Valid values for I<format> are:
-     - UDZO - zlib-compressed, read-only; extension I<.dmg>
-     - UDBZ - bzip2-compressed, read-only; extension I<.dmg>;
-              create and use on 10.4 ("Tiger") and later only
-     - UDRW - read-write; extension I<.dmg>
-     - UDSP - read-write, sparse; extension I<.sparseimage>
-
-UDBZ is the default format.
-
-See L<hdiutil(1)> for a description of these formats.
-
-=item B<--volname> I<volume-name>
-
-The name of the volume in the disk image.  If not specified, I<volume-name>
-defaults to the name of the source directory from B<--source>.
-
-=item B<--tempdir> I<temp-dir>
-
-A temporary directory to stage intermediate files in.  I<temp-dir> must
-have enough space available to accommodate twice the size of the files
-being packaged.  If not specified, defaults to the same directory that
-the I<target-image> is to be placed in.  B<pkg-dmg> will remove any
-temporary files it places in I<temp-dir>.
-
-=item B<--mkdir> I<directory>
-
-Specifies a directory that should be created in the disk image.
-I<directory> and any ancestor directories will be created.  This is
-useful in conjunction with B<--copy>, when copying files to directories
-that may not exist in I<source-folder>.  B<--mkdir> may appear multiple
-times.
-
-=item B<--copy> I<source>[:I<dest>]
-
-Additional files to copy into the disk image.  If I<dest> is
-specified, I<source> is copied to the location I<dest> identifies,
-otherwise, I<source> is copied to the root of the new volume.  B<--copy>
-provides a way to package up a I<source-folder> by adding files to it
-without modifying the original I<source-folder>.  B<--copy> may appear
-multiple times.
-
-This option is useful for adding .DS_Store files and window backgrounds
-to disk images.
-
-=item B<--symlink> I<source>[:I<dest>]
-
-Like B<--copy>, but allows symlinks to point out of the volume. Empty symlink
-destinations are interpreted as "like the source path, but inside the dmg"
-
-This option is useful for adding symlinks to external resources,
-e.g. to /Applications.
-
-=item B<--license> I<file>
-
-A plain text file containing a license agreement to be displayed before
-the disk image is mounted.  English is the only supported language.  To
-include license agreements in other languages, in multiple languages,
-or to use formatted text, prepare a resource and use L<--resource>.
-
-=item B<--resource> I<file>
-
-A resource file to merge into I<target-image>.  If I<format> is UDZO or
-UDBZ, the disk image will be flattened to a single-fork file that contains
-the resource but may be freely transferred without any special encodings.
-I<file> must be in a format suitable for L<Rez(1)>.  See L<Rez(1)> for a
-description of the format, and L<hdiutil(1)> for a discussion on flattened
-disk images.  B<--resource> may appear multiple times.
-
-This option is useful for adding license agreements and other messages
-to disk images.
-
-=item B<--icon> I<icns-file>
-
-Specifies an I<icns> file that will be used as the icon for the root of
-the volume.  This file will be copied to the new volume and the custom
-icon attribute will be set on the root folder.
-
-=item B<--attribute> I<a>:I<file>[:I<file>...]
-
-Sets the attributes of I<file> to the attribute list in I<a>.  See
-L<SetFile(1)>
-
-=item B<--idme>
-
-Enable IDME to make the disk image "Internet-enabled."  The first time
-the image is mounted, if IDME processing is enabled on the system, the
-contents of the image will be copied out of the image and the image will
-be placed in the trash with IDME disabled.
-
-=item B<--sourcefile>
-
-If this option is present, I<source-folder> is treated as a file, and is
-placed as a file within the volume's root folder.  Without this option,
-I<source-folder> is treated as the volume root itself.
-
-=item B<--verbosity> I<level>
-
-Adjusts the level of loudness of B<pkg-dmg>.  The possible values for
-I<level> are:
-     0 - Only error messages are displayed.
-     1 - Print error messages and command invocations.
-     2 - Print everything, including command output.
-
-The default I<level> is 2.
-
-=item B<--dry-run>
-
-When specified, the commands that would be executed are printed, without
-actually executing them.  When commands depend on the output of previous
-commands, dummy values are displayed.
-
-=back
-
-=head1 NON-OPTIONS
-
-=over 5
-
-=item
-
-Resource forks aren't copied.
-
-=item
-
-The root folder of the created volume is designated as the folder
-to open when the volume is mounted.  See L<bless(8)>.
-
-=item
-
-All files in the volume are set to be world-readable, only writable
-by the owner, and world-executable when appropriate.  All other
-permissions bits are cleared.
-
-=item
-
-When possible, disk images are created without any partition tables.  This
-is what L<hdiutil(1)> refers to as I<-layout NONE>, and saves a handful of
-kilobytes.  The alternative, I<SPUD>, contains a partition table that
-is not terribly handy on disk images that are not intended to represent any
-physical disk.
-
-=item
-
-Read-write images are created with journaling off.  Any read-write image
-created by this tool is expected to be transient, and the goal of this tool
-is to create images which consume a minimum of space.
-
-=back
-
-=head1 EXAMPLE
-
-pkg-dmg --source /Applications/DeerPark.app --target ~/DeerPark.dmg
-  --sourcefile --volname DeerPark --icon ~/DeerPark.icns
-  --mkdir /.background
-  --copy DeerParkBackground.png:/.background/background.png
-  --copy DeerParkDSStore:/.DS_Store
-  --symlink /Applications:"/Drag to here"
-
-=head1 REQUIREMENTS
-
-I<pkg-dmg> has been tested with Mac OS X releases 10.2 ("Jaguar")
-through 10.4 ("Tiger").  Certain adjustments to behavior are made
-depending on the host system's release.  Mac OS X 10.3 ("Panther") or
-later are recommended.
-
-=head1 LICENSE
-
-MPL 2.
-
-=head1 AUTHOR
-
-Mark Mentovai
-
-=head1 SEE ALSO
-
-L<bless(8)>, L<diskutil(8)>, L<hdid(8)>, L<hdiutil(1)>, L<Rez(1)>,
-L<rsync(1)>, L<SetFile(1)>
-
-=cut
-
-use Fcntl;
-use POSIX;
-use Getopt::Long;
-
-sub argumentEscape(@);
-sub cleanupDie($);
-sub command(@);
-sub commandInternal($@);
-sub commandInternalVerbosity($$@);
-sub commandOutput(@);
-sub commandOutputVerbosity($@);
-sub commandVerbosity($@);
-sub copyFiles($@);
-sub diskImageMaker($$$$$$$$);
-sub giveExtension($$);
-sub hdidMountImage($@);
-sub isFormatCompressed($);
-sub licenseMaker($$);
-sub pathSplit($);
-sub setAttributes($@);
-sub trapSignal($);
-sub usage();
-
-# Variables used as globals
-my(@gCleanup, %gConfig, $gDarwinMajor, $gDryRun, $gVerbosity);
-
-# Use the commands by name if they're expected to be in the user's
-# $PATH (/bin:/sbin:/usr/bin:/usr/sbin).  Otherwise, go by absolute
-# path.  These may be overridden with --config.
-%gConfig = ('cmd_bless'          => 'bless',
-            'cmd_chmod'          => 'chmod',
-            'cmd_diskutil'       => 'diskutil',
-            'cmd_du'             => 'du',
-            'cmd_hdid'           => 'hdid',
-            'cmd_hdiutil'        => 'hdiutil',
-            'cmd_mkdir'          => 'mkdir',
-            'cmd_mktemp'         => 'mktemp',
-            'cmd_Rez'            => 'Rez',
-            'cmd_rm'             => 'rm',
-            'cmd_rsync'          => 'rsync',
-            'cmd_SetFile'        => 'SetFile',
-
-            # create_directly indicates whether hdiutil create supports
-            # -srcfolder and -srcdevice.  It does on >= 10.3 (Panther).
-            # This is fixed up for earlier systems below.  If false,
-            # hdiutil create is used to create empty disk images that
-            # are manually filled.
-            'create_directly'    => 1,
-
-            # If hdiutil attach -mountpoint exists, use it to avoid
-            # mounting disk images in the default /Volumes.  This reduces
-            # the likelihood that someone will notice a mounted image and
-            # interfere with it.  Only available on >= 10.3 (Panther),
-            # fixed up for earlier systems below.
-            #
-            # This is presently turned off for all systems, because there
-            # is an infrequent synchronization problem during ejection.
-            # diskutil eject might return before the image is actually
-            # unmounted.  If pkg-dmg then attempts to clean up its
-            # temporary directory, it could remove items from a read-write
-            # disk image or attempt to remove items from a read-only disk
-            # image (or a read-only item from a read-write image) and fail,
-            # causing pkg-dmg to abort.  This problem is experienced
-            # under Tiger, which appears to eject asynchronously where
-            # previous systems treated it as a synchronous operation.
-            # Using hdiutil attach -mountpoint didn't always keep images
-            # from showing up on the desktop anyway.
-            'hdiutil_mountpoint' => 0,
-
-            # hdiutil makehybrid results in optimized disk images that
-            # consume less space and mount more quickly.  Use it when
-            # it's available, but that's only on >= 10.3 (Panther).
-            # If false, hdiutil create is used instead.  Fixed up for
-            # earlier systems below.
-            'makehybrid'         => 1,
-
-            # hdiutil create doesn't allow specifying a folder to open
-            # at volume mount time, so those images are mounted and
-            # their root folders made holy with bless -openfolder.  But
-            # only on >= 10.3 (Panther).  Earlier systems are out of luck.
-            # Even on Panther, bless refuses to run unless root.
-            # Fixed up below.
-            'openfolder_bless'   => 1,
-
-            # It's possible to save a few more kilobytes by including the
-            # partition only without any partition table in the image.
-            # This is a good idea on any system, so turn this option off.
-            #
-            # Except it's buggy.  "-layout NONE" seems to be creating
-            # disk images with more data than just the partition table
-            # stripped out.  You might wind up losing the end of the
-            # filesystem - the last file (or several) might be incomplete.
-            'partition_table'    => 1,
-
-            # To create a partition table-less image from something
-            # created by makehybrid, the hybrid image needs to be
-            # mounted and a new image made from the device associated
-            # with the relevant partition.  This requires >= 10.4
-            # (Tiger), presumably because earlier systems have
-            # problems creating images from devices themselves attached
-            # to images.  If this is false, makehybrid images will
-            # have partition tables, regardless of the partition_table
-            # setting.  Fixed up for earlier systems below.
-            'recursive_access'   => 1);
-
-# --verbosity
-$gVerbosity = 2;
-
-# --dry-run
-$gDryRun = 0;
-
-# %gConfig fix-ups based on features and bugs present in certain releases.
-my($ignore, $uname_r, $uname_s);
-($uname_s, $ignore, $uname_r, $ignore, $ignore) = POSIX::uname();
-if($uname_s eq 'Darwin') {
-  ($gDarwinMajor, $ignore) = split(/\./, $uname_r, 2);
-
-  # $major is the Darwin major release, which for our purposes, is 4 higher
-  # than the interesting digit in a Mac OS X release.
-  if($gDarwinMajor <= 6) {
-    # <= 10.2 (Jaguar)
-    # hdiutil create does not support -srcfolder or -srcdevice
-    $gConfig{'create_directly'} = 0;
-    # hdiutil attach does not support -mountpoint
-    $gConfig{'hdiutil_mountpoint'} = 0;
-    # hdiutil mkhybrid does not exist
-    $gConfig{'makehybrid'} = 0;
-  }
-  if($gDarwinMajor <= 7) {
-    # <= 10.3 (Panther)
-    # Can't mount a disk image and then make a disk image from the device
-    $gConfig{'recursive_access'} = 0;
-    # bless does not support -openfolder on 10.2 (Jaguar) and must run
-    # as root under 10.3 (Panther)
-    $gConfig{'openfolder_bless'} = 0;
-  }
-}
-else {
-  # If it's not Mac OS X, just assume all of those good features are
-  # available.  They're not, but things will fail long before they
-  # have a chance to make a difference.
-  #
-  # Now, if someone wanted to document some of these private formats...
-  print STDERR ($0.": warning, not running on Mac OS X, ".
-   "this could be interesting.\n");
-}
-
-# Non-global variables used in Getopt
-my(@attributes, @copyFiles, @createSymlinks, $iconFile, $idme, $licenseFile,
- @makeDirs, $outputFormat, @resourceFiles, $sourceFile, $sourceFolder,
- $targetImage, $tempDir, $volumeName);
-
-# --format
-$outputFormat = 'UDBZ';
-
-# --idme
-$idme = 0;
-
-# --sourcefile
-$sourceFile = 0;
-
-# Leaving this might screw up the Apple tools.
-delete $ENV{'NEXT_ROOT'};
-
-# This script can get pretty messy, so trap a few signals.
-$SIG{'INT'} = \&trapSignal;
-$SIG{'HUP'} = \&trapSignal;
-$SIG{'TERM'} = \&trapSignal;
-
-Getopt::Long::Configure('pass_through');
-GetOptions('source=s'    => \$sourceFolder,
-           'target=s'    => \$targetImage,
-           'volname=s'   => \$volumeName,
-           'format=s'    => \$outputFormat,
-           'tempdir=s'   => \$tempDir,
-           'mkdir=s'     => \@makeDirs,
-           'copy=s'      => \@copyFiles,
-           'symlink=s'   => \@createSymlinks,
-           'license=s'   => \$licenseFile,
-           'resource=s'  => \@resourceFiles,
-           'icon=s'      => \$iconFile,
-           'attribute=s' => \@attributes,
-           'idme'        => \$idme,
-           'sourcefile'  => \$sourceFile,
-           'verbosity=i' => \$gVerbosity,
-           'dry-run'     => \$gDryRun,
-           'config=s'    => \%gConfig); # "hidden" option not in usage()
-
-if(@ARGV) {
-  # All arguments are parsed by Getopt
-  usage();
-  exit(1);
-}
-
-if($gVerbosity<0 || $gVerbosity>2) {
-  usage();
-  exit(1);
-}
-
-if(!defined($sourceFolder) || $sourceFolder eq '' ||
- !defined($targetImage) || $targetImage eq '') {
-  # --source and --target are required arguments
-  usage();
-  exit(1);
-}
-
-# Make sure $sourceFolder doesn't contain trailing slashes.  It messes with
-# rsync.
-while(substr($sourceFolder, -1) eq '/') {
-  chop($sourceFolder);
-}
-
-if(!defined($volumeName)) {
-  # Default volumeName is the name of the source directory.
-  my(@components);
-  @components = pathSplit($sourceFolder);
-  $volumeName = pop(@components);
-}
-
-my(@tempDirComponents, $targetImageFilename);
-@tempDirComponents = pathSplit($targetImage);
-$targetImageFilename = pop(@tempDirComponents);
-
-if(defined($tempDir)) {
-  @tempDirComponents = pathSplit($tempDir);
-}
-else {
-  # Default tempDir is the same directory as what is specified for
-  # targetImage
-  $tempDir = join('/', @tempDirComponents);
-}
-
-# Ensure that the path of the target image has a suitable extension.  If
-# it didn't, hdiutil would add one, and we wouldn't be able to find the
-# file.
-#
-# Note that $targetImageFilename is not being reset.  This is because it's
-# used to build other names below, and we don't need to be adding all sorts
-# of extra unnecessary extensions to the name.
-my($originalTargetImage, $requiredExtension);
-$originalTargetImage = $targetImage;
-if($outputFormat eq 'UDSP') {
-  $requiredExtension = '.sparseimage';
-}
-else {
-  $requiredExtension = '.dmg';
-}
-$targetImage = giveExtension($originalTargetImage, $requiredExtension);
-
-if($targetImage ne $originalTargetImage) {
-  print STDERR ($0.": warning: target image extension is being added\n");
-  print STDERR ('  The new filename is '.
-   giveExtension($targetImageFilename,$requiredExtension)."\n");
-}
-
-# Make a temporary directory in $tempDir for our own nefarious purposes.
-my(@output, $tempSubdir, $tempSubdirTemplate);
-$tempSubdirTemplate=join('/', @tempDirComponents,
- 'pkg-dmg.'.$$.'.XXXXXXXX');
-if(!(@output = commandOutput($gConfig{'cmd_mktemp'}, '-d',
- $tempSubdirTemplate)) || $#output != 0) {
-  cleanupDie('mktemp failed');
-}
-
-if($gDryRun) {
-  (@output)=($tempSubdirTemplate);
-}
-
-($tempSubdir) = @output;
-
-push(@gCleanup,
- sub {commandVerbosity(0, $gConfig{'cmd_rm'}, '-rf', $tempSubdir);});
-
-my($tempMount, $tempRoot, @tempsToMake);
-$tempRoot = $tempSubdir.'/stage';
-$tempMount = $tempSubdir.'/mount';
-push(@tempsToMake, $tempRoot);
-if($gConfig{'hdiutil_mountpoint'}) {
-  push(@tempsToMake, $tempMount);
-}
-
-if(command($gConfig{'cmd_mkdir'}, @tempsToMake) != 0) {
-  cleanupDie('mkdir tempRoot/tempMount failed');
-}
-
-# This cleanup object is not strictly necessary, because $tempRoot is inside
-# of $tempSubdir, but the rest of the script relies on this object being
-# on the cleanup stack and expects to remove it.
-push(@gCleanup,
- sub {commandVerbosity(0, $gConfig{'cmd_rm'}, '-rf', $tempRoot);});
-
-# If $sourceFile is true, it means that $sourceFolder is to be treated as
-# a file and placed as a file within the volume root, as opposed to being
-# treated as the volume root itself.  rsync will do this by default, if no
-# trailing '/' is present.  With a trailing '/', $sourceFolder becomes
-# $tempRoot, instead of becoming an entry in $tempRoot.
-if(command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links',
- $sourceFolder.($sourceFile?'':'/'),$tempRoot) != 0) {
-  cleanupDie('rsync failed');
-}
-
-if(@makeDirs) {
-  my($makeDir, @tempDirsToMake);
-  foreach $makeDir (@makeDirs) {
-    if($makeDir =~ /^\//) {
-      push(@tempDirsToMake, $tempRoot.$makeDir);
-    }
-    else {
-      push(@tempDirsToMake, $tempRoot.'/'.$makeDir);
-    }
-  }
-  if(command($gConfig{'cmd_mkdir'}, '-p', @tempDirsToMake) != 0) {
-    cleanupDie('mkdir failed');
-  }
-}
-
-# copy files and/or create symlinks
-copyFiles($tempRoot, 'copy', @copyFiles);
-copyFiles($tempRoot, 'symlink', @createSymlinks);
-
-if($gConfig{'create_directly'}) {
-  # If create_directly is false, the contents will be rsynced into a
-  # disk image and they would lose their attributes.
-  setAttributes($tempRoot, @attributes);
-}
-
-if(defined($iconFile)) {
-  if(command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links', $iconFile,
-   $tempRoot.'/.VolumeIcon.icns') != 0) {
-    cleanupDie('rsync failed for volume icon');
-  }
-
-  # It's pointless to set the attributes of the root when diskutil create
-  # -srcfolder is being used.  In that case, the attributes will be set
-  # later, after the image is already created.
-  if(isFormatCompressed($outputFormat) &&
-   (command($gConfig{'cmd_SetFile'}, '-a', 'C', $tempRoot) != 0)) {
-    cleanupDie('SetFile failed');
-  }
-}
-
-if(command($gConfig{'cmd_chmod'}, '-R', 'a+rX,a-st,u+w,go-w',
- $tempRoot) != 0) {
-  cleanupDie('chmod failed');
-}
-
-my($unflattenable);
-if(isFormatCompressed($outputFormat)) {
-  $unflattenable = 1;
-}
-else {
-  $unflattenable = 0;
-}
-
-diskImageMaker($tempRoot, $targetImage, $outputFormat, $volumeName,
- $tempSubdir, $tempMount, $targetImageFilename, defined($iconFile));
-
-if(defined($licenseFile) && $licenseFile ne '') {
-  my($licenseResource);
-  $licenseResource = $tempSubdir.'/license.r';
-  if(!licenseMaker($licenseFile, $licenseResource)) {
-    cleanupDie('licenseMaker failed');
-  }
-  push(@resourceFiles, $licenseResource);
-  # Don't add a cleanup object because licenseResource is in tempSubdir.
-}
-
-if(@resourceFiles) {
-  # Add resources, such as a license agreement.
-
-  # Only unflatten read-only and compressed images.  It's not supported
-  # on other image times.
-  if($unflattenable &&
-   (command($gConfig{'cmd_hdiutil'}, 'unflatten', $targetImage)) != 0) {
-    cleanupDie('hdiutil unflatten failed');
-  }
-  # Don't push flatten onto the cleanup stack.  If we fail now, we'll be
-  # removing $targetImage anyway.
-
-  # Type definitions come from Carbon.r.
-  if(command($gConfig{'cmd_Rez'}, 'Carbon.r', @resourceFiles, '-a', '-o',
-   $targetImage) != 0) {
-    cleanupDie('Rez failed');
-  }
-
-  # Flatten.  This merges the resource fork into the data fork, so no
-  # special encoding is needed to transfer the file.
-  if($unflattenable &&
-   (command($gConfig{'cmd_hdiutil'}, 'flatten', $targetImage)) != 0) {
-    cleanupDie('hdiutil flatten failed');
-  }
-}
-
-# $tempSubdir is no longer needed.  It's buried on the stack below the
-# rm of the fresh image file.  Splice in this fashion is equivalent to
-# pop-save, pop, push-save.
-splice(@gCleanup, -2, 1);
-# No need to remove licenseResource separately, it's in tempSubdir.
-if(command($gConfig{'cmd_rm'}, '-rf', $tempSubdir) != 0) {
-  cleanupDie('rm -rf tempSubdir failed');
-}
-
-if($idme) {
-  if(command($gConfig{'cmd_hdiutil'}, 'internet-enable', '-yes',
-   $targetImage) != 0) {
-    cleanupDie('hdiutil internet-enable failed');
-  }
-}
-
-# Done.
-
-exit(0);
-
-# argumentEscape(@arguments)
-#
-# Takes a list of @arguments and makes them shell-safe.
-sub argumentEscape(@) {
-  my(@arguments);
-  @arguments = @_;
-  my($argument, @argumentsOut);
-  foreach $argument (@arguments) {
-    $argument =~ s%([^A-Za-z0-9_\-/.=+,])%\\$1%g;
-    push(@argumentsOut, $argument);
-  }
-  return @argumentsOut;
-}
-
-# cleanupDie($message)
-#
-# Displays $message as an error message, and then runs through the
-# @gCleanup stack, performing any cleanup operations needed before
-# exiting.  Does not return, exits with exit status 1.
-sub cleanupDie($) {
-  my($message);
-  ($message) = @_;
-  print STDERR ($0.': '.$message.(@gCleanup?' (cleaning up)':'')."\n");
-  while(@gCleanup) {
-    my($subroutine);
-    $subroutine = pop(@gCleanup);
-    &$subroutine;
-  }
-  exit(1);
-}
-
-# command(@arguments)
-#
-# Runs the specified command at the verbosity level defined by $gVerbosity.
-# Returns nonzero on failure, returning the exit status if appropriate.
-# Discards command output.
-sub command(@) {
-  my(@arguments);
-  @arguments = @_;
-  return commandVerbosity($gVerbosity,@arguments);
-}
-
-# commandInternal($command, @arguments)
-#
-# Runs the specified internal command at the verbosity level defined by
-# $gVerbosity.
-# Returns zero(!) on failure, because commandInternal is supposed to be a
-# direct replacement for the Perl system call wrappers, which, unlike shell
-# commands and C equivalent system calls, return true (instead of 0) to
-# indicate success.
-sub commandInternal($@) {
-  my(@arguments, $command);
-  ($command, @arguments) = @_;
-  return commandInternalVerbosity($gVerbosity, $command, @arguments);
-}
-
-# commandInternalVerbosity($verbosity, $command, @arguments)
-#
-# Run an internal command, printing a bogus command invocation message if
-# $verbosity is true.
-#
-# If $command is unlink:
-# Removes the files specified by @arguments.  Wraps unlink.
-#
-# If $command is symlink:
-# Creates the symlink specified by @arguments. Wraps symlink.
-sub commandInternalVerbosity($$@) {
-  my(@arguments, $command, $verbosity);
-  ($verbosity, $command, @arguments) = @_;
-  if($command eq 'unlink') {
-    if($verbosity || $gDryRun) {
-      print(join(' ', 'rm', '-f', argumentEscape(@arguments))."\n");
-    }
-    if($gDryRun) {
-      return $#arguments+1;
-    }
-    return unlink(@arguments);
-  }
-  elsif($command eq 'symlink') {
-    if($verbosity || $gDryRun) {
-      print(join(' ', 'ln', '-s', argumentEscape(@arguments))."\n");
-    }
-    if($gDryRun) {
-      return 1;
-    }
-    my($source, $target);
-    ($source, $target) = @arguments;
-    return symlink($source, $target);
-  }
-}
-
-# commandOutput(@arguments)
-#
-# Runs the specified command at the verbosity level defined by $gVerbosity.
-# Output is returned in an array of lines.  undef is returned on failure.
-# The exit status is available in $?.
-sub commandOutput(@) {
-  my(@arguments);
-  @arguments = @_;
-  return commandOutputVerbosity($gVerbosity, @arguments);
-}
-
-# commandOutputVerbosity($verbosity, @arguments)
-#
-# Runs the specified command at the verbosity level defined by the
-# $verbosity argument.  Output is returned in an array of lines.  undef is
-# returned on failure.  The exit status is available in $?.
-#
-# If an error occurs in fork or exec, an error message is printed to
-# stderr and undef is returned.
-#
-# If $verbosity is 0, the command invocation is not printed, and its
-# stdout is not echoed back to stdout.
-#
-# If $verbosity is 1, the command invocation is printed.
-#
-# If $verbosity is 2, the command invocation is printed and the output
-# from stdout is echoed back to stdout.
-#
-# Regardless of $verbosity, stderr is left connected.
-sub commandOutputVerbosity($@) {
-  my(@arguments, $verbosity);
-  ($verbosity, @arguments) = @_;
-  my($pid);
-  if($verbosity || $gDryRun) {
-    print(join(' ', argumentEscape(@arguments))."\n");
-  }
-  if($gDryRun) {
-    return(1);
-  }
-  if (!defined($pid = open(*COMMAND, '-|'))) {
-    printf STDERR ($0.': fork: '.$!."\n");
-    return undef;
-  }
-  elsif ($pid) {
-    # parent
-    my(@lines);
-    while(!eof(*COMMAND)) {
-      my($line);
-      chop($line = <COMMAND>);
-      if($verbosity > 1) {
-        print($line."\n");
-      }
-      push(@lines, $line);
-    }
-    close(*COMMAND);
-    if ($? == -1) {
-      printf STDERR ($0.': fork: '.$!."\n");
-      return undef;
-    }
-    elsif ($? & 127) {
-      printf STDERR ($0.': exited on signal '.($? & 127).
-       ($? & 128 ? ', core dumped' : '')."\n");
-      return undef;
-    }
-    return @lines;
-  }
-  else {
-    # child; this form of exec is immune to shell games
-    if(!exec {$arguments[0]} (@arguments)) {
-      printf STDERR ($0.': exec: '.$!."\n");
-      exit(-1);
-    }
-  }
-}
-
-# commandVerbosity($verbosity, @arguments)
-#
-# Runs the specified command at the verbosity level defined by the
-# $verbosity argument.  Returns nonzero on failure, returning the exit
-# status if appropriate.  Discards command output.
-sub commandVerbosity($@) {
-  my(@arguments, $verbosity);
-  ($verbosity, @arguments) = @_;
-  if(!defined(commandOutputVerbosity($verbosity, @arguments))) {
-    return -1;
-  }
-  return $?;
-}
-
-# copyFiles($tempRoot, $method, @arguments)
-#
-# Copies files or create symlinks in the disk image.
-# See --copy and --symlink descriptions for details.
-# If $method is 'copy', @arguments are interpreted as source:target, if $method
-# is 'symlink', @arguments are interpreted as symlink:target.
-sub copyFiles($@) {
-  my(@fileList, $method, $tempRoot);
-  ($tempRoot, $method, @fileList) = @_;
-  my($file, $isSymlink);
-  $isSymlink = ($method eq 'symlink');
-  foreach $file (@fileList) {
-    my($source, $target);
-    ($source, $target) = split(/:/, $file);
-    if(!defined($target) and $isSymlink) {
-      # empty symlink targets would result in an invalid target and fail,
-      # but they shall be interpreted as "like source path, but inside dmg"
-      $target = $source;
-    }
-    if(!defined($target)) {
-      $target = $tempRoot;
-    }
-    elsif($target =~ /^\//) {
-      $target = $tempRoot.$target;
-    }
-    else {
-      $target = $tempRoot.'/'.$target;
-    }
-
-    my($success);
-    if($isSymlink) {
-      $success = commandInternal('symlink', $source, $target);
-    }
-    else {
-      $success = !command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links',
-                          $source, $target);
-    }
-    if(!$success) {
-      cleanupDie('copyFiles failed for method '.$method);
-    }
-  }
-}
-
-# diskImageMaker($source, $destination, $format, $name, $tempDir, $tempMount,
-#  $baseName, $setRootIcon)
-#
-# Creates a disk image in $destination of format $format corresponding to the
-# source directory $source.  $name is the volume name.  $tempDir is a good
-# place to write temporary files, which should be empty (aside from the other
-# things that this script might create there, like stage and mount).
-# $tempMount is a mount point for temporary disk images.  $baseName is the
-# name of the disk image, and is presently unused.  $setRootIcon is true if
-# a volume icon was added to the staged $source and indicates that the
-# custom volume icon bit on the volume root needs to be set.
-sub diskImageMaker($$$$$$$$) {
-  my($baseName, $destination, $format, $name, $setRootIcon, $source,
-   $tempDir, $tempMount);
-  ($source, $destination, $format, $name, $tempDir, $tempMount,
-   $baseName, $setRootIcon) = @_;
-  if(isFormatCompressed($format)) {
-    my($uncompressedImage);
-
-    if($gConfig{'makehybrid'}) {
-      my($hybridImage);
-      $hybridImage = giveExtension($tempDir.'/hybrid', '.dmg');
-
-      if(command($gConfig{'cmd_hdiutil'}, 'makehybrid', '-hfs',
-       '-hfs-volume-name', $name, '-hfs-openfolder', $source, '-ov',
-       $source, '-o', $hybridImage) != 0) {
-        cleanupDie('hdiutil makehybrid failed');
-      }
-
-      $uncompressedImage = $hybridImage;
-
-      # $source is no longer needed and will be removed before anything
-      # else can fail.  splice in this form is the same as pop/push.
-      splice(@gCleanup, -1, 1,
-       sub {commandInternalVerbosity(0, 'unlink', $hybridImage);});
-
-      if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) {
-        cleanupDie('rm -rf failed');
-      }
-
-      if(!$gConfig{'partition_table'} && $gConfig{'recursive_access'}) {
-        # Even if we do want to create disk images without partition tables,
-        # it's impossible unless recursive_access is set.
-        my($rootDevice, $partitionDevice, $partitionMountPoint);
-
-        if(!(($rootDevice, $partitionDevice, $partitionMountPoint) =
-         hdidMountImage($tempMount, '-readonly', $hybridImage))) {
-          cleanupDie('hdid mount failed');
-        }
-
-        push(@gCleanup, sub {commandVerbosity(0,
-         $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);});
-
-        my($udrwImage);
-        $udrwImage = giveExtension($tempDir.'/udrw', '.dmg');
-
-        if(command($gConfig{'cmd_hdiutil'}, 'create', '-format', 'UDRW',
-         '-ov', '-srcdevice', $partitionDevice, $udrwImage) != 0) {
-          cleanupDie('hdiutil create failed');
-        }
-
-        $uncompressedImage = $udrwImage;
-
-        # Going to eject before anything else can fail.  Get the eject off
-        # the stack.
-        pop(@gCleanup);
-
-        # $hybridImage will be removed soon, but until then, it needs to
-        # stay on the cleanup stack.  It needs to wait until after
-        # ejection.  $udrwImage is staying around.  Make it appear as
-        # though it's been done before $hybridImage.
-        #
-        # splice in this form is the same as popping one element to
-        # @tempCleanup and pushing the subroutine.
-        my(@tempCleanup);
-        @tempCleanup = splice(@gCleanup, -1, 1,
-         sub {commandInternalVerbosity(0, 'unlink', $udrwImage);});
-        push(@gCleanup, @tempCleanup);
-
-        if(command($gConfig{'cmd_diskutil'}, 'eject', $rootDevice) != 0) {
-          cleanupDie('diskutil eject failed');
-        }
-
-        # Pop unlink of $uncompressedImage
-        pop(@gCleanup);
-
-        if(commandInternal('unlink', $hybridImage) != 1) {
-          cleanupDie('unlink hybridImage failed: '.$!);
-        }
-      }
-    }
-    else {
-      # makehybrid is not available, fall back to making a UDRW and
-      # converting to a compressed image.  It ought to be possible to
-      # create a compressed image directly, but those come out far too
-      # large (journaling?) and need to be read-write to fix up the
-      # volume icon anyway.  Luckily, we can take advantage of a single
-      # call back into this function.
-      my($udrwImage);
-      $udrwImage = giveExtension($tempDir.'/udrw', '.dmg');
-
-      diskImageMaker($source, $udrwImage, 'UDRW', $name, $tempDir,
-       $tempMount, $baseName, $setRootIcon);
-
-      # The call back into diskImageMaker already removed $source.
-
-      $uncompressedImage = $udrwImage;
-    }
-
-    # The uncompressed disk image is now in its final form.  Compress it.
-    # Jaguar doesn't support hdiutil convert -ov, but it always allows
-    # overwriting.
-    # bzip2-compressed UDBZ images can only be created and mounted on 10.4
-    # and later.  The bzip2-level imagekey is only effective when creating
-    # images in 10.5.  In 10.4, bzip2-level is harmlessly ignored, and the
-    # default value of 1 is always used.
-    if(command($gConfig{'cmd_hdiutil'}, 'convert', '-format', $format,
-     '-imagekey', ($format eq 'UDBZ' ? 'bzip2-level=9' : 'zlib-level=9'),
-     (defined($gDarwinMajor) && $gDarwinMajor <= 6 ? () : ('-ov')),
-     $uncompressedImage, '-o', $destination) != 0) {
-      cleanupDie('hdiutil convert failed');
-    }
-
-    # $uncompressedImage is going to be unlinked before anything else can
-    # fail.  splice in this form is the same as pop/push.
-    splice(@gCleanup, -1, 1,
-     sub {commandInternalVerbosity(0, 'unlink', $destination);});
-
-    if(commandInternal('unlink', $uncompressedImage) != 1) {
-      cleanupDie('unlink uncompressedImage failed: '.$!);
-    }
-
-    # At this point, the only thing that the compressed block has added to
-    # the cleanup stack is the removal of $destination.  $source has already
-    # been removed, and its cleanup entry has been removed as well.
-  }
-  elsif($format eq 'UDRW' || $format eq 'UDSP') {
-    my(@extraArguments);
-    if(!$gConfig{'partition_table'}) {
-      @extraArguments = ('-layout', 'NONE');
-    }
-
-    if($gConfig{'create_directly'}) {
-      # Use -fs HFS+ to suppress the journal.
-      if(command($gConfig{'cmd_hdiutil'}, 'create', '-format', $format,
-       @extraArguments, '-fs', 'HFS+', '-volname', $name,
-       '-ov', '-srcfolder', $source, $destination) != 0) {
-        cleanupDie('hdiutil create failed');
-      }
-
-      # $source is no longer needed and will be removed before anything
-      # else can fail.  splice in this form is the same as pop/push.
-      splice(@gCleanup, -1, 1,
-       sub {commandInternalVerbosity(0, 'unlink', $destination);});
-
-      if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) {
-        cleanupDie('rm -rf failed');
-      }
-    }
-    else {
-      # hdiutil create does not support -srcfolder or -srcdevice, it only
-      # knows how to create blank images.  Figure out how large an image
-      # is needed, create it, and fill it.  This is needed for Jaguar.
-
-      # Use native block size for hdiutil create -sectors.
-      delete $ENV{'BLOCKSIZE'};
-
-      my(@duOutput, $ignore, $sizeBlocks, $sizeOverhead, $sizeTotal, $type);
-      if(!(@output = commandOutput($gConfig{'cmd_du'}, '-s', $tempRoot)) ||
-       $? != 0) {
-        cleanupDie('du failed');
-      }
-      ($sizeBlocks, $ignore) = split(' ', $output[0], 2);
-
-      # The filesystem itself takes up 152 blocks of its own blocks for the
-      # filesystem up to 8192 blocks, plus 64 blocks for every additional
-      # 4096 blocks or portion thereof.
-      $sizeOverhead = 152 + 64 * POSIX::ceil(
-       (($sizeBlocks - 8192) > 0) ? (($sizeBlocks - 8192) / (4096 - 64)) : 0);
-
-      # The number of blocks must be divisible by 8.
-      my($mod);
-      if($mod = ($sizeOverhead % 8)) {
-        $sizeOverhead += 8 - $mod;
-      }
-
-      # sectors is taken as the size of a disk, not a filesystem, so the
-      # partition table eats into it.
-      if($gConfig{'partition_table'}) {
-        $sizeOverhead += 80;
-      }
-
-      # That was hard.  Leave some breathing room anyway.  Use 1024 sectors
-      # (512kB).  These read-write images wouldn't be useful if they didn't
-      # have at least a little free space.
-      $sizeTotal = $sizeBlocks + $sizeOverhead + 1024;
-
-      # Minimum sizes - these numbers are larger on Jaguar than on later
-      # systems.  Just use the Jaguar numbers, since it's unlikely to wind
-      # up here on any other release.
-      if($gConfig{'partition_table'} && $sizeTotal < 8272) {
-        $sizeTotal = 8272;
-      }
-      if(!$gConfig{'partition_table'} && $sizeTotal < 8192) {
-        $sizeTotal = 8192;
-      }
-
-      # hdiutil create without -srcfolder or -srcdevice will not accept
-      # -format.  It uses -type.  Fortunately, the two supported formats
-      # here map directly to the only two supported types.
-      if ($format eq 'UDSP') {
-        $type = 'SPARSE';
-      }
-      else {
-        $type = 'UDIF';
-      }
-
-      if(command($gConfig{'cmd_hdiutil'}, 'create', '-type', $type,
-       @extraArguments, '-fs', 'HFS+', '-volname', $name,
-       '-ov', '-sectors', $sizeTotal, $destination) != 0) {
-        cleanupDie('hdiutil create failed');
-      }
-
-      push(@gCleanup,
-       sub {commandInternalVerbosity(0, 'unlink', $destination);});
-
-      # The rsync will occur shortly.
-    }
-
-    my($mounted, $rootDevice, $partitionDevice, $partitionMountPoint);
-
-    $mounted=0;
-    if(!$gConfig{'create_directly'} || $gConfig{'openfolder_bless'} ||
-     $setRootIcon) {
-      # The disk image only needs to be mounted if:
-      #  create_directly is false, because the content needs to be copied
-      #  openfolder_bless is true, because bless -openfolder needs to run
-      #  setRootIcon is true, because the root needs its attributes set.
-      if(!(($rootDevice, $partitionDevice, $partitionMountPoint) =
-       hdidMountImage($tempMount, $destination))) {
-        cleanupDie('hdid mount failed');
-      }
-
-      $mounted=1;
-
-      push(@gCleanup, sub {commandVerbosity(0,
-       $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);});
-    }
-
-    if(!$gConfig{'create_directly'}) {
-      # Couldn't create and copy directly in one fell swoop.  Now that
-      # the volume is mounted, copy the files.  --copy-unsafe-links is
-      # unnecessary since it was used to copy everything to the staging
-      # area.  There can be no more unsafe links.
-      if(command($gConfig{'cmd_rsync'}, '-a',
-       $source.'/',$partitionMountPoint) != 0) {
-        cleanupDie('rsync to new volume failed');
-      }
-
-      # We need to get the rm -rf of $source off the stack, because it's
-      # being cleaned up here.  There are two items now on top of it:
-      # removing the target image and, above that, ejecting it.  Splice it
-      # out.
-      my(@tempCleanup);
-      @tempCleanup = splice(@gCleanup, -2);
-      # The next splice is the same as popping once and pushing @tempCleanup.
-      splice(@gCleanup, -1, 1, @tempCleanup);
-
-      if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) {
-        cleanupDie('rm -rf failed');
-      }
-    }
-
-    if($gConfig{'openfolder_bless'}) {
-      # On Tiger, the bless docs say to use --openfolder, but only
-      # --openfolder is accepted on Panther.  Tiger takes it with a single
-      # dash too.  Jaguar is out of luck.
-      if(command($gConfig{'cmd_bless'}, '-openfolder',
-       $partitionMountPoint) != 0) {
-        cleanupDie('bless failed');
-      }
-    }
-
-    setAttributes($partitionMountPoint, @attributes);
-
-    if($setRootIcon) {
-      # When "hdiutil create -srcfolder" is used, the root folder's
-      # attributes are not copied to the new volume.  Fix up.
-
-      if(command($gConfig{'cmd_SetFile'}, '-a', 'C',
-       $partitionMountPoint) != 0) {
-        cleanupDie('SetFile failed');
-      }
-    }
-
-    if($mounted) {
-      # Pop diskutil eject
-      pop(@gCleanup);
-
-      if(command($gConfig{'cmd_diskutil'}, 'eject', $rootDevice) != 0) {
-        cleanupDie('diskutil eject failed');
-      }
-    }
-
-    # End of UDRW/UDSP section.  At this point, $source has been removed
-    # and its cleanup entry has been removed from the stack.
-  }
-  else {
-    cleanupDie('unrecognized format');
-    print STDERR ($0.": unrecognized format\n");
-    exit(1);
-  }
-}
-
-# giveExtension($file, $extension)
-#
-# If $file does not end in $extension, $extension is added.  The new
-# filename is returned.
-sub giveExtension($$) {
-  my($extension, $file);
-  ($file, $extension) = @_;
-  if(substr($file, -length($extension)) ne $extension) {
-    return $file.$extension;
-  }
-  return $file;
-}
-
-# hdidMountImage($mountPoint, @arguments)
-#
-# Runs the hdid command with arguments specified by @arguments.
-# @arguments may be a single-element array containing the name of the
-# disk image to mount.  Returns a three-element array, with elements
-# corresponding to:
-#  - The root device of the mounted image, suitable for ejection
-#  - The device corresponding to the mounted partition
-#  - The mounted partition's mount point
-#
-# If running on a system that supports easy mounting at points outside
-# of the default /Volumes with hdiutil attach, it is used instead of hdid,
-# and $mountPoint is used as the mount point.
-#
-# The root device will differ from the partition device when the disk
-# image contains a partition table, otherwise, they will be identical.
-#
-# If hdid fails, undef is returned.
-sub hdidMountImage($@) {
-  my(@arguments, @command, $mountPoint);
-  ($mountPoint, @arguments) = @_;
-  my(@output);
-
-  if($gConfig{'hdiutil_mountpoint'}) {
-    @command=($gConfig{'cmd_hdiutil'}, 'attach', @arguments,
-     '-mountpoint', $mountPoint);
-  }
-  else {
-    @command=($gConfig{'cmd_hdid'}, @arguments);
-  }
-
-  if(!(@output = commandOutput(@command)) ||
-   $? != 0) {
-    return undef;
-  }
-
-  if($gDryRun) {
-    return('/dev/diskX','/dev/diskXsY','/Volumes/'.$volumeName);
-  }
-
-  my($line, $restOfLine, $rootDevice);
-
-  foreach $line (@output) {
-    my($device, $mountpoint);
-    if($line !~ /^\/dev\//) {
-      # Consider only lines that correspond to /dev entries
-      next;
-    }
-    ($device, $restOfLine) = split(' ', $line, 2);
-
-    if(!defined($rootDevice) || $rootDevice eq '') {
-      # If this is the first device seen, it's the root device to be
-      # used for ejection.  Keep it.
-      $rootDevice = $device;
-    }
-
-    if($restOfLine =~ /(\/.*)/) {
-      # The first partition with a mount point is the interesting one.  It's
-      # usually Apple_HFS and usually the last one in the list, but beware of
-      # the possibility of other filesystem types and the Apple_Free partition.
-      # If the disk image contains no partition table, the partition will not
-      # have a type, so look for the mount point by looking for a slash.
-      $mountpoint = $1;
-      return($rootDevice, $device, $mountpoint);
-    }
-  }
-
-  # No mount point?  This is bad.  If there's a root device, eject it.
-  if(defined($rootDevice) && $rootDevice ne '') {
-    # Failing anyway, so don't care about failure
-    commandVerbosity(0, $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);
-  }
-
-  return undef;
-}
-
-# isFormatCompressed($format)
-#
-# Returns true if $format corresponds to a compressed disk image format.
-# Returns false otherwise.
-sub isFormatCompressed($) {
-  my($format);
-  ($format) = @_;
-  return $format eq 'UDZO' || $format eq 'UDBZ';
-}
-
-# licenseMaker($text, $resource)
-#
-# Takes a plain text file at path $text and creates a license agreement
-# resource containing the text at path $license.  English-only, and
-# no special formatting.  This is the bare-bones stuff.  For more
-# intricate license agreements, create your own resource.
-#
-# ftp://ftp.apple.com/developer/Development_Kits/SLAs_for_UDIFs_1.0.dmg
-sub licenseMaker($$) {
-  my($resource, $text);
-  ($text, $resource) = @_;
-  if(!sysopen(*TEXT, $text, O_RDONLY)) {
-    print STDERR ($0.': licenseMaker: sysopen text: '.$!."\n");
-    return 0;
-  }
-  if(!sysopen(*RESOURCE, $resource, O_WRONLY|O_CREAT|O_EXCL)) {
-    print STDERR ($0.': licenseMaker: sysopen resource: '.$!."\n");
-    return 0;
-  }
-  print RESOURCE << '__EOT__';
-// See /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/Script.h for language IDs.
-data 'LPic' (5000) {
-  // Default language ID, 0 = English
-  $"0000"
-  // Number of entries in list
-  $"0001"
-
-  // Entry 1
-  // Language ID, 0 = English
-  $"0000"
-  // Resource ID, 0 = STR#/TEXT/styl 5000
-  $"0000"
-  // Multibyte language, 0 = no
-  $"0000"
-};
-
-resource 'STR#' (5000, "English") {
-  {
-    // Language (unused?) = English
-    "English",
-    // Agree
-    "Agree",
-    // Disagree
-    "Disagree",
-__EOT__
-    # This stuff needs double-quotes for interpolations to work.
-    print RESOURCE ("    // Print, ellipsis is 0xC9\n");
-    print RESOURCE ("    \"Print\xc9\",\n");
-    print RESOURCE ("    // Save As, ellipsis is 0xC9\n");
-    print RESOURCE ("    \"Save As\xc9\",\n");
-    print RESOURCE ('    // Descriptive text, curly quotes are 0xD2 and 0xD3'.
-     "\n");
-    print RESOURCE ('    "If you agree to the terms of this license '.
-     "agreement, click \xd2Agree\xd3 to access the software.  If you ".
-     "do not agree, press \xd2Disagree.\xd3\"\n");
-print RESOURCE << '__EOT__';
-  };
-};
-
-// Beware of 1024(?) byte (character?) line length limitation.  Split up long
-// lines.
-// If straight quotes are used ("), remember to escape them (\").
-// Newline is \n, to leave a blank line, use two of them.
-// 0xD2 and 0xD3 are curly double-quotes ("), 0xD4 and 0xD5 are curly
-//   single quotes ('), 0xD5 is also the apostrophe.
-data 'TEXT' (5000, "English") {
-__EOT__
-
-  while(!eof(*TEXT)) {
-    my($line);
-    chop($line = <TEXT>);
-
-    while(defined($line)) {
-      my($chunk);
-
-      # Rez doesn't care for lines longer than (1024?) characters.  Split
-      # at less than half of that limit, in case everything needs to be
-      # backwhacked.
-      if(length($line)>500) {
-        $chunk = substr($line, 0, 500);
-        $line = substr($line, 500);
-      }
-      else {
-        $chunk = $line;
-        $line = undef;
-      }
-
-      if(length($chunk) > 0) {
-        # Unsafe characters are the double-quote (") and backslash (\), escape
-        # them with backslashes.
-        $chunk =~ s/(["\\])/\\$1/g;
-
-        print RESOURCE '  "'.$chunk.'"'."\n";
-      }
-    }
-    print RESOURCE '  "\n"'."\n";
-  }
-  close(*TEXT);
-
-  print RESOURCE << '__EOT__';
-};
-
-data 'styl' (5000, "English") {
-  // Number of styles following = 1
-  $"0001"
-
-  // Style 1.  This is used to display the first two lines in bold text.
-  // Start character = 0
-  $"0000 0000"
-  // Height = 16
-  $"0010"
-  // Ascent = 12
-  $"000C"
-  // Font family = 1024 (Lucida Grande)
-  $"0400"
-  // Style bitfield, 0x1=bold 0x2=italic 0x4=underline 0x8=outline
-  // 0x10=shadow 0x20=condensed 0x40=extended
-  $"00"
-  // Style, unused?
-  $"02"
-  // Size = 12 point
-  $"000C"
-  // Color, RGB
-  $"0000 0000 0000"
-};
-__EOT__
-  close(*RESOURCE);
-
-  return 1;
-}
-
-# pathSplit($pathname)
-#
-# Splits $pathname into an array of path components.
-sub pathSplit($) {
-  my($pathname);
-  ($pathname) = @_;
-  return split(/\//, $pathname);
-}
-
-# setAttributes($root, @attributeList)
-#
-# @attributeList is an array, each element of which must be in the form
-# <a>:<file>.  <a> is a list of attributes, per SetFile.  <file> is a file
-# which is taken as relative to $root (even if it appears as an absolute
-# path.)  SetFile is called to set the attributes on each file in
-# @attributeList.
-sub setAttributes($@) {
-  my(@attributes, $root);
-  ($root, @attributes) = @_;
-  my($attribute);
-  foreach $attribute (@attributes) {
-    my($attrList, $file, @fileList, @fixedFileList);
-    ($attrList, @fileList) = split(/:/, $attribute);
-    if(!defined($attrList) || !@fileList) {
-      cleanupDie('--attribute requires <attributes>:<file>');
-    }
-    @fixedFileList=();
-    foreach $file (@fileList) {
-      if($file =~ /^\//) {
-        push(@fixedFileList, $root.$file);
-      }
-      else {
-        push(@fixedFileList, $root.'/'.$file);
-      }
-    }
-    if(command($gConfig{'cmd_SetFile'}, '-a', $attrList, @fixedFileList)) {
-      cleanupDie('SetFile failed to set attributes');
-    }
-  }
-  return;
-}
-
-sub trapSignal($) {
-  my($signalName);
-  ($signalName) = @_;
-  cleanupDie('exiting on SIG'.$signalName);
-}
-
-sub usage() {
-  print STDERR (
-"usage: pkg-dmg --source <source-folder>\n".
-"               --target <target-image>\n".
-"              [--format <format>]           (default: UDZO)\n".
-"              [--volname <volume-name>]     (default: same name as source)\n".
-"              [--tempdir <temp-dir>]        (default: same dir as target)\n".
-"              [--mkdir <directory>]         (make directory in image)\n".
-"              [--copy <source>[:<dest>]]    (extra files to add)\n".
-"              [--symlink <source>[:<dest>]] (extra symlinks to add)\n".
-"              [--license <file>]            (plain text license agreement)\n".
-"              [--resource <file>]           (flat .r files to merge)\n".
-"              [--icon <icns-file>]          (volume icon)\n".
-"              [--attribute <a>:<file>]      (set file attributes)\n".
-"              [--idme]                      (make Internet-enabled image)\n".
-"              [--sourcefile]                (treat --source as a file)\n".
-"              [--verbosity <level>]         (0, 1, 2; default=2)\n".
-"              [--dry-run]                   (print what would be done)\n");
-  return;
-}
--- a/build/virtualenv_packages.txt
+++ b/build/virtualenv_packages.txt
@@ -25,8 +25,9 @@ packages.txt:testing/mozbase/packages.tx
 objdir:build
 gyp.pth:media/webrtc/trunk/tools/gyp/pylib
 pyasn1.pth:python/pyasn1
 pyasn1_modules.pth:python/pyasn1-modules
 bitstring.pth:python/bitstring
 redo.pth:python/redo
 requests.pth:python/requests
 rsa.pth:python/rsa
+futures.pth:python/futures
--- a/config/check_macroassembler_style.py
+++ b/config/check_macroassembler_style.py
@@ -25,18 +25,18 @@ from __future__ import print_function
 import difflib
 import os
 import re
 import subprocess
 import sys
 from check_utils import get_all_toplevel_filenames
 
 architecture_independent = set([ 'generic' ])
-all_architecture_names = set([ 'x86', 'x64', 'arm', 'arm64', 'mips' ])
-all_shared_architecture_names = set([ 'x86_shared', 'arm', 'arm64', 'mips' ])
+all_architecture_names = set([ 'x86', 'x64', 'arm', 'arm64', 'mips32' ])
+all_shared_architecture_names = set([ 'x86_shared', 'arm', 'arm64', 'mips32' ])
 
 def get_normalized_signatures(signature, fileAnnot = None):
     # Remove semicolon.
     signature = signature.replace(';', ' ')
     # Normalize spaces.
     signature = re.sub(r'\s+', ' ', signature).strip()
     # Remove argument names.
     signature = re.sub(r'(?P<type>(?:[(]|,\s)[\w\s:*&]+)(?P<name>\s\w+)(?=[,)])', '\g<type>', signature)
--- a/dom/base/DOMRequest.cpp
+++ b/dom/base/DOMRequest.cpp
@@ -4,18 +4,18 @@
  * 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 "DOMRequest.h"
 
 #include "DOMError.h"
 #include "nsThreadUtils.h"
 #include "DOMCursor.h"
-#include "nsIDOMEvent.h"
 #include "mozilla/ErrorResult.h"
+#include "mozilla/dom/Event.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 using mozilla::dom::AnyCallback;
 using mozilla::dom::DOMError;
 using mozilla::dom::DOMRequest;
 using mozilla::dom::DOMRequestService;
 using mozilla::dom::DOMCursor;
@@ -187,18 +187,17 @@ DOMRequest::FireDetailedError(DOMError* 
 
 void
 DOMRequest::FireEvent(const nsAString& aType, bool aBubble, bool aCancelable)
 {
   if (NS_FAILED(CheckInnerWindowCorrectness())) {
     return;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
   nsresult rv = event->InitEvent(aType, aBubble, aCancelable);
   if (NS_FAILED(rv)) {
     return;
   }
 
   event->SetTrusted(true);
 
   bool dummy;
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -840,22 +840,17 @@ EventSource::AnnounceConnection()
 
   mReadyState = OPEN;
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to create the open event!!!");
-    return;
-  }
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
   // it doesn't bubble, and it isn't cancelable
   rv = event->InitEvent(NS_LITERAL_STRING("open"), false, false);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to init the open event!!!");
     return;
   }
 
@@ -905,22 +900,17 @@ EventSource::ReestablishConnection()
     return;
   }
 
   rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to create the error event!!!");
-    return;
-  }
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
   // it doesn't bubble, and it isn't cancelable
   rv = event->InitEvent(NS_LITERAL_STRING("error"), false, false);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to init the error event!!!");
     return;
   }
 
@@ -1061,22 +1051,17 @@ EventSource::FailConnection()
 
   Close(); // it sets mReadyState to CLOSED
 
   rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to create the error event!!!");
-    return;
-  }
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
   // it doesn't bubble, and it isn't cancelable
   rv = event->InitEvent(NS_LITERAL_STRING("error"), false, false);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to init the error event!!!");
     return;
   }
 
@@ -1229,37 +1214,30 @@ EventSource::DispatchAllMessageEvents()
       NS_ENSURE_TRUE_VOID(jsString);
 
       jsData.setString(jsString);
     }
 
     // create an event that uses the MessageEvent interface,
     // which does not bubble, is not cancelable, and has no default action
 
-    nsCOMPtr<nsIDOMEvent> event;
-    rv = NS_NewDOMMessageEvent(getter_AddRefs(event), this, nullptr, nullptr);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to create the message event!!!");
-      return;
-    }
+    nsRefPtr<MessageEvent> event =
+      NS_NewDOMMessageEvent(this, nullptr, nullptr);
 
-    nsCOMPtr<nsIDOMMessageEvent> messageEvent = do_QueryInterface(event);
-    rv = messageEvent->InitMessageEvent(message->mEventName,
-                                        false, false,
-                                        jsData,
-                                        mOrigin,
-                                        message->mLastEventID, nullptr);
+    rv = event->InitMessageEvent(message->mEventName, false, false, jsData,
+                                 mOrigin, message->mLastEventID, nullptr);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to init the message event!!!");
       return;
     }
 
-    messageEvent->SetTrusted(true);
+    event->SetTrusted(true);
 
-    rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+    rv = DispatchDOMEvent(nullptr, static_cast<Event*>(event), nullptr,
+                          nullptr);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to dispatch the message event!!!");
       return;
     }
 
     mLastEventID.Assign(message->mLastEventID);
   }
 }
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/dom/WebSocketBinding.h"
 #include "mozilla/net/WebSocketChannel.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/net/WebSocketChannel.h"
 #include "mozilla/dom/File.h"
+#include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/nsCSPContext.h"
 #include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMWindow.h"
@@ -25,17 +26,16 @@
 #include "nsXPCOM.h"
 #include "nsIXPConnect.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIURL.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsThreadUtils.h"
-#include "nsIDOMMessageEvent.h"
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
 #include "nsIPrompt.h"
 #include "nsIStringBundle.h"
 #include "nsIConsoleService.h"
 #include "mozilla/dom/CloseEvent.h"
 #include "nsICryptoHash.h"
 #include "nsJSUtils.h"
@@ -1732,19 +1732,17 @@ WebSocket::CreateAndDispatchSimpleEvent(
   MOZ_ASSERT(mImpl);
   AssertIsOnTargetThread();
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
   // it doesn't bubble, and it isn't cancelable
   rv = event->InitEvent(aName, false, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
   event->SetTrusted(true);
 
   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
@@ -1812,31 +1810,27 @@ WebSocket::CreateAndDispatchMessageEvent
     NS_ENSURE_TRUE(jsString, NS_ERROR_FAILURE);
 
     jsData.setString(jsString);
   }
 
   // create an event that uses the MessageEvent interface,
   // which does not bubble, is not cancelable, and has no default action
 
-  nsCOMPtr<nsIDOMEvent> event;
-  rv = NS_NewDOMMessageEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIDOMMessageEvent> messageEvent = do_QueryInterface(event);
-  rv = messageEvent->InitMessageEvent(NS_LITERAL_STRING("message"),
-                                      false, false,
-                                      jsData,
-                                      mImpl->mUTF16Origin,
-                                      EmptyString(), nullptr);
+  nsRefPtr<MessageEvent> event = NS_NewDOMMessageEvent(this, nullptr, nullptr);
+
+  rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false,
+                               jsData, mImpl->mUTF16Origin, EmptyString(),
+                               nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   event->SetTrusted(true);
 
-  return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+  return DispatchDOMEvent(nullptr, static_cast<Event*>(event), nullptr,
+                          nullptr);
 }
 
 nsresult
 WebSocket::CreateAndDispatchCloseEvent(bool aWasClean,
                                        uint16_t aCode,
                                        const nsAString &aReason)
 {
   MOZ_ASSERT(mImpl);
--- a/dom/base/nsDOMDataChannel.cpp
+++ b/dom/base/nsDOMDataChannel.cpp
@@ -12,19 +12,19 @@
 extern PRLogModuleInfo* GetDataChannelLog();
 #undef LOG
 #define LOG(args) MOZ_LOG(GetDataChannelLog(), mozilla::LogLevel::Debug, args)
 
 
 #include "nsDOMDataChannelDeclarations.h"
 #include "nsDOMDataChannel.h"
 #include "nsIDOMDataChannel.h"
-#include "nsIDOMMessageEvent.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/File.h"
+#include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 #include "nsError.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIScriptObjectPrincipal.h"
 
@@ -396,30 +396,25 @@ nsDOMDataChannel::DoOnMessageAvailable(c
   } else {
     NS_ConvertUTF8toUTF16 utf16data(aData);
     JSString* jsString = JS_NewUCStringCopyN(cx, utf16data.get(), utf16data.Length());
     NS_ENSURE_TRUE(jsString, NS_ERROR_FAILURE);
 
     jsData.setString(jsString);
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  rv = NS_NewDOMMessageEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  NS_ENSURE_SUCCESS(rv,rv);
+  nsRefPtr<MessageEvent> event = NS_NewDOMMessageEvent(this, nullptr, nullptr);
 
-  nsCOMPtr<nsIDOMMessageEvent> messageEvent = do_QueryInterface(event);
-  rv = messageEvent->InitMessageEvent(NS_LITERAL_STRING("message"),
-                                      false, false,
-                                      jsData, mOrigin, EmptyString(),
-                                      nullptr);
+  rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false,
+                               jsData, mOrigin, EmptyString(), nullptr);
   NS_ENSURE_SUCCESS(rv,rv);
   event->SetTrusted(true);
 
   LOG(("%p(%p): %s - Dispatching\n",this,(void*)mDataChannel,__FUNCTION__));
-  rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+  rv = DispatchDOMEvent(nullptr, static_cast<Event*>(event), nullptr, nullptr);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to dispatch the message event!!!");
   }
   return rv;
 }
 
 nsresult
 nsDOMDataChannel::OnMessageAvailable(nsISupports* aContext,
@@ -442,19 +437,17 @@ nsDOMDataChannel::OnSimpleEvent(nsISuppo
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  NS_ENSURE_SUCCESS(rv,rv);
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
   rv = event->InitEvent(aName, false, false);
   NS_ENSURE_SUCCESS(rv,rv);
 
   event->SetTrusted(true);
 
   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -8127,27 +8127,27 @@ nsIDocument::CreateEvent(const nsAString
   nsPresContext *presContext = nullptr;
 
   if (shell) {
     // Retrieve the context
     presContext = shell->GetPresContext();
   }
 
   // Create event even without presContext.
-  nsCOMPtr<nsIDOMEvent> ev;
-  rv = EventDispatcher::CreateEvent(const_cast<nsIDocument*>(this),
-                                    presContext, nullptr, aEventType,
-                                    getter_AddRefs(ev));
+  nsRefPtr<Event> ev =
+    EventDispatcher::CreateEvent(const_cast<nsIDocument*>(this), presContext,
+                                 nullptr, aEventType);
   if (!ev) {
+    rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return nullptr;
   }
   WidgetEvent* e = ev->GetInternalNSEvent();
   e->mFlags.mBubbles = false;
   e->mFlags.mCancelable = false;
-  return dont_AddRef(ev.forget().take()->InternalDOMEvent());
+  return ev.forget();
 }
 
 void
 nsDocument::FlushPendingNotifications(mozFlushType aType)
 {
   nsDocumentOnStack dos(this);
 
   // We need to flush the sink for non-HTML documents (because the XML
@@ -9204,18 +9204,17 @@ NotifyPageHide(nsIDocument* aDocument, v
   aDocument->OnPageHide(*aPersistedPtr, nullptr);
   return true;
 }
 
 static void
 DispatchCustomEventWithFlush(nsINode* aTarget, const nsAString& aEventType,
                              bool aBubbles, bool aOnlyChromeDispatch)
 {
-  nsCOMPtr<nsIDOMEvent> event;
-  NS_NewDOMEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
+  nsRefPtr<Event> event = NS_NewDOMEvent(aTarget, nullptr, nullptr);
   nsresult rv = event->InitEvent(aEventType, aBubbles, false);
   if (NS_FAILED(rv)) {
     return;
   }
   event->SetTrusted(true);
   if (aOnlyChromeDispatch) {
     event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
   }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -9096,18 +9096,17 @@ nsGlobalWindow::LeaveModalState()
   }
 
   // Remember the time of the last dialog quit.
   nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
   if (inner)
     inner->mLastDialogQuitTime = TimeStamp::Now();
 
   if (topWin->mModalStateDepth == 0) {
-    nsCOMPtr<nsIDOMEvent> event;
-    NS_NewDOMEvent(getter_AddRefs(event), topWin, nullptr, nullptr);
+    nsRefPtr<Event> event = NS_NewDOMEvent(topWin, nullptr, nullptr);
     event->InitEvent(NS_LITERAL_STRING("endmodalstate"), true, false);
     event->SetTrusted(true);
     event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
     bool dummy;
     topWin->DispatchEvent(event, &dummy);
   }
 }
 
@@ -11885,18 +11884,17 @@ nsGlobalWindow::Observe(nsISupports* aSu
 #ifdef MOZ_B2G
   if (!nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC) ||
       !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC)) {
     MOZ_ASSERT(IsInnerWindow());
     if (!IsCurrentInnerWindow()) {
       return NS_OK;
     }
 
-    nsCOMPtr<nsIDOMEvent> event;
-    NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
+    nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
     nsresult rv = event->InitEvent(
       !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC)
         ? NETWORK_UPLOAD_EVENT_NAME
         : NETWORK_DOWNLOAD_EVENT_NAME,
       false, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     event->SetTrusted(true);
@@ -11922,18 +11920,17 @@ nsGlobalWindow::Observe(nsISupports* aSu
       NavigatorBinding::ClearCachedLanguagesValue(mNavigator);
     }
 
     // The event has to be dispatched only to the current inner window.
     if (!IsCurrentInnerWindow()) {
       return NS_OK;
     }
 
-    nsCOMPtr<nsIDOMEvent> event;
-    NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
+    nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
     nsresult rv = event->InitEvent(NS_LITERAL_STRING("languagechange"), false, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     event->SetTrusted(true);
 
     bool dummy;
     return DispatchEvent(event, &dummy);
   }
--- a/dom/base/nsPerformance.cpp
+++ b/dom/base/nsPerformance.cpp
@@ -473,26 +473,25 @@ nsPerformance::Timing()
         mDOMTiming->GetNavigationStart());
   }
   return mTiming;
 }
 
 void
 nsPerformance::DispatchBufferFullEvent()
 {
-  nsCOMPtr<nsIDOMEvent> event;
-  nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  if (NS_SUCCEEDED(rv)) {
-    // it bubbles, and it isn't cancelable
-    rv = event->InitEvent(NS_LITERAL_STRING("resourcetimingbufferfull"), true, false);
-    if (NS_SUCCEEDED(rv)) {
-      event->SetTrusted(true);
-      DispatchDOMEvent(nullptr, event, nullptr, nullptr);
-    }
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
+  // it bubbles, and it isn't cancelable
+  nsresult rv = event->InitEvent(NS_LITERAL_STRING("resourcetimingbufferfull"),
+                                 true, false);
+  if (NS_FAILED(rv)) {
+    return;
   }
+  event->SetTrusted(true);
+  DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
 nsPerformanceNavigation*
 nsPerformance::Navigation()
 {
   if (!mNavigation) {
     mNavigation = new nsPerformanceNavigation(this);
   }
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -1462,22 +1462,18 @@ nsXMLHttpRequest::GetLoadGroup() const
   }
 
   return nullptr;
 }
 
 nsresult
 nsXMLHttpRequest::CreateReadystatechangeEvent(nsIDOMEvent** aDOMEvent)
 {
-  nsresult rv = EventDispatcher::CreateEvent(this, nullptr, nullptr,
-                                             NS_LITERAL_STRING("Events"),
-                                             aDOMEvent);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
+  event.forget(aDOMEvent);
 
   (*aDOMEvent)->InitEvent(NS_LITERAL_STRING(READYSTATE_STR),
                           false, false);
 
   // We assume anyone who managed to call CreateReadystatechangeEvent is trusted
   (*aDOMEvent)->SetTrusted(true);
 
   return NS_OK;
--- a/dom/bluetooth/bluetooth1/BluetoothAdapter.cpp
+++ b/dom/bluetooth/bluetooth1/BluetoothAdapter.cpp
@@ -11,16 +11,17 @@
 #include "nsThreadUtils.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/BluetoothAdapterBinding.h"
 #include "mozilla/dom/BluetoothDeviceEvent.h"
 #include "mozilla/dom/BluetoothDiscoveryStateChangedEvent.h"
 #include "mozilla/dom/BluetoothStatusChangedEvent.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/Event.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/LazyIdleThread.h"
 
 #include "BluetoothAdapter.h"
 #include "BluetoothDevice.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
@@ -356,21 +357,19 @@ BluetoothAdapter::Notify(const Bluetooth
     init.mBubbles = false;
     init.mCancelable = false;
     init.mAddress = address;
     init.mStatus = status;
     nsRefPtr<BluetoothStatusChangedEvent> event =
       BluetoothStatusChangedEvent::Constructor(this, aData.name(), init);
     DispatchTrustedEvent(event);
   } else if (aData.name().EqualsLiteral(REQUEST_MEDIA_PLAYSTATUS_ID)) {
-    nsCOMPtr<nsIDOMEvent> event;
-    nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-    NS_ENSURE_SUCCESS_VOID(rv);
+    nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
-    rv = event->InitEvent(aData.name(), false, false);
+    nsresult rv = event->InitEvent(aData.name(), false, false);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     DispatchTrustedEvent(event);
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling adapter signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
--- a/dom/bluetooth/bluetooth2/BluetoothAdapter.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothAdapter.cpp
@@ -11,16 +11,17 @@
 #include "nsIDocument.h"
 #include "nsIPrincipal.h"
 #include "nsTArrayHelpers.h"
 
 #include "mozilla/dom/BluetoothAdapter2Binding.h"
 #include "mozilla/dom/BluetoothAttributeEvent.h"
 #include "mozilla/dom/BluetoothStatusChangedEvent.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/Event.h"
 #include "mozilla/dom/File.h"
 
 #include "mozilla/dom/bluetooth/BluetoothAdapter.h"
 #include "mozilla/dom/bluetooth/BluetoothClassOfDevice.h"
 #include "mozilla/dom/bluetooth/BluetoothDevice.h"
 #include "mozilla/dom/bluetooth/BluetoothDiscoveryHandle.h"
 #include "mozilla/dom/bluetooth/BluetoothGattServer.h"
 #include "mozilla/dom/bluetooth/BluetoothPairingListener.h"
@@ -1191,21 +1192,19 @@ BluetoothAdapter::DispatchDeviceEvent(co
   nsRefPtr<BluetoothDeviceEvent> event =
     BluetoothDeviceEvent::Constructor(this, aType, aInit);
   DispatchTrustedEvent(event);
 }
 
 void
 BluetoothAdapter::DispatchEmptyEvent(const nsAString& aType)
 {
-  nsCOMPtr<nsIDOMEvent> event;
-  nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  NS_ENSURE_SUCCESS_VOID(rv);
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
-  rv = event->InitEvent(aType, false, false);
+  nsresult rv = event->InitEvent(aType, false, false);
   NS_ENSURE_SUCCESS_VOID(rv);
 
   DispatchTrustedEvent(event);
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::Connect(BluetoothDevice& aDevice,
                           const Optional<short unsigned int>& aServiceUuid,
--- a/dom/bluetooth/bluetooth2/BluetoothGatt.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGatt.cpp
@@ -7,16 +7,17 @@
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothUtils.h"
 #include "mozilla/dom/bluetooth/BluetoothCommon.h"
 #include "mozilla/dom/bluetooth/BluetoothGatt.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/BluetoothGattBinding.h"
 #include "mozilla/dom/BluetoothGattCharacteristicEvent.h"
+#include "mozilla/dom/Event.h"
 #include "mozilla/dom/Promise.h"
 #include "nsServiceManagerUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 USING_BLUETOOTH_NAMESPACE
 
@@ -235,23 +236,22 @@ BluetoothGatt::DiscoverServices(ErrorRes
 
 void
 BluetoothGatt::UpdateConnectionState(BluetoothConnectionState aState)
 {
   BT_LOGR("GATT connection state changes to: %d", int(aState));
   mConnectionState = aState;
 
   // Dispatch connectionstatechanged event to application
-  nsCOMPtr<nsIDOMEvent> event;
-  nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  NS_ENSURE_SUCCESS_VOID(rv);
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
-  rv = event->InitEvent(NS_LITERAL_STRING(GATT_CONNECTION_STATE_CHANGED_ID),
-                        false,
-                        false);
+  nsresult rv =
+    event->InitEvent(NS_LITERAL_STRING(GATT_CONNECTION_STATE_CHANGED_ID),
+                     false,
+                     false);
   NS_ENSURE_SUCCESS_VOID(rv);
 
   DispatchTrustedEvent(event);
 }
 
 void
 BluetoothGatt::HandleServicesDiscovered(const BluetoothValue& aValue)
 {
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -97,41 +97,36 @@ DispatchCustomDOMEvent(Element* aFrameEl
 {
   NS_ENSURE_TRUE(aFrameElement, false);
   nsIPresShell *shell = aFrameElement->OwnerDoc()->GetShell();
   nsRefPtr<nsPresContext> presContext;
   if (shell) {
     presContext = shell->GetPresContext();
   }
 
-  nsCOMPtr<nsIDOMEvent> domEvent;
-  EventDispatcher::CreateEvent(aFrameElement, presContext, nullptr,
-                               NS_LITERAL_STRING("customevent"),
-                               getter_AddRefs(domEvent));
-  NS_ENSURE_TRUE(domEvent, false);
+  nsRefPtr<CustomEvent> event =
+    NS_NewDOMCustomEvent(aFrameElement, presContext, nullptr);
 
-  nsCOMPtr<nsIDOMCustomEvent> customEvent = do_QueryInterface(domEvent);
-  NS_ENSURE_TRUE(customEvent, false);
   ErrorResult res;
-  CustomEvent* event = static_cast<CustomEvent*>(customEvent.get());
   event->InitCustomEvent(cx,
                          aEventName,
                          /* bubbles = */ true,
                          /* cancelable = */ true,
                          aDetailValue,
                          res);
   if (res.Failed()) {
     return false;
   }
-  customEvent->SetTrusted(true);
+  event->SetTrusted(true);
   // Dispatch the event.
   *aStatus = nsEventStatus_eConsumeNoDefault;
   nsresult rv =
     EventDispatcher::DispatchDOMEvent(aFrameElement, nullptr,
-                                      domEvent, presContext, aStatus);
+                                      static_cast<Event*>(event),
+                                      presContext, aStatus);
   return NS_SUCCEEDED(rv);
 }
 
 } // namespace
 
 namespace mozilla {
 
 /**
--- a/dom/events/AnimationEvent.cpp
+++ b/dom/events/AnimationEvent.cpp
@@ -83,19 +83,17 @@ AnimationEvent::GetPseudoElement(nsAStri
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMAnimationEvent(nsIDOMEvent** aInstancePtrResult,
-                        EventTarget* aOwner,
+already_AddRefed<AnimationEvent>
+NS_NewDOMAnimationEvent(EventTarget* aOwner,
                         nsPresContext* aPresContext,
                         InternalAnimationEvent* aEvent)
 {
-  AnimationEvent* it = new AnimationEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<AnimationEvent> it =
+    new AnimationEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/AnimationEvent.h
+++ b/dom/events/AnimationEvent.h
@@ -47,9 +47,14 @@ public:
 
 protected:
   ~AnimationEvent() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::AnimationEvent>
+NS_NewDOMAnimationEvent(mozilla::dom::EventTarget* aOwner,
+                        nsPresContext* aPresContext,
+                        mozilla::InternalAnimationEvent* aEvent);
+
 #endif // mozilla_dom_AnimationEvent_h_
--- a/dom/events/AsyncEventDispatcher.cpp
+++ b/dom/events/AsyncEventDispatcher.cpp
@@ -21,35 +21,36 @@ using namespace dom;
  ******************************************************************************/
 
 AsyncEventDispatcher::AsyncEventDispatcher(EventTarget* aTarget,
                                            WidgetEvent& aEvent)
   : mTarget(aTarget)
   , mOnlyChromeDispatch(false)
 {
   MOZ_ASSERT(mTarget);
-  EventDispatcher::CreateEvent(aTarget, nullptr, &aEvent, EmptyString(),
-                               getter_AddRefs(mEvent));
+  nsRefPtr<Event> event =
+    EventDispatcher::CreateEvent(aTarget, nullptr, &aEvent, EmptyString());
+  mEvent = do_QueryInterface(event);
   NS_ASSERTION(mEvent, "Should never fail to create an event");
   mEvent->DuplicatePrivateData();
   mEvent->SetTrusted(aEvent.mFlags.mIsTrusted);
 }
 
 NS_IMETHODIMP
 AsyncEventDispatcher::Run()
 {
-  nsCOMPtr<nsIDOMEvent> event = mEvent;
+  nsRefPtr<Event> event = mEvent ? mEvent->InternalDOMEvent() : nullptr;
   if (!event) {
-    NS_NewDOMEvent(getter_AddRefs(event), mTarget, nullptr, nullptr);
+    event = NS_NewDOMEvent(mTarget, nullptr, nullptr);
     nsresult rv = event->InitEvent(mEventType, mBubbles, false);
     NS_ENSURE_SUCCESS(rv, rv);
     event->SetTrusted(true);
   }
   if (mOnlyChromeDispatch) {
-    MOZ_ASSERT(event->InternalDOMEvent()->IsTrusted());
+    MOZ_ASSERT(event->IsTrusted());
     event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
   }
   bool dummy;
   mTarget->DispatchEvent(event, &dummy);
   return NS_OK;
 }
 
 nsresult
--- a/dom/events/BeforeAfterKeyboardEvent.cpp
+++ b/dom/events/BeforeAfterKeyboardEvent.cpp
@@ -73,21 +73,17 @@ BeforeAfterKeyboardEvent::GetEmbeddedCan
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMBeforeAfterKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
-                                  EventTarget* aOwner,
+already_AddRefed<BeforeAfterKeyboardEvent>
+NS_NewDOMBeforeAfterKeyboardEvent(EventTarget* aOwner,
                                   nsPresContext* aPresContext,
                                   InternalBeforeAfterKeyboardEvent* aEvent)
 {
-  BeforeAfterKeyboardEvent* it =
+  nsRefPtr<BeforeAfterKeyboardEvent> it =
     new BeforeAfterKeyboardEvent(aOwner, aPresContext, aEvent);
-
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  return it.forget();
 }
--- a/dom/events/BeforeAfterKeyboardEvent.h
+++ b/dom/events/BeforeAfterKeyboardEvent.h
@@ -38,9 +38,14 @@ public:
   // This function returns a boolean value when event typs is either
   // "mozbrowserafterkeydown" or "mozbrowserafterkeyup".
   Nullable<bool> GetEmbeddedCancelled();
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::BeforeAfterKeyboardEvent>
+NS_NewDOMBeforeAfterKeyboardEvent(mozilla::dom::EventTarget* aOwner,
+                                  nsPresContext* aPresContext,
+                                  mozilla::InternalBeforeAfterKeyboardEvent* aEvent);
+
 #endif // mozilla_dom_BeforeAfterKeyboardEvent_h_
--- a/dom/events/BeforeUnloadEvent.cpp
+++ b/dom/events/BeforeUnloadEvent.cpp
@@ -31,19 +31,17 @@ BeforeUnloadEvent::GetReturnValue(nsAStr
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMBeforeUnloadEvent(nsIDOMEvent** aInstancePtrResult,
-                           EventTarget* aOwner,
+already_AddRefed<BeforeUnloadEvent>
+NS_NewDOMBeforeUnloadEvent(EventTarget* aOwner,
                            nsPresContext* aPresContext,
                            WidgetEvent* aEvent) 
 {
-  BeforeUnloadEvent* it = new BeforeUnloadEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<BeforeUnloadEvent> it =
+    new BeforeUnloadEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/BeforeUnloadEvent.h
+++ b/dom/events/BeforeUnloadEvent.h
@@ -42,9 +42,14 @@ protected:
   ~BeforeUnloadEvent() {}
 
   nsString mText;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::BeforeUnloadEvent>
+NS_NewDOMBeforeUnloadEvent(mozilla::dom::EventTarget* aOwner,
+                           nsPresContext* aPresContext,
+                           mozilla::WidgetEvent* aEvent);
+
 #endif // mozilla_dom_BeforeUnloadEvent_h_
--- a/dom/events/ClipboardEvent.cpp
+++ b/dom/events/ClipboardEvent.cpp
@@ -118,19 +118,17 @@ ClipboardEvent::GetClipboardData()
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMClipboardEvent(nsIDOMEvent** aInstancePtrResult,
-                        EventTarget* aOwner,
+already_AddRefed<ClipboardEvent>
+NS_NewDOMClipboardEvent(EventTarget* aOwner,
                         nsPresContext* aPresContext,
                         InternalClipboardEvent* aEvent)
 {
-  ClipboardEvent* it = new ClipboardEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<ClipboardEvent> it =
+    new ClipboardEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/ClipboardEvent.h
+++ b/dom/events/ClipboardEvent.h
@@ -51,9 +51,14 @@ public:
 
 protected:
   ~ClipboardEvent() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::ClipboardEvent>
+NS_NewDOMClipboardEvent(mozilla::dom::EventTarget* aOwner,
+                        nsPresContext* aPresContext,
+                        mozilla::InternalClipboardEvent* aEvent);
+
 #endif // mozilla_dom_ClipboardEvent_h_
--- a/dom/events/CommandEvent.cpp
+++ b/dom/events/CommandEvent.cpp
@@ -59,19 +59,17 @@ CommandEvent::InitCommandEvent(const nsA
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMCommandEvent(nsIDOMEvent** aInstancePtrResult,
-                      EventTarget* aOwner,
+already_AddRefed<CommandEvent>
+NS_NewDOMCommandEvent(EventTarget* aOwner,
                       nsPresContext* aPresContext,
                       WidgetCommandEvent* aEvent)
 {
-  CommandEvent* it = new CommandEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<CommandEvent> it =
+    new CommandEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/CommandEvent.h
+++ b/dom/events/CommandEvent.h
@@ -46,9 +46,14 @@ public:
 
 protected:
   ~CommandEvent() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::CommandEvent>
+NS_NewDOMCommandEvent(mozilla::dom::EventTarget* aOwner,
+                      nsPresContext* aPresContext,
+                      mozilla::WidgetCommandEvent* aEvent);
+
 #endif // mozilla_dom_CommandEvent_h_
--- a/dom/events/CompositionEvent.cpp
+++ b/dom/events/CompositionEvent.cpp
@@ -75,17 +75,17 @@ CompositionEvent::InitCompositionEvent(c
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMCompositionEvent(nsIDOMEvent** aInstancePtrResult,
-                          EventTarget* aOwner,
+already_AddRefed<CompositionEvent>
+NS_NewDOMCompositionEvent(EventTarget* aOwner,
                           nsPresContext* aPresContext,
                           WidgetCompositionEvent* aEvent)
 {
-  CompositionEvent* event = new CompositionEvent(aOwner, aPresContext, aEvent);
-  return CallQueryInterface(event, aInstancePtrResult);
+  nsRefPtr<CompositionEvent> event =
+    new CompositionEvent(aOwner, aPresContext, aEvent);
+  return event.forget();
 }
--- a/dom/events/CompositionEvent.h
+++ b/dom/events/CompositionEvent.h
@@ -49,9 +49,14 @@ protected:
 
   nsString mData;
   nsString mLocale;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::CompositionEvent>
+NS_NewDOMCompositionEvent(mozilla::dom::EventTarget* aOwner,
+                          nsPresContext* aPresContext,
+                          mozilla::WidgetCompositionEvent* aEvent);
+
 #endif // mozilla_dom_CompositionEvent_h_
--- a/dom/events/CustomEvent.cpp
+++ b/dom/events/CustomEvent.cpp
@@ -106,19 +106,17 @@ CustomEvent::GetDetail(JSContext* aCx,
   if (!mDetail) {
     aRetval.setNull();
     return;
   }
 
   VariantToJsval(aCx, mDetail, aRetval);
 }
 
-nsresult
-NS_NewDOMCustomEvent(nsIDOMEvent** aInstancePtrResult,
-                     mozilla::dom::EventTarget* aOwner,
+already_AddRefed<CustomEvent>
+NS_NewDOMCustomEvent(EventTarget* aOwner,
                      nsPresContext* aPresContext,
                      mozilla::WidgetEvent* aEvent)
 {
-  CustomEvent* it = new CustomEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<CustomEvent> it =
+    new CustomEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/CustomEvent.h
+++ b/dom/events/CustomEvent.h
@@ -53,9 +53,14 @@ public:
                   bool aCancelable,
                   JS::Handle<JS::Value> aDetail,
                   ErrorResult& aRv);
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::CustomEvent>
+NS_NewDOMCustomEvent(mozilla::dom::EventTarget* aOwner,
+                     nsPresContext* aPresContext,
+                     mozilla::WidgetEvent* aEvent);
+
 #endif // CustomEvent_h__
--- a/dom/events/DOMEventTargetHelper.cpp
+++ b/dom/events/DOMEventTargetHelper.cpp
@@ -257,18 +257,17 @@ DOMEventTargetHelper::DispatchEvent(nsID
 
   *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
   return rv;
 }
 
 nsresult
 DOMEventTargetHelper::DispatchTrustedEvent(const nsAString& aEventName)
 {
-  nsCOMPtr<nsIDOMEvent> event;
-  NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
   nsresult rv = event->InitEvent(aEventName, false, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return DispatchTrustedEvent(event);
 }
 
 nsresult
 DOMEventTargetHelper::DispatchTrustedEvent(nsIDOMEvent* event)
--- a/dom/events/DataContainerEvent.cpp
+++ b/dom/events/DataContainerEvent.cpp
@@ -82,20 +82,18 @@ DataContainerEvent::SetData(JSContext* a
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMDataContainerEvent(nsIDOMEvent** aInstancePtrResult,
-                            EventTarget* aOwner,
+already_AddRefed<DataContainerEvent>
+NS_NewDOMDataContainerEvent(EventTarget* aOwner,
                             nsPresContext* aPresContext,
                             WidgetEvent* aEvent)
 {
-  DataContainerEvent* it = new DataContainerEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<DataContainerEvent> it =
+    new DataContainerEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
 
--- a/dom/events/DataContainerEvent.h
+++ b/dom/events/DataContainerEvent.h
@@ -52,9 +52,14 @@ protected:
 
 private:
   nsInterfaceHashtable<nsStringHashKey, nsIVariant> mData;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::DataContainerEvent>
+NS_NewDOMDataContainerEvent(mozilla::dom::EventTarget* aOwner,
+                            nsPresContext* aPresContext,
+                            mozilla::WidgetEvent* aEvent);
+
 #endif // mozilla_dom_DataContainerEvent_h_
--- a/dom/events/DeviceMotionEvent.cpp
+++ b/dom/events/DeviceMotionEvent.cpp
@@ -140,21 +140,17 @@ DeviceRotationRate::~DeviceRotationRate(
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMDeviceMotionEvent(nsIDOMEvent** aInstancePtrResult,
-                           EventTarget* aOwner,
+already_AddRefed<DeviceMotionEvent>
+NS_NewDOMDeviceMotionEvent(EventTarget* aOwner,
                            nsPresContext* aPresContext,
                            WidgetEvent* aEvent) 
 {
-  NS_ENSURE_ARG_POINTER(aInstancePtrResult);
-
-  DeviceMotionEvent* it = new DeviceMotionEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<DeviceMotionEvent> it =
+    new DeviceMotionEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/DeviceMotionEvent.h
+++ b/dom/events/DeviceMotionEvent.h
@@ -144,9 +144,14 @@ protected:
   nsRefPtr<DeviceAcceleration> mAccelerationIncludingGravity;
   nsRefPtr<DeviceRotationRate> mRotationRate;
   Nullable<double> mInterval;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::DeviceMotionEvent>
+NS_NewDOMDeviceMotionEvent(mozilla::dom::EventTarget* aOwner,
+                           nsPresContext* aPresContext,
+                           mozilla::WidgetEvent* aEvent);
+
 #endif // mozilla_dom_DeviceMotionEvent_h_
--- a/dom/events/DragEvent.cpp
+++ b/dom/events/DragEvent.cpp
@@ -154,17 +154,17 @@ DragEvent::Constructor(const GlobalObjec
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult,
-                   EventTarget* aOwner,
+already_AddRefed<DragEvent>
+NS_NewDOMDragEvent(EventTarget* aOwner,
                    nsPresContext* aPresContext,
                    WidgetDragEvent* aEvent) 
 {
-  DragEvent* event = new DragEvent(aOwner, aPresContext, aEvent);
-  return CallQueryInterface(event, aInstancePtrResult);
+  nsRefPtr<DragEvent> event =
+    new DragEvent(aOwner, aPresContext, aEvent);
+  return event.forget();
 }
--- a/dom/events/DragEvent.h
+++ b/dom/events/DragEvent.h
@@ -56,9 +56,14 @@ public:
 
 protected:
   ~DragEvent() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::DragEvent>
+NS_NewDOMDragEvent(mozilla::dom::EventTarget* aOwner,
+                   nsPresContext* aPresContext,
+                   mozilla::WidgetDragEvent* aEvent);
+
 #endif // mozilla_dom_DragEvent_h_
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -1252,19 +1252,16 @@ Event::GetShadowRelatedTarget(nsIContent
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMEvent(nsIDOMEvent** aInstancePtrResult,
-               EventTarget* aOwner,
+already_AddRefed<Event>
+NS_NewDOMEvent(EventTarget* aOwner,
                nsPresContext* aPresContext,
                WidgetEvent* aEvent) 
 {
-  Event* it = new Event(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<Event> it = new Event(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -335,9 +335,14 @@ ToSupports(mozilla::dom::Event* e)
 }
 
 inline nsISupports*
 ToCanonicalSupports(mozilla::dom::Event* e)
 {
   return static_cast<nsIDOMEvent*>(e);
 }
 
+already_AddRefed<mozilla::dom::Event>
+NS_NewDOMEvent(mozilla::dom::EventTarget* aOwner,
+               nsPresContext* aPresContext,
+               mozilla::WidgetEvent* aEvent);
+
 #endif // mozilla_dom_Event_h_
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -10,23 +10,38 @@
 #include <new>
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsINode.h"
 #include "nsPIDOMWindow.h"
 #include "GeckoProfiler.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/dom/CloseEvent.h"
+#include "mozilla/dom/CustomEvent.h"
 #include "mozilla/dom/DeviceOrientationEvent.h"
 #include "mozilla/dom/EventTarget.h"
+#include "mozilla/dom/FocusEvent.h"
 #include "mozilla/dom/HashChangeEvent.h"
+#include "mozilla/dom/InputEvent.h"
+#include "mozilla/dom/MessageEvent.h"
+#include "mozilla/dom/MouseScrollEvent.h"
+#include "mozilla/dom/MutationEvent.h"
+#include "mozilla/dom/NotifyPaintEvent.h"
 #include "mozilla/dom/PageTransitionEvent.h"
+#include "mozilla/dom/PointerEvent.h"
 #include "mozilla/dom/PopStateEvent.h"
+#include "mozilla/dom/ScrollAreaEvent.h"
+#include "mozilla/dom/SimpleGestureEvent.h"
 #include "mozilla/dom/StorageEvent.h"
+#include "mozilla/dom/SVGZoomEvent.h"
+#include "mozilla/dom/TimeEvent.h"
 #include "mozilla/dom/TouchEvent.h"
+#include "mozilla/dom/TransitionEvent.h"
+#include "mozilla/dom/WheelEvent.h"
+#include "mozilla/dom/XULCommandEvent.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
@@ -700,198 +715,177 @@ EventDispatcher::DispatchDOMEvent(nsISup
                                      aDOMEvent, aEventStatus);
   } else if (aEvent) {
     return EventDispatcher::Dispatch(aTarget, aPresContext, aEvent,
                                      aDOMEvent, aEventStatus);
   }
   return NS_ERROR_ILLEGAL_VALUE;
 }
 
-/* static */ nsresult
+/* static */ already_AddRefed<dom::Event>
 EventDispatcher::CreateEvent(EventTarget* aOwner,
                              nsPresContext* aPresContext,
                              WidgetEvent* aEvent,
-                             const nsAString& aEventType,
-                             nsIDOMEvent** aDOMEvent)
+                             const nsAString& aEventType)
 {
-  *aDOMEvent = nullptr;
-
   if (aEvent) {
     switch(aEvent->mClass) {
     case eMutationEventClass:
-      return NS_NewDOMMutationEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMMutationEvent(aOwner, aPresContext,
                                     aEvent->AsMutationEvent());
     case eGUIEventClass:
     case eScrollPortEventClass:
     case eUIEventClass:
-      return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext,
-                              aEvent->AsGUIEvent());
+      return NS_NewDOMUIEvent(aOwner, aPresContext, aEvent->AsGUIEvent());
     case eScrollAreaEventClass:
-      return NS_NewDOMScrollAreaEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMScrollAreaEvent(aOwner, aPresContext,
                                       aEvent->AsScrollAreaEvent());
     case eKeyboardEventClass:
-      return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMKeyboardEvent(aOwner, aPresContext,
                                     aEvent->AsKeyboardEvent());
     case eBeforeAfterKeyboardEventClass:
-      return NS_NewDOMBeforeAfterKeyboardEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMBeforeAfterKeyboardEvent(aOwner, aPresContext,
                                                aEvent->AsBeforeAfterKeyboardEvent());
     case eCompositionEventClass:
-      return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMCompositionEvent(aOwner, aPresContext,
                                        aEvent->AsCompositionEvent());
     case eMouseEventClass:
-      return NS_NewDOMMouseEvent(aDOMEvent, aOwner, aPresContext,
-                                 aEvent->AsMouseEvent());
+      return NS_NewDOMMouseEvent(aOwner, aPresContext, aEvent->AsMouseEvent());
     case eFocusEventClass:
-      return NS_NewDOMFocusEvent(aDOMEvent, aOwner, aPresContext,
-                                 aEvent->AsFocusEvent());
+      return NS_NewDOMFocusEvent(aOwner, aPresContext, aEvent->AsFocusEvent());
     case eMouseScrollEventClass:
-      return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMMouseScrollEvent(aOwner, aPresContext,
                                        aEvent->AsMouseScrollEvent());
     case eWheelEventClass:
-      return NS_NewDOMWheelEvent(aDOMEvent, aOwner, aPresContext,
-                                 aEvent->AsWheelEvent());
+      return NS_NewDOMWheelEvent(aOwner, aPresContext, aEvent->AsWheelEvent());
     case eEditorInputEventClass:
-      return NS_NewDOMInputEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMInputEvent(aOwner, aPresContext,
                                  aEvent->AsEditorInputEvent());
     case eDragEventClass:
-      return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext,
-                                aEvent->AsDragEvent());
+      return NS_NewDOMDragEvent(aOwner, aPresContext, aEvent->AsDragEvent());
     case eClipboardEventClass:
-      return NS_NewDOMClipboardEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMClipboardEvent(aOwner, aPresContext,
                                      aEvent->AsClipboardEvent());
     case eSVGZoomEventClass:
-      return NS_NewDOMSVGZoomEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMSVGZoomEvent(aOwner, aPresContext,
                                    aEvent->AsSVGZoomEvent());
     case eSMILTimeEventClass:
-      return NS_NewDOMTimeEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMTimeEvent(aOwner, aPresContext,
                                 aEvent->AsSMILTimeEvent());
     case eCommandEventClass:
-      return NS_NewDOMCommandEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMCommandEvent(aOwner, aPresContext,
                                    aEvent->AsCommandEvent());
     case eSimpleGestureEventClass:
-      return NS_NewDOMSimpleGestureEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMSimpleGestureEvent(aOwner, aPresContext,
                                          aEvent->AsSimpleGestureEvent());
     case ePointerEventClass:
-      return NS_NewDOMPointerEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMPointerEvent(aOwner, aPresContext,
                                    aEvent->AsPointerEvent());
     case eTouchEventClass:
-      return NS_NewDOMTouchEvent(aDOMEvent, aOwner, aPresContext,
-                                 aEvent->AsTouchEvent());
+      return NS_NewDOMTouchEvent(aOwner, aPresContext, aEvent->AsTouchEvent());
     case eTransitionEventClass:
-      return NS_NewDOMTransitionEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMTransitionEvent(aOwner, aPresContext,
                                       aEvent->AsTransitionEvent());
     case eAnimationEventClass:
-      return NS_NewDOMAnimationEvent(aDOMEvent, aOwner, aPresContext,
+      return NS_NewDOMAnimationEvent(aOwner, aPresContext,
                                      aEvent->AsAnimationEvent());
     default:
       // For all other types of events, create a vanilla event object.
-      return NS_NewDOMEvent(aDOMEvent, aOwner, aPresContext, aEvent);
+      return NS_NewDOMEvent(aOwner, aPresContext, aEvent);
     }
   }
 
   // And if we didn't get an event, check the type argument.
 
   if (aEventType.LowerCaseEqualsLiteral("mouseevent") ||
       aEventType.LowerCaseEqualsLiteral("mouseevents") ||
       aEventType.LowerCaseEqualsLiteral("popupevents"))
-    return NS_NewDOMMouseEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMMouseEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("mousescrollevents"))
-    return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMMouseScrollEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("dragevent") ||
       aEventType.LowerCaseEqualsLiteral("dragevents"))
-    return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMDragEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("keyboardevent") ||
       aEventType.LowerCaseEqualsLiteral("keyevents"))
-    return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMKeyboardEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("compositionevent") ||
       aEventType.LowerCaseEqualsLiteral("textevent") ||
       aEventType.LowerCaseEqualsLiteral("textevents")) {
-    return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMCompositionEvent(aOwner, aPresContext, nullptr);
   }
   if (aEventType.LowerCaseEqualsLiteral("mutationevent") ||
         aEventType.LowerCaseEqualsLiteral("mutationevents"))
-    return NS_NewDOMMutationEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMMutationEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("deviceorientationevent")) {
     DeviceOrientationEventInit init;
-    nsRefPtr<DeviceOrientationEvent> event =
-      DeviceOrientationEvent::Constructor(aOwner, EmptyString(), init);
-    event.forget(aDOMEvent);
-    return NS_OK;
+    return DeviceOrientationEvent::Constructor(aOwner, EmptyString(), init);
   }
   if (aEventType.LowerCaseEqualsLiteral("devicemotionevent"))
-    return NS_NewDOMDeviceMotionEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMDeviceMotionEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("uievent") ||
       aEventType.LowerCaseEqualsLiteral("uievents"))
-    return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMUIEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("event") ||
       aEventType.LowerCaseEqualsLiteral("events") ||
       aEventType.LowerCaseEqualsLiteral("htmlevents") ||
       aEventType.LowerCaseEqualsLiteral("svgevent") ||
       aEventType.LowerCaseEqualsLiteral("svgevents"))
-    return NS_NewDOMEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("svgzoomevent") ||
       aEventType.LowerCaseEqualsLiteral("svgzoomevents"))
-    return NS_NewDOMSVGZoomEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMSVGZoomEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("timeevent") ||
       aEventType.LowerCaseEqualsLiteral("timeevents"))
-    return NS_NewDOMTimeEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMTimeEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("xulcommandevent") ||
       aEventType.LowerCaseEqualsLiteral("xulcommandevents"))
-    return NS_NewDOMXULCommandEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMXULCommandEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("commandevent") ||
       aEventType.LowerCaseEqualsLiteral("commandevents"))
-    return NS_NewDOMCommandEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMCommandEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("datacontainerevent") ||
       aEventType.LowerCaseEqualsLiteral("datacontainerevents"))
-    return NS_NewDOMDataContainerEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMDataContainerEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("messageevent"))
-    return NS_NewDOMMessageEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMMessageEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("notifypaintevent"))
-    return NS_NewDOMNotifyPaintEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMNotifyPaintEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("simplegestureevent"))
-    return NS_NewDOMSimpleGestureEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMSimpleGestureEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("beforeunloadevent"))
-    return NS_NewDOMBeforeUnloadEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMBeforeUnloadEvent(aOwner, aPresContext, nullptr);
   // XXXkhuey this is broken
   if (aEventType.LowerCaseEqualsLiteral("pagetransition")) {
     PageTransitionEventInit init;
-    nsRefPtr<PageTransitionEvent> event =
-      PageTransitionEvent::Constructor(aOwner, EmptyString(), init);
-    event.forget(aDOMEvent);
-    return NS_OK;
+    return PageTransitionEvent::Constructor(aOwner, EmptyString(), init);
   }
   if (aEventType.LowerCaseEqualsLiteral("scrollareaevent"))
-    return NS_NewDOMScrollAreaEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMScrollAreaEvent(aOwner, aPresContext, nullptr);
   // XXXkhuey Chrome supports popstateevent here, even though it provides no
   // initPopStateEvent method.  This is nuts ... but copying it is unlikely to
   // break the web.
   if (aEventType.LowerCaseEqualsLiteral("popstateevent")) {
     AutoJSContext cx;
     RootedDictionary<PopStateEventInit> init(cx);
-    nsRefPtr<PopStateEvent> event =
-      PopStateEvent::Constructor(aOwner, EmptyString(), init);
-    event.forget(aDOMEvent);
-    return NS_OK;
+    return PopStateEvent::Constructor(aOwner, EmptyString(), init);
   }
   if (aEventType.LowerCaseEqualsLiteral("touchevent") &&
       TouchEvent::PrefEnabled())
-    return NS_NewDOMTouchEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMTouchEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("hashchangeevent")) {
     HashChangeEventInit init;
-    nsRefPtr<HashChangeEvent> event =
-      HashChangeEvent::Constructor(aOwner, EmptyString(), init);
-    event.forget(aDOMEvent);
-    return NS_OK;
+    return HashChangeEvent::Constructor(aOwner, EmptyString(), init);
   }
   if (aEventType.LowerCaseEqualsLiteral("customevent"))
-    return NS_NewDOMCustomEvent(aDOMEvent, aOwner, aPresContext, nullptr);
+    return NS_NewDOMCustomEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("storageevent")) {
-    return NS_NewDOMStorageEvent(aDOMEvent, aOwner);
+    return NS_NewDOMStorageEvent(aOwner);
   }
 
 
   // NEW EVENT TYPES SHOULD NOT BE ADDED HERE; THEY SHOULD USE ONLY EVENT
   // CONSTRUCTORS
 
-  return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+  return nullptr;
 }
 
 } // namespace mozilla
--- a/dom/events/EventDispatcher.h
+++ b/dom/events/EventDispatcher.h
@@ -18,16 +18,17 @@
 class nsIContent;
 class nsIDOMEvent;
 class nsPresContext;
 
 template<class E> class nsCOMArray;
 
 namespace mozilla {
 namespace dom {
+class Event;
 class EventTarget;
 } // namespace dom
 
 /**
  * About event dispatching:
  * When either EventDispatcher::Dispatch or
  * EventDispatcher::DispatchDOMEvent is called an event target chain is
  * created. EventDispatcher creates the chain by calling PreHandleEvent 
@@ -267,23 +268,22 @@ public:
    */
   static nsresult DispatchDOMEvent(nsISupports* aTarget,
                                    WidgetEvent* aEvent,
                                    nsIDOMEvent* aDOMEvent,
                                    nsPresContext* aPresContext,
                                    nsEventStatus* aEventStatus);
 
   /**
-   * Creates a DOM Event.
+   * Creates a DOM Event.  Returns null if the event type is unsupported.
    */
-  static nsresult CreateEvent(dom::EventTarget* aOwner,
-                              nsPresContext* aPresContext,
-                              WidgetEvent* aEvent,
-                              const nsAString& aEventType,
-                              nsIDOMEvent** aDOMEvent);
+  static already_AddRefed<dom::Event> CreateEvent(dom::EventTarget* aOwner,
+                                                  nsPresContext* aPresContext,
+                                                  WidgetEvent* aEvent,
+                                                  const nsAString& aEventType);
 
   /**
    * Called at shutting down.
    */
   static void Shutdown();
 };
 
 } // namespace mozilla
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -1104,18 +1104,20 @@ EventListenerManager::HandleEventInterna
       hasListener = true;
       if (listener->IsListening(aEvent) &&
           (aEvent->mFlags.mIsTrusted ||
            listener->mFlags.mAllowUntrustedEvents)) {
         if (!*aDOMEvent) {
           // This is tiny bit slow, but happens only once per event.
           nsCOMPtr<EventTarget> et =
             do_QueryInterface(aEvent->originalTarget);
-          EventDispatcher::CreateEvent(et, aPresContext,
-                                       aEvent, EmptyString(), aDOMEvent);
+          nsRefPtr<Event> event = EventDispatcher::CreateEvent(et, aPresContext,
+                                                               aEvent,
+                                                               EmptyString());
+          event.forget(aDOMEvent);
         }
         if (*aDOMEvent) {
           if (!aEvent->currentTarget) {
             aEvent->currentTarget = aCurrentTarget->GetTargetForDOMEvent();
             if (!aEvent->currentTarget) {
               break;
             }
           }
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/DragEvent.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/UIEvent.h"
 
 #include "ContentEventHandler.h"
 #include "IMEContentObserver.h"
 #include "WheelHandlingHelper.h"
 
@@ -49,17 +50,16 @@
 #include "nsIContentViewer.h"
 #include "nsFrameManager.h"
 
 #include "nsIDOMXULElement.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIObserverService.h"
 #include "nsIDocShell.h"
 #include "nsIDOMWheelEvent.h"
-#include "nsIDOMDragEvent.h"
 #include "nsIDOMUIEvent.h"
 #include "nsIMozBrowserFrame.h"
 
 #include "nsSubDocumentFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsContentUtils.h"
@@ -1876,32 +1876,26 @@ EventStateManager::DoDefaultDragStart(ns
   nsCOMPtr<nsISupportsArray> transArray =
     aDataTransfer->GetTransferables(dragTarget->AsDOMNode());
   if (!transArray)
     return false;
 
   // XXXndeakin don't really want to create a new drag DOM event
   // here, but we need something to pass to the InvokeDragSession
   // methods.
-  nsCOMPtr<nsIDOMEvent> domEvent;
-  NS_NewDOMDragEvent(getter_AddRefs(domEvent), dragTarget,
-                     aPresContext, aDragEvent);
-
-  nsCOMPtr<nsIDOMDragEvent> domDragEvent = do_QueryInterface(domEvent);
-  // if creating a drag event failed, starting a drag session will
-  // just fail.
+  nsRefPtr<DragEvent> event =
+    NS_NewDOMDragEvent(dragTarget, aPresContext, aDragEvent);
 
   // Use InvokeDragSessionWithSelection if a selection is being dragged,
   // such that the image can be generated from the selected text. However,
   // use InvokeDragSessionWithImage if a custom image was set or something
   // other than a selection is being dragged.
   if (!dragImage && aSelection) {
     dragService->InvokeDragSessionWithSelection(aSelection, transArray,
-                                                action, domDragEvent,
-                                                aDataTransfer);
+                                                action, event, aDataTransfer);
   }
   else {
     // if dragging within a XUL tree and no custom drag image was
     // set, the region argument to InvokeDragSessionWithImage needs
     // to be set to the area encompassing the selected rows of the
     // tree to ensure that the drag feedback gets clipped to those
     // rows. For other content, region should be null.
     nsCOMPtr<nsIScriptableRegion> region;
@@ -1917,18 +1911,17 @@ EventStateManager::DoDefaultDragStart(ns
       }
     }
 #endif
 
     dragService->InvokeDragSessionWithImage(dragTarget->AsDOMNode(), transArray,
                                             region, action,
                                             dragImage ? dragImage->AsDOMNode() :
                                                         nullptr,
-                                            imageX,
-                                            imageY, domDragEvent,
+                                            imageX, imageY, event,
                                             aDataTransfer);
   }
 
   return true;
 }
 
 nsresult
 EventStateManager::GetContentViewer(nsIContentViewer** aCv)
--- a/dom/events/FocusEvent.cpp
+++ b/dom/events/FocusEvent.cpp
@@ -72,19 +72,16 @@ FocusEvent::Constructor(const GlobalObje
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMFocusEvent(nsIDOMEvent** aInstancePtrResult,
-                    EventTarget* aOwner,
+already_AddRefed<FocusEvent>
+NS_NewDOMFocusEvent(EventTarget* aOwner,
                     nsPresContext* aPresContext,
                     InternalFocusEvent* aEvent)
 {
-  FocusEvent* it = new FocusEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<FocusEvent> it = new FocusEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/FocusEvent.h
+++ b/dom/events/FocusEvent.h
@@ -48,9 +48,14 @@ protected:
                           nsIDOMWindow* aView,
                           int32_t aDetail,
                           EventTarget* aRelatedTarget);
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::FocusEvent>
+NS_NewDOMFocusEvent(mozilla::dom::EventTarget* aOwner,
+                    nsPresContext* aPresContext,
+                    mozilla::InternalFocusEvent* aEvent);
+
 #endif // mozilla_dom_FocusEvent_h_
--- a/dom/events/InputEvent.cpp
+++ b/dom/events/InputEvent.cpp
@@ -58,19 +58,16 @@ InputEvent::Constructor(const GlobalObje
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMInputEvent(nsIDOMEvent** aInstancePtrResult,
-                    EventTarget* aOwner,
+already_AddRefed<InputEvent>
+NS_NewDOMInputEvent(EventTarget* aOwner,
                     nsPresContext* aPresContext,
                     InternalEditorInputEvent* aEvent)
 {
-  InputEvent* it = new InputEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<InputEvent> it = new InputEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/InputEvent.h
+++ b/dom/events/InputEvent.h
@@ -41,9 +41,14 @@ public:
 
 protected:
   ~InputEvent() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::InputEvent>
+NS_NewDOMInputEvent(mozilla::dom::EventTarget* aOwner,
+                    nsPresContext* aPresContext,
+                    mozilla::InternalEditorInputEvent* aEvent);
+
 #endif // mozilla_dom_InputEvent_h_
--- a/dom/events/KeyboardEvent.cpp
+++ b/dom/events/KeyboardEvent.cpp
@@ -304,19 +304,16 @@ KeyboardEvent::InitKeyEvent(const nsAStr
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
-                       EventTarget* aOwner,
+already_AddRefed<KeyboardEvent>
+NS_NewDOMKeyboardEvent(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        WidgetKeyboardEvent* aEvent)
 {
-  KeyboardEvent* it = new KeyboardEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<KeyboardEvent> it = new KeyboardEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/KeyboardEvent.h
+++ b/dom/events/KeyboardEvent.h
@@ -88,9 +88,14 @@ private:
   // value.  mInitializedWhichValue stores it.  I.e., this is invalid when
   // mInitializedByCtor is false.
   uint32_t mInitializedWhichValue;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::KeyboardEvent>
+NS_NewDOMKeyboardEvent(mozilla::dom::EventTarget* aOwner,
+                       nsPresContext* aPresContext,
+                       mozilla::WidgetKeyboardEvent* aEvent);
+
 #endif // mozilla_dom_KeyboardEvent_h_
--- a/dom/events/MessageEvent.cpp
+++ b/dom/events/MessageEvent.cpp
@@ -167,17 +167,17 @@ MessageEvent::Constructor(EventTarget* a
   }
 
   if (aParam.mPorts.WasPassed() && !aParam.mPorts.Value().IsNull()) {
     nsTArray<nsRefPtr<MessagePortBase>> ports;
     for (uint32_t i = 0, len = aParam.mPorts.Value().Value().Length(); i < len; ++i) {
       ports.AppendElement(aParam.mPorts.Value().Value()[i].get());
     }
 
-    event->mPorts = new MessagePortList(static_cast<EventBase*>(event), ports);
+    event->mPorts = new MessagePortList(static_cast<Event*>(event), ports);
   }
 
   return event.forget();
 }
 
 NS_IMETHODIMP
 MessageEvent::InitMessageEvent(const nsAString& aType,
                                bool aCanBubble,
@@ -219,19 +219,16 @@ MessageEvent::SetSource(mozilla::dom::wo
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult,
-                      EventTarget* aOwner,
+already_AddRefed<MessageEvent>
+NS_NewDOMMessageEvent(EventTarget* aOwner,
                       nsPresContext* aPresContext,
                       WidgetEvent* aEvent) 
 {
-  MessageEvent* it = new MessageEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<MessageEvent> it = new MessageEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/MessageEvent.h
+++ b/dom/events/MessageEvent.h
@@ -97,9 +97,14 @@ private:
   nsRefPtr<MessagePortBase> mPortSource;
   nsRefPtr<workers::ServiceWorkerClient> mClientSource;
   nsRefPtr<MessagePortList> mPorts;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::MessageEvent>
+NS_NewDOMMessageEvent(mozilla::dom::EventTarget* aOwner,
+                      nsPresContext* aPresContext,
+                      mozilla::WidgetEvent* aEvent);
+
 #endif // mozilla_dom_MessageEvent_h_
--- a/dom/events/MouseEvent.cpp
+++ b/dom/events/MouseEvent.cpp
@@ -499,19 +499,16 @@ MouseEvent::GetMozInputSource(uint16_t* 
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMMouseEvent(nsIDOMEvent** aInstancePtrResult,
-                    EventTarget* aOwner,
+already_AddRefed<MouseEvent>
+NS_NewDOMMouseEvent(EventTarget* aOwner,
                     nsPresContext* aPresContext,
                     WidgetMouseEvent* aEvent)
 {
-  MouseEvent* it = new MouseEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<MouseEvent> it = new MouseEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/MouseEvent.h
+++ b/dom/events/MouseEvent.h
@@ -127,9 +127,14 @@ protected:
 
 } // namespace dom
 } // namespace mozilla
 
 #define NS_FORWARD_TO_MOUSEEVENT \
   NS_FORWARD_NSIDOMMOUSEEVENT(MouseEvent::) \
   NS_FORWARD_TO_UIEVENT
 
+already_AddRefed<mozilla::dom::MouseEvent>
+NS_NewDOMMouseEvent(mozilla::dom::EventTarget* aOwner,
+                    nsPresContext* aPresContext,
+                    mozilla::WidgetMouseEvent* aEvent);
+
 #endif // mozilla_dom_MouseEvent_h_
--- a/dom/events/MouseScrollEvent.cpp
+++ b/dom/events/MouseScrollEvent.cpp
@@ -83,19 +83,17 @@ MouseScrollEvent::Axis()
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace dom;
 
-nsresult
-NS_NewDOMMouseScrollEvent(nsIDOMEvent** aInstancePtrResult,
-                          EventTarget* aOwner,
+already_AddRefed<MouseScrollEvent>
+NS_NewDOMMouseScrollEvent(EventTarget* aOwner,
                           nsPresContext* aPresContext,
                           WidgetMouseScrollEvent* aEvent)
 {
-  MouseScrollEvent* it = new MouseScrollEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<MouseScrollEvent> it =
+    new MouseScrollEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/MouseScrollEvent.h
+++ b/dom/events/MouseScrollEvent.h
@@ -54,9 +54,14 @@ public:
 
 protected:
   ~MouseScrollEvent() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::MouseScrollEvent>
+NS_NewDOMMouseScrollEvent(mozilla::dom::EventTarget* aOwner,
+                          nsPresContext* aPresContext,
+                          mozilla::WidgetMouseScrollEvent* aEvent);
+
 #endif // mozilla_dom_MouseScrollEvent_h_
--- a/dom/events/MutationEvent.cpp
+++ b/dom/events/MutationEvent.cpp
@@ -114,19 +114,16 @@ MutationEvent::InitMutationEvent(const n
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMMutationEvent(nsIDOMEvent** aInstancePtrResult,
-                       EventTarget* aOwner,
+already_AddRefed<MutationEvent>
+NS_NewDOMMutationEvent(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        InternalMutationEvent* aEvent) 
 {
-  MutationEvent* it = new MutationEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<MutationEvent> it = new MutationEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/MutationEvent.h
+++ b/dom/events/MutationEvent.h
@@ -60,9 +60,14 @@ public:
 
 protected:
   ~MutationEvent() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::MutationEvent>
+NS_NewDOMMutationEvent(mozilla::dom::EventTarget* aOwner,
+                       nsPresContext* aPresContext,
+                       mozilla::InternalMutationEvent* aEvent);
+
 #endif // mozilla_dom_MutationEvent_h_
--- a/dom/events/NotifyPaintEvent.cpp
+++ b/dom/events/NotifyPaintEvent.cpp
@@ -157,22 +157,20 @@ NotifyPaintEvent::Deserialize(const IPC:
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMNotifyPaintEvent(nsIDOMEvent** aInstancePtrResult,
-                          EventTarget* aOwner,
+already_AddRefed<NotifyPaintEvent>
+NS_NewDOMNotifyPaintEvent(EventTarget* aOwner,
                           nsPresContext* aPresContext,
                           WidgetEvent* aEvent,
                           uint32_t aEventType,
                           nsInvalidateRequestList* aInvalidateRequests) 
 {
-  NotifyPaintEvent* it = new NotifyPaintEvent(aOwner, aPresContext, aEvent,
-                                              aEventType, aInvalidateRequests);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<NotifyPaintEvent> it =
+    new NotifyPaintEvent(aOwner, aPresContext, aEvent, aEventType,
+                         aInvalidateRequests);
+  return it.forget();
 }
--- a/dom/events/NotifyPaintEvent.h
+++ b/dom/events/NotifyPaintEvent.h
@@ -62,9 +62,17 @@ private:
   nsRegion GetRegion();
 
   nsTArray<nsInvalidateRequestList::Request> mInvalidateRequests;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+// This empties aInvalidateRequests.
+already_AddRefed<mozilla::dom::NotifyPaintEvent>
+NS_NewDOMNotifyPaintEvent(mozilla::dom::EventTarget* aOwner,
+                          nsPresContext* aPresContext,
+                          mozilla::WidgetEvent* aEvent,
+                          uint32_t aEventType = 0,
+                          nsInvalidateRequestList* aInvalidateRequests = nullptr);
+
 #endif // mozilla_dom_NotifyPaintEvent_h_
--- a/dom/events/PointerEvent.cpp
+++ b/dom/events/PointerEvent.cpp
@@ -159,19 +159,16 @@ PointerEvent::IsPrimary()
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMPointerEvent(nsIDOMEvent** aInstancePtrResult,
-                      EventTarget* aOwner,
+already_AddRefed<PointerEvent>
+NS_NewDOMPointerEvent(EventTarget* aOwner,
                       nsPresContext* aPresContext,
                       WidgetPointerEvent *aEvent)
 {
-  PointerEvent *it = new PointerEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<PointerEvent> it = new PointerEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/PointerEvent.h
+++ b/dom/events/PointerEvent.h
@@ -50,9 +50,14 @@ public:
   void GetPointerType(nsAString& aPointerType);
 };
 
 void ConvertPointerTypeToString(uint16_t aPointerTypeSrc, nsAString& aPointerTypeDest);
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::PointerEvent>
+NS_NewDOMPointerEvent(mozilla::dom::EventTarget* aOwner,
+                      nsPresContext* aPresContext,
+                      mozilla::WidgetPointerEvent* aEvent);
+
 #endif // mozilla_dom_PointerEvent_h_
--- a/dom/events/ScrollAreaEvent.cpp
+++ b/dom/events/ScrollAreaEvent.cpp
@@ -95,17 +95,17 @@ ScrollAreaEvent::Deserialize(const IPC::
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMScrollAreaEvent(nsIDOMEvent** aInstancePtrResult,
-                         EventTarget* aOwner,
+already_AddRefed<ScrollAreaEvent>
+NS_NewDOMScrollAreaEvent(EventTarget* aOwner,
                          nsPresContext* aPresContext,
                          InternalScrollAreaEvent* aEvent)
 {
-  ScrollAreaEvent* ev = new ScrollAreaEvent(aOwner, aPresContext, aEvent);
-  return CallQueryInterface(ev, aInstancePtrResult);
+  nsRefPtr<ScrollAreaEvent> ev =
+    new ScrollAreaEvent(aOwner, aPresContext, aEvent);
+  return ev.forget();
 }
--- a/dom/events/ScrollAreaEvent.h
+++ b/dom/events/ScrollAreaEvent.h
@@ -81,9 +81,14 @@ protected:
   ~ScrollAreaEvent() {}
 
   nsRefPtr<DOMRect> mClientArea;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::ScrollAreaEvent>
+NS_NewDOMScrollAreaEvent(mozilla::dom::EventTarget* aOwner,
+                         nsPresContext* aPresContext,
+                         mozilla::InternalScrollAreaEvent* aEvent);
+
 #endif // mozilla_dom_ScrollAreaEvent_h_
--- a/dom/events/SimpleGestureEvent.cpp
+++ b/dom/events/SimpleGestureEvent.cpp
@@ -141,19 +141,17 @@ SimpleGestureEvent::InitSimpleGestureEve
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMSimpleGestureEvent(nsIDOMEvent** aInstancePtrResult,
-                            EventTarget* aOwner,
+already_AddRefed<SimpleGestureEvent>
+NS_NewDOMSimpleGestureEvent(EventTarget* aOwner,
                             nsPresContext* aPresContext,
                             WidgetSimpleGestureEvent* aEvent)
 {
-  SimpleGestureEvent* it = new SimpleGestureEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<SimpleGestureEvent> it =
+    new SimpleGestureEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/SimpleGestureEvent.h
+++ b/dom/events/SimpleGestureEvent.h
@@ -73,9 +73,14 @@ public:
 
 protected:
   ~SimpleGestureEvent() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::SimpleGestureEvent>
+NS_NewDOMSimpleGestureEvent(mozilla::dom::EventTarget* aOwner,
+                            nsPresContext* aPresContext,
+                            mozilla::WidgetSimpleGestureEvent* aEvent);
+
 #endif // mozilla_dom_SimpleGestureEvent_h_
--- a/dom/events/StorageEvent.cpp
+++ b/dom/events/StorageEvent.cpp
@@ -98,21 +98,20 @@ StorageEvent::InitStorageEvent(const nsA
   mNewValue = aNewValue;
   mUrl = aURL;
   mStorageArea = aStorageArea;
 }
 
 } // namespace dom
 } // namespace mozilla
 
-nsresult
-NS_NewDOMStorageEvent(nsIDOMEvent** aDOMEvent,
-                      mozilla::dom::EventTarget* aOwner)
+using namespace mozilla;
+using namespace mozilla::dom;
+
+already_AddRefed<StorageEvent>
+NS_NewDOMStorageEvent(EventTarget* aOwner)
 {
-  nsRefPtr<mozilla::dom::StorageEvent> e =
-    new mozilla::dom::StorageEvent(aOwner);
+  nsRefPtr<StorageEvent> e = new StorageEvent(aOwner);
 
   e->SetTrusted(e->Init(aOwner));
-  e.forget(aDOMEvent);
-
-  return NS_OK;
+  return e.forget();
 }
 
--- a/dom/events/StorageEvent.h
+++ b/dom/events/StorageEvent.h
@@ -9,18 +9,18 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/StorageEventBinding.h"
 
 // Helper for EventDispatcher.
-nsresult NS_NewDOMStorageEvent(nsIDOMEvent** aDOMEvent,
-                               mozilla::dom::EventTarget* aOwner);
+already_AddRefed<mozilla::dom::StorageEvent>
+NS_NewDOMStorageEvent(mozilla::dom::EventTarget* aOwner);
 
 namespace mozilla {
 namespace dom {
 
 class DOMStorage;
 
 class StorageEvent : public Event
 {
--- a/dom/events/TouchEvent.cpp
+++ b/dom/events/TouchEvent.cpp
@@ -233,19 +233,16 @@ TouchEvent::ShiftKey()
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult,
-                    EventTarget* aOwner,
+already_AddRefed<TouchEvent>
+NS_NewDOMTouchEvent(EventTarget* aOwner,
                     nsPresContext* aPresContext,
                     WidgetTouchEvent* aEvent)
 {
-  TouchEvent* it = new TouchEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<TouchEvent> it = new TouchEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/TouchEvent.h
+++ b/dom/events/TouchEvent.h
@@ -127,9 +127,14 @@ protected:
   nsRefPtr<TouchList> mTouches;
   nsRefPtr<TouchList> mTargetTouches;
   nsRefPtr<TouchList> mChangedTouches;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::TouchEvent>
+NS_NewDOMTouchEvent(mozilla::dom::EventTarget* aOwner,
+                    nsPresContext* aPresContext,
+                    mozilla::WidgetTouchEvent* aEvent);
+
 #endif // mozilla_dom_TouchEvent_h_
--- a/dom/events/TransitionEvent.cpp
+++ b/dom/events/TransitionEvent.cpp
@@ -83,19 +83,17 @@ TransitionEvent::GetPseudoElement(nsAStr
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMTransitionEvent(nsIDOMEvent** aInstancePtrResult,
-                         EventTarget* aOwner,
+already_AddRefed<TransitionEvent>
+NS_NewDOMTransitionEvent(EventTarget* aOwner,
                          nsPresContext* aPresContext,
                          InternalTransitionEvent* aEvent)
 {
-  TransitionEvent *it = new TransitionEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<TransitionEvent> it =
+    new TransitionEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/TransitionEvent.h
+++ b/dom/events/TransitionEvent.h
@@ -47,9 +47,14 @@ public:
 
 protected:
   ~TransitionEvent() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::TransitionEvent>
+NS_NewDOMTransitionEvent(mozilla::dom::EventTarget* aOwner,
+                         nsPresContext* aPresContext,
+                         mozilla::InternalTransitionEvent* aEvent);
+
 #endif // mozilla_dom_TransitionEvent_h_
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -494,19 +494,16 @@ UIEvent::InitModifiers(const EventModifi
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMUIEvent(nsIDOMEvent** aInstancePtrResult,
-                 EventTarget* aOwner,
+already_AddRefed<UIEvent>
+NS_NewDOMUIEvent(EventTarget* aOwner,
                  nsPresContext* aPresContext,
                  WidgetGUIEvent* aEvent) 
 {
-  UIEvent* it = new UIEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<UIEvent> it = new UIEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/UIEvent.h
+++ b/dom/events/UIEvent.h
@@ -189,9 +189,14 @@ protected:
     UIEvent::Serialize(aMsg, aSerializeInterfaceType);      \
   }                                                         \
   NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg,   \
                                 void** aIter) override      \
   {                                                         \
     return UIEvent::Deserialize(aMsg, aIter);               \
   }
 
+already_AddRefed<mozilla::dom::UIEvent>
+NS_NewDOMUIEvent(mozilla::dom::EventTarget* aOwner,
+                 nsPresContext* aPresContext,
+                 mozilla::WidgetGUIEvent* aEvent);
+
 #endif // mozilla_dom_UIEvent_h_
--- a/dom/events/WheelEvent.cpp
+++ b/dom/events/WheelEvent.cpp
@@ -170,19 +170,16 @@ WheelEvent::Constructor(const GlobalObje
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMWheelEvent(nsIDOMEvent** aInstancePtrResult,
-                    EventTarget* aOwner,
+already_AddRefed<WheelEvent>
+NS_NewDOMWheelEvent(EventTarget* aOwner,
                     nsPresContext* aPresContext,
                     WidgetWheelEvent* aEvent)
 {
-  WheelEvent* it = new WheelEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<WheelEvent> it = new WheelEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/WheelEvent.h
+++ b/dom/events/WheelEvent.h
@@ -55,9 +55,14 @@ protected:
 
 private:
   int32_t mAppUnitsPerDevPixel;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::WheelEvent>
+NS_NewDOMWheelEvent(mozilla::dom::EventTarget* aOwner,
+                    nsPresContext* aPresContext,
+                    mozilla::WidgetWheelEvent* aEvent);
+
 #endif // mozilla_dom_WheelEvent_h_
--- a/dom/events/XULCommandEvent.cpp
+++ b/dom/events/XULCommandEvent.cpp
@@ -124,19 +124,17 @@ XULCommandEvent::InitCommandEvent(const 
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMXULCommandEvent(nsIDOMEvent** aInstancePtrResult,
-                         EventTarget* aOwner,
+already_AddRefed<XULCommandEvent>
+NS_NewDOMXULCommandEvent(EventTarget* aOwner,
                          nsPresContext* aPresContext,
                          WidgetInputEvent* aEvent) 
 {
-  XULCommandEvent* it = new XULCommandEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<XULCommandEvent> it =
+    new XULCommandEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/events/XULCommandEvent.h
+++ b/dom/events/XULCommandEvent.h
@@ -66,9 +66,14 @@ protected:
   ~XULCommandEvent() {}
 
   nsCOMPtr<nsIDOMEvent> mSourceEvent;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::XULCommandEvent>
+NS_NewDOMXULCommandEvent(mozilla::dom::EventTarget* aOwner,
+                         nsPresContext* aPresContext,
+                         mozilla::WidgetInputEvent* aEvent);
+
 #endif // mozilla_dom_XULCommandEvent_h_
--- a/dom/events/moz.build
+++ b/dom/events/moz.build
@@ -130,16 +130,17 @@ include('/ipc/chromium/chromium-config.m
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/docshell/base',
     '/dom/base',
     '/dom/html',
     '/dom/settings',
     '/dom/storage',
+    '/dom/svg',
     '/dom/workers',
     '/dom/xml',
     '/dom/xul',
     '/js/xpconnect/wrappers',
     '/layout/generic',
     '/layout/xul',
     '/layout/xul/tree/',
 ]
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -5398,27 +5398,23 @@ HTMLInputElement::GetPhonetic(nsAString&
 }
 
 #ifdef ACCESSIBILITY
 /*static*/ nsresult
 FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
                           nsPresContext* aPresContext,
                           const nsAString& aEventType)
 {
-  nsCOMPtr<nsIDOMEvent> event;
   nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aTarget);
-  if (NS_SUCCEEDED(EventDispatcher::CreateEvent(element, aPresContext, nullptr,
-                                                NS_LITERAL_STRING("Events"),
-                                                getter_AddRefs(event)))) {
-    event->InitEvent(aEventType, true, true);
-    event->SetTrusted(true);
-
-    EventDispatcher::DispatchDOMEvent(aTarget, nullptr, event, aPresContext,
-                                      nullptr);
-  }
+  nsRefPtr<Event> event = NS_NewDOMEvent(element, aPresContext, nullptr);
+  event->InitEvent(aEventType, true, true);
+  event->SetTrusted(true);
+
+  EventDispatcher::DispatchDOMEvent(aTarget, nullptr, event, aPresContext,
+                                    nullptr);
 
   return NS_OK;
 }
 #endif
 
 nsresult
 HTMLInputElement::SetDefaultValueAsValue()
 {
--- a/dom/interfaces/events/nsIDOMEvent.idl
+++ b/dom/interfaces/events/nsIDOMEvent.idl
@@ -210,167 +210,8 @@ interface nsIDOMEvent : nsISupports
   [noscript,notxpcom] void SetTrusted(in boolean aTrusted);
   [notxpcom] void Serialize(in IPCMessagePtr aMsg,
                             in boolean aSerializeInterfaceType);
   [notxpcom] boolean Deserialize(in ConstIPCMessagePtr aMsg, out voidPtr aIter);
   [noscript,notxpcom] void SetOwner(in EventTargetPtr aOwner);
   [notxpcom] DOMEventPtr InternalDOMEvent();
   [noscript] void stopCrossProcessForwarding();
 };
-
-%{C++
-
-nsresult
-NS_NewDOMEvent(nsIDOMEvent** aInstancePtrResult,
-               mozilla::dom::EventTarget* aOwner,
-               nsPresContext* aPresContext,
-               mozilla::WidgetEvent* aEvent);
-nsresult
-NS_NewDOMDataContainerEvent(nsIDOMEvent** aInstancePtrResult,
-                            mozilla::dom::EventTarget* aOwner,
-                            nsPresContext* aPresContext,
-                            mozilla::WidgetEvent* aEvent);
-nsresult
-NS_NewDOMUIEvent(nsIDOMEvent** aInstancePtrResult,
-                 mozilla::dom::EventTarget* aOwner,
-                 nsPresContext* aPresContext,
-                 mozilla::WidgetGUIEvent* aEvent);
-nsresult
-NS_NewDOMMouseEvent(nsIDOMEvent** aInstancePtrResult,
-                    mozilla::dom::EventTarget* aOwner,
-                    nsPresContext* aPresContext,
-                    mozilla::WidgetMouseEvent* aEvent);
-nsresult
-NS_NewDOMFocusEvent(nsIDOMEvent** aInstancePtrResult,
-                    mozilla::dom::EventTarget* aOwner,
-                    nsPresContext* aPresContext,
-                    mozilla::InternalFocusEvent* aEvent);
-nsresult
-NS_NewDOMMouseScrollEvent(nsIDOMEvent** aInstancePtrResult,
-                          mozilla::dom::EventTarget* aOwner,
-                          nsPresContext* aPresContext,
-                          mozilla::WidgetMouseScrollEvent* aEvent);
-nsresult
-NS_NewDOMWheelEvent(nsIDOMEvent** aInstancePtrResult,
-                    mozilla::dom::EventTarget* aOwner,
-                    nsPresContext* aPresContext,
-                    mozilla::WidgetWheelEvent* aEvent);
-nsresult
-NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult,
-                   mozilla::dom::EventTarget* aOwner,
-                   nsPresContext* aPresContext,
-                   mozilla::WidgetDragEvent* aEvent);
-nsresult
-NS_NewDOMClipboardEvent(nsIDOMEvent** aInstancePtrResult,
-                        mozilla::dom::EventTarget* aOwner,
-                        nsPresContext* aPresContext,
-                        mozilla::InternalClipboardEvent* aEvent);
-nsresult
-NS_NewDOMInputEvent(nsIDOMEvent** aInstancePtrResult,
-                    mozilla::dom::EventTarget* aOwner,
-                    nsPresContext* aPresContext,
-                    mozilla::InternalEditorInputEvent* aEvent);
-nsresult
-NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
-                       mozilla::dom::EventTarget* aOwner,
-                       nsPresContext* aPresContext,
-                       mozilla::WidgetKeyboardEvent* aEvent);
-
-nsresult
-NS_NewDOMBeforeAfterKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
-                                  mozilla::dom::EventTarget* aOwner,
-                                  nsPresContext* aPresContext,
-                                  mozilla::InternalBeforeAfterKeyboardEvent* aEvent);
-
-nsresult
-NS_NewDOMCompositionEvent(nsIDOMEvent** aInstancePtrResult,
-                          mozilla::dom::EventTarget* aOwner,
-                          nsPresContext* aPresContext,
-                          mozilla::WidgetCompositionEvent* aEvent);
-nsresult
-NS_NewDOMMutationEvent(nsIDOMEvent** aResult,
-                       mozilla::dom::EventTarget* aOwner,
-                       nsPresContext* aPresContext,
-                       mozilla::InternalMutationEvent* aEvent);
-nsresult
-NS_NewDOMDeviceMotionEvent(nsIDOMEvent** aResult,
-                           mozilla::dom::EventTarget* aOwner,
-                           nsPresContext* aPresContext,
-                           mozilla::WidgetEvent* aEvent);
-nsresult
-NS_NewDOMBeforeUnloadEvent(nsIDOMEvent** aResult,
-                           mozilla::dom::EventTarget* aOwner,
-                           nsPresContext* aPresContext,
-                           mozilla::WidgetEvent* aEvent);
-nsresult
-NS_NewDOMSVGEvent(nsIDOMEvent** aResult,
-                  mozilla::dom::EventTarget* aOwner,
-                  nsPresContext* aPresContext,
-                  mozilla::WidgetEvent* aEvent);
-nsresult
-NS_NewDOMSVGZoomEvent(nsIDOMEvent** aResult,
-                      mozilla::dom::EventTarget* aOwner,
-                      nsPresContext* aPresContext,
-                      mozilla::InternalSVGZoomEvent* aEvent);
-nsresult
-NS_NewDOMTimeEvent(nsIDOMEvent** aResult,
-                   mozilla::dom::EventTarget* aOwner,
-                   nsPresContext* aPresContext,
-                   mozilla::InternalSMILTimeEvent* aEvent);
-nsresult
-NS_NewDOMXULCommandEvent(nsIDOMEvent** aResult,
-                         mozilla::dom::EventTarget* aOwner,
-                         nsPresContext* aPresContext,
-                         mozilla::WidgetInputEvent* aEvent);
-nsresult
-NS_NewDOMCommandEvent(nsIDOMEvent** aInstancePtrResult,
-                      mozilla::dom::EventTarget* aOwner,
-                      nsPresContext* aPresContext,
-                      mozilla::WidgetCommandEvent* aEvent);
-nsresult
-NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult,
-                      mozilla::dom::EventTarget* aOwner,
-                      nsPresContext* aPresContext,
-                      mozilla::WidgetEvent* aEvent);
-// This empties aInvalidateRequests.
-nsresult
-NS_NewDOMNotifyPaintEvent(nsIDOMEvent** aResult,
-                          mozilla::dom::EventTarget* aOwner,
-                          nsPresContext* aPresContext,
-                          mozilla::WidgetEvent* aEvent,
-                          uint32_t aEventType = 0,
-                          nsInvalidateRequestList* aInvalidateRequests = nullptr);
-nsresult
-NS_NewDOMSimpleGestureEvent(nsIDOMEvent** aInstancePtrResult,
-                            mozilla::dom::EventTarget* aOwner,
-                            nsPresContext* aPresContext,
-                            mozilla::WidgetSimpleGestureEvent* aEvent);
-nsresult
-NS_NewDOMScrollAreaEvent(nsIDOMEvent** aInstancePtrResult,
-                         mozilla::dom::EventTarget* aOwner,
-                         nsPresContext* aPresContext,
-                         mozilla::InternalScrollAreaEvent* aEvent);
-nsresult
-NS_NewDOMTransitionEvent(nsIDOMEvent** aInstancePtrResult,
-                         mozilla::dom::EventTarget* aOwner,
-                         nsPresContext* aPresContext,
-                         mozilla::InternalTransitionEvent* aEvent);
-nsresult
-NS_NewDOMAnimationEvent(nsIDOMEvent** aInstancePtrResult,
-                        mozilla::dom::EventTarget* aOwner,
-                        nsPresContext* aPresContext,
-                        mozilla::InternalAnimationEvent* aEvent);
-nsresult
-NS_NewDOMPointerEvent(nsIDOMEvent** aInstancePtrResult,
-                      mozilla::dom::EventTarget* aOwner,
-                      nsPresContext* aPresContext,
-                      mozilla::WidgetPointerEvent* aEvent);
-nsresult
-NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult,
-                    mozilla::dom::EventTarget* aOwner,
-                    nsPresContext* aPresContext,
-                    mozilla::WidgetTouchEvent* aEvent);
-nsresult
-NS_NewDOMCustomEvent(nsIDOMEvent** aInstancePtrResult,
-                     mozilla::dom::EventTarget* aOwner,
-                     nsPresContext* aPresContext,
-                     mozilla::WidgetEvent* aEvent);
-%}
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -140,16 +140,22 @@ parent:
     sync PPluginWidget();
 
     /**
      * Return native data of root widget
      */
     sync GetWidgetNativeData() returns (WindowsHandle value);
 
     /**
+     * Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the
+     * widget's shareable window on the chrome side. Only used on Windows.
+     */
+    async SetNativeChildOfShareableWindow(uintptr_t childWindow);
+
+    /**
      * When content moves focus from a native plugin window that's a child
      * of the native browser window we need to move native focus to the
      * browser. Otherwise the plugin window will never relinquish focus.
      */
     sync DispatchFocusToTopLevelWindow();
 
 parent:
     /**
--- a/dom/ipc/TabMessageUtils.cpp
+++ b/dom/ipc/TabMessageUtils.cpp
@@ -1,33 +1,30 @@
 /* -*- 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/EventDispatcher.h"
+#include "mozilla/dom/Event.h"
 #include "mozilla/dom/TabMessageUtils.h"
 #include "nsCOMPtr.h"
-#include "nsIDOMEvent.h"
 
 namespace mozilla {
 namespace dom {
 
 bool
 ReadRemoteEvent(const IPC::Message* aMsg, void** aIter,
                 RemoteDOMEvent* aResult)
 {
   aResult->mEvent = nullptr;
   nsString type;
   NS_ENSURE_TRUE(ReadParam(aMsg, aIter, &type), false);
 
-  nsCOMPtr<nsIDOMEvent> event;
-  EventDispatcher::CreateEvent(nullptr, nullptr, nullptr, type,
-                               getter_AddRefs(event));
-  aResult->mEvent = do_QueryInterface(event);
-  NS_ENSURE_TRUE(aResult->mEvent, false);
+  aResult->mEvent = EventDispatcher::CreateEvent(nullptr, nullptr, nullptr,
+                                                 type);
 
   return aResult->mEvent->Deserialize(aMsg, aIter);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2533,16 +2533,34 @@ TabParent::RecvGetWidgetNativeData(Windo
   if (widget) {
     *aValue = reinterpret_cast<WindowsHandle>(
       widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
   }
   return true;
 }
 
 bool
+TabParent::RecvSetNativeChildOfShareableWindow(const uintptr_t& aChildWindow)
+{
+#if defined(XP_WIN)
+  nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
+  if (widget) {
+    // Note that this call will probably cause a sync native message to the
+    // process that owns the child window.
+    widget->SetNativeData(NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW, aChildWindow);
+  }
+  return true;
+#else
+  NS_NOTREACHED(
+    "TabParent::RecvSetNativeChildOfShareableWindow not implemented!");
+  return false;
+#endif
+}
+
+bool
 TabParent::RecvDispatchFocusToTopLevelWindow()
 {
   nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
   if (widget) {
     widget->SetFocus(false);
   }
   return true;
 }
@@ -3017,18 +3035,17 @@ bool
 TabParent::LayerTreeUpdate(bool aActive)
 {
   nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(mFrameElement);
   if (!target) {
     NS_WARNING("Could not locate target for layer tree message.");
     return true;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  NS_NewDOMEvent(getter_AddRefs(event), mFrameElement, nullptr, nullptr);
+  nsRefPtr<Event> event = NS_NewDOMEvent(mFrameElement, nullptr, nullptr);
   if (aActive) {
     event->InitEvent(NS_LITERAL_STRING("MozLayerTreeReady"), true, false);
   } else {
     event->InitEvent(NS_LITERAL_STRING("MozLayerTreeCleared"), true, false);
   }
   event->SetTrusted(true);
   event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
   bool dummy;
@@ -3057,18 +3074,17 @@ bool
 TabParent::RecvRemotePaintIsReady()
 {
   nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(mFrameElement);
   if (!target) {
     NS_WARNING("Could not locate target for MozAfterRemotePaint message.");
     return true;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  NS_NewDOMEvent(getter_AddRefs(event), mFrameElement, nullptr, nullptr);
+  nsRefPtr<Event> event = NS_NewDOMEvent(mFrameElement, nullptr, nullptr);
   event->InitEvent(NS_LITERAL_STRING("MozAfterRemotePaint"), false, false);
   event->SetTrusted(true);
   event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
   bool dummy;
   mFrameElement->DispatchEvent(event, &dummy);
   return true;
 }
 
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -216,16 +216,17 @@ public:
     virtual bool RecvIsParentWindowMainWidgetVisible(bool* aIsVisible) override;
     virtual bool RecvShowTooltip(const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip) override;
     virtual bool RecvHideTooltip() override;
     virtual bool RecvGetTabOffset(LayoutDeviceIntPoint* aPoint) override;
     virtual bool RecvGetDPI(float* aValue) override;
     virtual bool RecvGetDefaultScale(double* aValue) override;
     virtual bool RecvGetMaxTouchPoints(uint32_t* aTouchPoints) override;
     virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue) override;
+    virtual bool RecvSetNativeChildOfShareableWindow(const uintptr_t& childWindow) override;
     virtual bool RecvDispatchFocusToTopLevelWindow() override;
     virtual bool RecvZoomToRect(const uint32_t& aPresShellId,
                                 const ViewID& aViewId,
                                 const CSSRect& aRect) override;
     virtual bool RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
                                            const ViewID& aViewId,
                                            const MaybeZoomConstraints& aConstraints) override;
     virtual bool RecvContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -98,17 +98,17 @@ public:
 
   // Return true if the media layer supports seeking.
   virtual bool IsTransportSeekable() = 0;
 
   // Return true if the transport layer supports seeking.
   virtual bool IsMediaSeekable() = 0;
 
   virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags, MediaDecoderEventVisibility aEventVisibility) = 0;
-  virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) = 0;
+  virtual void QueueMetadata(const media::TimeUnit& aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) = 0;
   virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, MediaDecoderEventVisibility aEventVisibility) = 0;
 
   virtual void RemoveMediaTracks() = 0;
 
   // May be called by the reader to notify this decoder that the metadata from
   // the media file has been read. Call on the decode thread only.
   virtual void OnReadMetadataCompleted() = 0;
 
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -633,17 +633,17 @@ double MediaDecoder::GetCurrentTime()
 }
 
 already_AddRefed<nsIPrincipal> MediaDecoder::GetCurrentPrincipal()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mResource ? mResource->GetCurrentPrincipal() : nullptr;
 }
 
-void MediaDecoder::QueueMetadata(int64_t aPublishTime,
+void MediaDecoder::QueueMetadata(const TimeUnit& aPublishTime,
                                  nsAutoPtr<MediaInfo> aInfo,
                                  nsAutoPtr<MetadataTags> aTags)
 {
   MOZ_ASSERT(OnDecodeTaskQueue());
   GetReentrantMonitor().AssertCurrentThreadIn();
   mDecoderStateMachine->QueueMetadata(aPublishTime, aInfo, aTags);
 }
 
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -577,17 +577,17 @@ public:
   bool CanPlayThrough();
 
   void SetAudioChannel(dom::AudioChannel aChannel) { mAudioChannel = aChannel; }
   dom::AudioChannel GetAudioChannel() { return mAudioChannel; }
 
   // Send a new set of metadata to the state machine, to be dispatched to the
   // main thread to be presented when the |currentTime| of the media is greater
   // or equal to aPublishTime.
-  void QueueMetadata(int64_t aPublishTime,
+  void QueueMetadata(const media::TimeUnit& aPublishTime,
                      nsAutoPtr<MediaInfo> aInfo,
                      nsAutoPtr<MetadataTags> aTags) override;
 
   /******
    * The following methods must only be called on the main
    * thread.
    ******/
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1101,17 +1101,17 @@ void MediaDecoderStateMachine::UpdatePla
 }
 
 void MediaDecoderStateMachine::UpdatePlaybackPosition(int64_t aTime)
 {
   MOZ_ASSERT(OnTaskQueue());
   UpdatePlaybackPositionInternal(aTime);
 
   bool fragmentEnded = mFragmentEndTime >= 0 && GetMediaTime() >= mFragmentEndTime;
-  mMetadataManager.DispatchMetadataIfNeeded(mDecoder, aTime);
+  mMetadataManager.DispatchMetadataIfNeeded(mDecoder, TimeUnit::FromMicroseconds(aTime));
 
   if (fragmentEnded) {
     StopPlayback();
   }
 }
 
 void MediaDecoderStateMachine::ClearPositionChangeFlag()
 {
@@ -3002,17 +3002,17 @@ void MediaDecoderStateMachine::Preserves
 }
 
 bool MediaDecoderStateMachine::IsShutdown()
 {
   MOZ_ASSERT(OnTaskQueue());
   return mIsShutdown;
 }
 
-void MediaDecoderStateMachine::QueueMetadata(int64_t aPublishTime,
+void MediaDecoderStateMachine::QueueMetadata(const TimeUnit& aPublishTime,
                                              nsAutoPtr<MediaInfo> aInfo,
                                              nsAutoPtr<MetadataTags> aTags)
 {
   MOZ_ASSERT(OnDecodeTaskQueue());
   AssertCurrentThreadInMonitor();
   TimedMetadata* metadata = new TimedMetadata;
   metadata->mPublishTime = aPublishTime;
   metadata->mInfo = aInfo.forget();
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -327,17 +327,17 @@ public:
   void FinishStreamData();
   bool HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs);
   bool HaveEnoughDecodedVideo();
 
   // Returns true if the state machine has shutdown or is in the process of
   // shutting down. The decoder monitor must be held while calling this.
   bool IsShutdown();
 
-  void QueueMetadata(int64_t aPublishTime,
+  void QueueMetadata(const media::TimeUnit& aPublishTime,
                      nsAutoPtr<MediaInfo> aInfo,
                      nsAutoPtr<MetadataTags> aTags);
 
   // Returns true if we're currently playing. The decoder monitor must
   // be held.
   bool IsPlaying() const;
 
   // Called when the reader may have acquired the hardware resources required
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -757,18 +757,18 @@ MediaFormatReader::OnAudioDemuxCompleted
   mAudio.mQueuedSamples.AppendElements(aSamples->mSamples);
   ScheduleUpdate(TrackInfo::kAudioTrack);
 }
 
 void
 MediaFormatReader::NotifyNewOutput(TrackType aTrack, MediaData* aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
-  LOGV("Received new sample time:%lld duration:%lld",
-       aSample->mTime, aSample->mDuration);
+  LOGV("Received new %s sample time:%lld duration:%lld",
+       TrackTypeToStr(aTrack), aSample->mTime, aSample->mDuration);
   auto& decoder = GetDecoderData(aTrack);
   if (!decoder.mOutputRequested) {
     LOG("MediaFormatReader produced output while flushing, discarding.");
     return;
   }
   decoder.mOutput.AppendElement(aSample);
   decoder.mNumSamplesOutput++;
   ScheduleUpdate(aTrack);
@@ -810,17 +810,16 @@ MediaFormatReader::NotifyError(TrackType
 }
 
 void
 MediaFormatReader::NotifyWaitingForData(TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
   auto& decoder = GetDecoderData(aTrack);
   decoder.mWaitingForData = true;
-  decoder.mNeedDraining = true;
   ScheduleUpdate(aTrack);
 }
 
 void
 MediaFormatReader::NotifyEndOfStream(TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
   auto& decoder = GetDecoderData(aTrack);
@@ -974,17 +973,17 @@ MediaFormatReader::DecodeDemuxedSamples(
 
       if (decoder.mNextStreamSourceID.isNothing() ||
           decoder.mNextStreamSourceID.ref() != info->GetID()) {
         LOG("%s stream id has changed from:%d to:%d, draining decoder.",
             TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
             info->GetID());
         decoder.mNeedDraining = true;
         decoder.mNextStreamSourceID = Some(info->GetID());
-        DrainDecoder(aTrack);
+        ScheduleUpdate(aTrack);
         return;
       }
 
       LOG("%s stream id has changed from:%d to:%d, recreating decoder.",
           TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
           info->GetID());
       decoder.mInfo = info;
       decoder.mLastStreamSourceID = info->GetID();
@@ -1089,16 +1088,22 @@ MediaFormatReader::Update(TrackType aTra
   auto& decoder = GetDecoderData(aTrack);
   decoder.mUpdateScheduled = false;
 
   if (UpdateReceivedNewData(aTrack)) {
     LOGV("Nothing more to do");
     return;
   }
 
+  if (!decoder.HasPromise() && decoder.mWaitingForData) {
+    // Nothing more we can do at present.
+    LOGV("Still waiting for data.");
+    return;
+  }
+
   // Record number of frames decoded and parsed. Automatically update the
   // stats counters using the AutoNotifyDecoded stack-based class.
   AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
 
   if (aTrack == TrackInfo::kVideoTrack) {
     uint64_t delta =
       decoder.mNumSamplesOutput - mLastReportedNumDecodedFrames;
     a.mDecoded = static_cast<uint32_t>(delta);
@@ -1133,42 +1138,43 @@ MediaFormatReader::Update(TrackType aTra
       decoder.mDrainComplete = false;
       decoder.mDraining = false;
       if (decoder.mError) {
         LOG("Decoding Error");
         decoder.RejectPromise(DECODE_ERROR, __func__);
         return;
       } else if (decoder.mDemuxEOS) {
         decoder.RejectPromise(END_OF_STREAM, __func__);
-      } else if (decoder.mWaitingForData) {
-        LOG("Waiting For Data");
-        decoder.RejectPromise(WAITING_FOR_DATA, __func__);
       }
     } else if (decoder.mError && !decoder.mDecoder) {
       decoder.RejectPromise(DECODE_ERROR, __func__);
       return;
+    } else if (decoder.mWaitingForData) {
+      LOG("Waiting For Data");
+      decoder.RejectPromise(WAITING_FOR_DATA, __func__);
+      return;
     }
   }
 
-  if (decoder.mError || decoder.mDemuxEOS || decoder.mWaitingForData) {
+  if (decoder.mNeedDraining) {
     DrainDecoder(aTrack);
     return;
   }
 
   if (!NeedInput(decoder)) {
     LOGV("No need for additional input");
     return;
   }
 
   needInput = true;
 
-  LOGV("Update(%s) ni=%d no=%d ie=%d, in:%d out:%d qs=%d sid:%d",
+  LOGV("Update(%s) ni=%d no=%d ie=%d, in:%llu out:%llu qs=%u sid:%u",
        TrackTypeToStr(aTrack), needInput, needOutput, decoder.mInputExhausted,
        decoder.mNumSamplesInput, decoder.mNumSamplesOutput,
-       size_t(decoder.mSizeOfQueue), decoder.mLastStreamSourceID);
+       uint32_t(size_t(decoder.mSizeOfQueue)), decoder.mLastStreamSourceID);
 
   // Demux samples if we don't have some.
   RequestDemuxSamples(aTrack);
   // Decode all pending demuxed samples.
   DecodeDemuxedSamples(aTrack, a);
 }
 
 void
--- a/dom/media/MediaMetadataManager.h
+++ b/dom/media/MediaMetadataManager.h
@@ -1,68 +1,74 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(MediaMetadataManager_h__)
 #define MediaMetadataManager_h__
-#include "VideoUtils.h"
+
 #include "mozilla/LinkedList.h"
+
+#include "nsAutoPtr.h"
 #include "AbstractMediaDecoder.h"
-#include "nsAutoPtr.h"
+#include "TimeUnits.h"
+#include "VideoUtils.h"
 
 namespace mozilla {
 
-  // A struct that contains the metadata of a media, and the time at which those
-  // metadata should start to be reported.
-  class TimedMetadata : public LinkedListElement<TimedMetadata> {
-    public:
-      // The time, in microseconds, at which those metadata should be available.
-      int64_t mPublishTime;
-      // The metadata. The ownership is transfered to the element when dispatching to
-      // the main threads.
-      nsAutoPtr<MetadataTags> mTags;
-      // The media info, including the info of audio tracks and video tracks.
-      // The ownership is transfered to MediaDecoder when dispatching to the
-      // main thread.
-      nsAutoPtr<MediaInfo> mInfo;
-  };
+// A struct that contains the metadata of a media, and the time at which those
+// metadata should start to be reported.
+class TimedMetadata : public LinkedListElement<TimedMetadata> {
+public:
+  // The time, in microseconds, at which those metadata should be available.
+  media::TimeUnit mPublishTime;
+  // The metadata. The ownership is transfered to the element when dispatching to
+  // the main threads.
+  nsAutoPtr<MetadataTags> mTags;
+  // The media info, including the info of audio tracks and video tracks.
+  // The ownership is transfered to MediaDecoder when dispatching to the
+  // main thread.
+  nsAutoPtr<MediaInfo> mInfo;
+};
+
+// This class encapsulate the logic to give the metadata from the reader to
+// the content, at the right time.
+class MediaMetadataManager
+{
+public:
+  ~MediaMetadataManager() {
+    TimedMetadata* element;
+    while((element = mMetadataQueue.popFirst()) != nullptr) {
+      delete element;
+    }
+  }
 
-  // This class encapsulate the logic to give the metadata from the reader to
-  // the content, at the right time.
-  class MediaMetadataManager
-  {
-    public:
-      ~MediaMetadataManager() {
-        TimedMetadata* element;
-        while((element = mMetadataQueue.popFirst()) != nullptr) {
-          delete element;
-        }
-      }
-      void QueueMetadata(TimedMetadata* aMetadata) {
-        mMetadataQueue.insertBack(aMetadata);
-      }
+  void QueueMetadata(TimedMetadata* aMetadata) {
+    mMetadataQueue.insertBack(aMetadata);
+  }
+
+  void DispatchMetadataIfNeeded(AbstractMediaDecoder* aDecoder, const media::TimeUnit& aCurrentTime) {
+    TimedMetadata* metadata = mMetadataQueue.getFirst();
+    while (metadata && aCurrentTime >= metadata->mPublishTime) {
+      // Remove all media tracks from the list first.
+      nsCOMPtr<nsIRunnable> removeTracksEvent =
+        new RemoveMediaTracksEventRunner(aDecoder);
+      NS_DispatchToMainThread(removeTracksEvent);
 
-      void DispatchMetadataIfNeeded(AbstractMediaDecoder* aDecoder, double aCurrentTime) {
-        TimedMetadata* metadata = mMetadataQueue.getFirst();
-        while (metadata && aCurrentTime >= static_cast<double>(metadata->mPublishTime) / USECS_PER_S) {
-          // Remove all media tracks from the list first.
-          nsCOMPtr<nsIRunnable> removeTracksEvent =
-            new RemoveMediaTracksEventRunner(aDecoder);
-          NS_DispatchToMainThread(removeTracksEvent);
+      nsCOMPtr<nsIRunnable> metadataUpdatedEvent =
+        new MetadataUpdatedEventRunner(aDecoder,
+                                       metadata->mInfo,
+                                       metadata->mTags);
+      NS_DispatchToMainThread(metadataUpdatedEvent);
+      delete mMetadataQueue.popFirst();
+      metadata = mMetadataQueue.getFirst();
+    }
+  }
 
-          nsCOMPtr<nsIRunnable> metadataUpdatedEvent =
-            new MetadataUpdatedEventRunner(aDecoder,
-                                           metadata->mInfo,
-                                           metadata->mTags);
-          NS_DispatchToMainThread(metadataUpdatedEvent);
-          delete mMetadataQueue.popFirst();
-          metadata = mMetadataQueue.getFirst();
-        }
-      }
-    protected:
-      LinkedList<TimedMetadata> mMetadataQueue;
-  };
+protected:
+  LinkedList<TimedMetadata> mMetadataQueue;
+};
+
 } // namespace mozilla
 
 #endif
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -1025,22 +1025,17 @@ void
 MediaRecorder::DispatchSimpleEvent(const nsAString & aStr)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to create the error event!!!");
-    return;
-  }
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
   rv = event->InitEvent(aStr, false, false);
 
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to init the error event!!!");
     return;
   }
 
   event->SetTrusted(true);
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -1109,17 +1109,16 @@ bool
 ChannelMediaResource::IsSuspendedByCache()
 {
   return mCacheStream.AreAllStreamsForResourceSuspended();
 }
 
 bool
 ChannelMediaResource::IsSuspended()
 {
-  MutexAutoLock lock(mLock);
   return mSuspendCount > 0;
 }
 
 void
 ChannelMediaResource::SetReadMode(MediaCacheStream::ReadMode aMode)
 {
   mCacheStream.SetReadMode(aMode);
 }
--- a/dom/media/MediaResource.h
+++ b/dom/media/MediaResource.h
@@ -11,16 +11,17 @@
 #include "nsIURI.h"
 #include "nsISeekableStream.h"
 #include "nsIStreamingProtocolController.h"
 #include "nsIStreamListener.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "MediaCache.h"
 #include "MediaData.h"
+#include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/TimeStamp.h"
 #include "nsThreadUtils.h"
 #include <algorithm>
 
 // For HTTP seeking, if number of bytes needing to be
 // seeked forward is less than this value then a read is
 // done rather than a byte range request.
@@ -773,17 +774,17 @@ protected:
   void PossiblyResume();
 
   // Main thread access only
   int64_t            mOffset;
   nsRefPtr<Listener> mListener;
   // A data received event for the decoder that has been dispatched but has
   // not yet been processed.
   nsRevocableEventPtr<nsRunnableMethod<ChannelMediaResource, void, false> > mDataReceivedEvent;
-  uint32_t           mSuspendCount;
+  Atomic<uint32_t>   mSuspendCount;
   // When this flag is set, if we get a network error we should silently
   // reopen the stream.
   bool               mReopenOnError;
   // When this flag is set, we should not report the next close of the
   // channel.
   bool               mIgnoreClose;
 
   // Any thread access
--- a/dom/media/TextTrackList.cpp
+++ b/dom/media/TextTrackList.cpp
@@ -155,24 +155,19 @@ nsresult
 TextTrackList::DispatchTrackEvent(nsIDOMEvent* aEvent)
 {
   return DispatchTrustedEvent(aEvent);
 }
 
 void
 TextTrackList::CreateAndDispatchChangeEvent()
 {
-  nsCOMPtr<nsIDOMEvent> event;
-  nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to create the error event!");
-    return;
-  }
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
-  rv = event->InitEvent(NS_LITERAL_STRING("change"), false, false);
+  nsresult rv = event->InitEvent(NS_LITERAL_STRING("change"), false, false);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to init the change event!");
     return;
   }
 
   event->SetTrusted(true);
 
   nsCOMPtr<nsIRunnable> eventRunner = new TrackEventRunner(this, event);
--- a/dom/media/mediasource/SourceBufferDecoder.cpp
+++ b/dom/media/mediasource/SourceBufferDecoder.cpp
@@ -95,17 +95,17 @@ SourceBufferDecoder::MetadataLoaded(nsAu
 void
 SourceBufferDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
                                       MediaDecoderEventVisibility aEventVisibility)
 {
   MSE_DEBUG("UNIMPLEMENTED");
 }
 
 void
-SourceBufferDecoder::QueueMetadata(int64_t aTime,
+SourceBufferDecoder::QueueMetadata(const media::TimeUnit& aTime,
                                    nsAutoPtr<MediaInfo> aInfo,
                                    nsAutoPtr<MetadataTags> aTags)
 {
   MSE_DEBUG("UNIMPLEMENTED");
 }
 
 void
 SourceBufferDecoder::RemoveMediaTracks()
--- a/dom/media/mediasource/SourceBufferDecoder.h
+++ b/dom/media/mediasource/SourceBufferDecoder.h
@@ -46,17 +46,17 @@ public:
                               MediaDecoderEventVisibility aEventVisibility) final override;
   virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
                                 MediaDecoderEventVisibility aEventVisibility) final override;
   virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) final override;
   virtual void NotifyDataArrived(uint32_t aLength, int64_t aOffset, bool aThrottleUpdates) final override;
   virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, uint32_t aDropped) final override;
   virtual void NotifyWaitingForResourcesStatusChanged() final override;
   virtual void OnReadMetadataCompleted() final override;
-  virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) final override;
+  virtual void QueueMetadata(const media::TimeUnit& aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) final override;
   virtual void RemoveMediaTracks() final override;
   virtual void SetMediaSeekable(bool aMediaSeekable) final override;
   virtual bool HasInitializationData() final override;
 
   // SourceBufferResource specific interface below.
   int64_t GetTimestampOffset() const { return mTimestampOffset; }
   void SetTimestampOffset(int64_t aOffset)  { mTimestampOffset = aOffset; }
 
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -1615,18 +1615,16 @@ TrackBuffersManager::RemoveFrames(const 
                    TimeUnit::FromMicroseconds(sample->GetEndTime()));
     removedIntervals += sampleInterval;
     if (sample->mDuration > maxSampleDuration) {
       maxSampleDuration = sample->mDuration;
     }
     aTrackData.mSizeBuffer -= sample->ComputedSizeOfIncludingThis();
   }
 
-  removedIntervals.SetFuzz(TimeUnit::FromMicroseconds(maxSampleDuration));
-
   MSE_DEBUG("Removing frames from:%u (frames:%u) ([%f, %f))",
             firstRemovedIndex.ref(),
             lastRemovedIndex - firstRemovedIndex.ref() + 1,
             removedIntervals.GetStart().ToSeconds(),
             removedIntervals.GetEnd().ToSeconds());
 
   if (aTrackData.mNextGetSampleIndex.isSome()) {
     if (aTrackData.mNextGetSampleIndex.ref() >= firstRemovedIndex.ref() &&
--- a/dom/media/mediasource/test/mochitest.ini
+++ b/dom/media/mediasource/test/mochitest.ini
@@ -35,28 +35,28 @@ support-files =
   bipbop/bipbop13.m4s^headers^ bipbop/bipbop_video13.m4s^headers^
 
 [test_BufferedSeek.html]
 [test_BufferedSeek_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_BufferingWait.html]
 skip-if = true # bug 1190776
 [test_BufferingWait_mp4.html]
-skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
+skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138
 [test_EndOfStream.html]
 skip-if = (true || toolkit == 'android' || buildapp == 'mulet') #timeout android/mulet only bug 1101187 and bug 1182946
 [test_EndOfStream_mp4.html]
 skip-if = (toolkit == 'android' || buildapp == 'mulet') || ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_DurationUpdated.html]
 [test_DurationUpdated_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_FrameSelection.html]
 [test_HaveMetadataUnbufferedSeek.html]
 [test_HaveMetadataUnbufferedSeek_mp4.html]
-skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
+skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138
 [test_LoadedMetadataFired.html]
 [test_LoadedMetadataFired_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_MediaSource.html]
 [test_MediaSource_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_MediaSource_disabled.html]
 [test_MultipleInitSegments.html]
@@ -84,15 +84,16 @@ skip-if = ((os == "win" && os_version ==
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_SplitAppend.html]
 [test_SplitAppend_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_TimestampOffset_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
 [test_TruncatedDuration.html]
 [test_TruncatedDuration_mp4.html]
-skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
+skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138
 [test_WaitingOnMissingData.html]
 skip-if = true # Disabled due to bug 1124493 and friends. WebM MSE is deprioritized.
 [test_WaitingOnMissingData_mp4.html]
-skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
+skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138
 [test_WaitingToEndedTransition_mp4.html]
-skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
+skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138
+
--- a/dom/media/mediasource/test/test_BufferingWait_mp4.html
+++ b/dom/media/mediasource/test/test_BufferingWait_mp4.html
@@ -36,24 +36,28 @@ runWithMSE(function(ms, v) {
     sb.addEventListener('error', (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
     fetchAndLoad(sb, 'bipbop/bipbop', ['init'], '.mp4')
     .then(fetchAndLoad.bind(null, sb, 'bipbop/bipbop', ['1'], '.m4s'))
     .then(fetchAndLoad.bind(null, sb, 'bipbop/bipbop', ['2'], '.m4s'))
     /* Note - Missing |bipbop3| segment here corresponding to (1.62, 2.41] */
     /* Note - Missing |bipbop4| segment here corresponding to (2.41, 3.20]  */
     .then(fetchAndLoad.bind(null, sb, 'bipbop/bipbop', ['5'], '.m4s'))
     .then(function() {
-        var promise = waitUntilTime(1.4);
+        // Some decoders (Windows in particular) may keep up to 25 frames queued
+        // before returning a sample. 0.7 is 1.62s - 25 * 0.03333
+        var promise = waitUntilTime(0.7);
         info("Playing video. It should play for a bit, then fire 'waiting'");
         v.play();
         return promise;
       }).then(function() {
         window.firstStop = Date.now();
         fetchAndLoad(sb, 'bipbop/bipbop', ['3'], '.m4s');
-        return waitUntilTime(2.2);
+        // Some decoders (Windows in particular) may keep up to 25 frames queued
+        // before returning a sample. 1.5 is 2.41s - 25 * 0.03333
+        return waitUntilTime(1.5);
       }).then(function() {
         var waitDuration = (Date.now() - window.firstStop) / 1000;
         ok(waitDuration < 15, "Should not spend an inordinate amount of time buffering: " + waitDuration);
         once(v, 'ended', SimpleTest.finish.bind(SimpleTest));
         return fetchAndLoad(sb, 'bipbop/bipbop', ['4'], '.m4s');
       }).then(function() {
         ms.endOfStream();
       });;
--- a/dom/media/mediasource/test/test_WaitingOnMissingData_mp4.html
+++ b/dom/media/mediasource/test/test_WaitingOnMissingData_mp4.html
@@ -35,18 +35,19 @@ runWithMSE(function(ms, el) {
       ok(true, "Video playing. It should play for a bit, then fire 'waiting'");
       var p = once(el, 'waiting');
       el.play();
       return p;
     }).then(function() {
       // currentTime is based on the current video frame, so if the audio ends just before
       // the next video frame, currentTime can be up to 1 frame's worth earlier than
       // min(audioEnd, videoEnd).
+      // Some decoders (Windows in particular) may keep up to 25 frames queued.
       isfuzzy(el.currentTime, Math.min(audiosb.buffered.end(0), videosb.buffered.end(0)) - 1/60,
-              1/30, "Got a waiting event at " + el.currentTime);
+              25 * 1/30, "Got a waiting event at " + el.currentTime);
       info("Loading more data");
       var p = once(el, 'ended');
       var loads = Promise.all([fetchAndLoad(audiosb, 'bipbop/bipbop_audio', [5], '.m4s'),
                                fetchAndLoad(videosb, 'bipbop/bipbop_video', [6], '.m4s')]);
       loads.then(() => ms.endOfStream());
       return p;
     }).then(function() {
       // These fuzz factors are bigger than they should be. We should investigate
--- a/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html
+++ b/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html
@@ -33,18 +33,19 @@ runWithMSE(function(ms, el) {
       ok(true, "Video playing. It should play for a bit, then fire 'waiting'");
       var p = once(el, 'waiting');
       el.play();
       return p;
     }).then(function() {
       // currentTime is based on the current video frame, so if the audio ends just before
       // the next video frame, currentTime can be up to 1 frame's worth earlier than
       // min(audioEnd, videoEnd).
+      // Some decoders (Windows in particular) may keep up to 25 frames queued.
       isfuzzy(el.currentTime, Math.min(audiosb.buffered.end(0), videosb.buffered.end(0)) - 1/60,
-              1/30, "Got a waiting event at " + el.currentTime);
+              25 * 1/30, "Got a waiting event at " + el.currentTime);
     }).then(function() {
       var p = once(el, 'ended');
       ms.endOfStream();
       return p;
     }).then(function() {
       is(el.duration, 4.005, "Video has correct duration: " + el.duration);
       is(el.currentTime, el.duration, "Video has correct currentTime.");
       SimpleTest.finish();
--- a/dom/media/ogg/OggReader.cpp
+++ b/dom/media/ogg/OggReader.cpp
@@ -809,21 +809,20 @@ bool OggReader::ReadOggChain()
 
     chained = true;
     tags = newOpusState->GetTags();
   }
 
   if (chained) {
     SetChained(true);
     {
-      nsAutoPtr<MediaInfo> info(new MediaInfo());
-      *info = mInfo;
+      nsAutoPtr<MediaInfo> info(new MediaInfo(mInfo));
       ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-      mDecoder->QueueMetadata((mDecodedAudioFrames * USECS_PER_S) / mInfo.mAudio.mRate,
-                              info, tags);
+      auto t = mDecodedAudioFrames * USECS_PER_S / mInfo.mAudio.mRate;
+      mDecoder->QueueMetadata(media::TimeUnit::FromMicroseconds(t), info, tags);
     }
     return true;
   }
 
   return false;
 }
 
 nsresult OggReader::DecodeTheora(ogg_packet* aPacket, int64_t aTimeThreshold)
--- a/dom/media/platforms/apple/AppleUtils.h
+++ b/dom/media/platforms/apple/AppleUtils.h
@@ -38,11 +38,61 @@ public:
   }
 
 private:
   // Copy operator isn't supported and is not implemented.
   AutoCFRelease<T>& operator=(const AutoCFRelease<T>&);
   T mRef;
 };
 
+// CFRefPtr: A CoreFoundation smart pointer.
+template <class T>
+class CFRefPtr {
+public:
+  explicit CFRefPtr(T aRef)
+    : mRef(aRef)
+  {
+    if (mRef) {
+      CFRetain(mRef);
+    }
+  }
+  // Copy constructor.
+  CFRefPtr(const CFRefPtr<T>& aCFRefPtr)
+    : mRef(aCFRefPtr.mRef)
+  {
+    if (mRef) {
+      CFRetain(mRef);
+    }
+  }
+  // Copy operator
+  CFRefPtr<T>& operator=(const CFRefPtr<T>& aCFRefPtr)
+  {
+    if (mRef == aCFRefPtr.mRef) {
+      return;
+    }
+    if (mRef) {
+      CFRelease(mRef);
+    }
+    mRef = aCFRefPtr.mRef;
+    if (mRef) {
+      CFRetain(mRef);
+    }
+    return *this;
+  }
+  ~CFRefPtr()
+  {
+    if (mRef) {
+      CFRelease(mRef);
+    }
+  }
+  // Return the wrapped ref so it can be used as an in parameter.
+  operator T()
+  {
+    return mRef;
+  }
+
+private:
+  T mRef;
+};
+
 } // namespace mozilla
 
 #endif // mozilla_AppleUtils_h
--- a/dom/media/platforms/apple/AppleVDADecoder.cpp
+++ b/dom/media/platforms/apple/AppleVDADecoder.cpp
@@ -35,18 +35,22 @@ AppleVDADecoder::AppleVDADecoder(const V
                                layers::ImageContainer* aImageContainer)
   : mTaskQueue(aVideoTaskQueue)
   , mCallback(aCallback)
   , mImageContainer(aImageContainer)
   , mPictureWidth(aConfig.mImage.width)
   , mPictureHeight(aConfig.mImage.height)
   , mDisplayWidth(aConfig.mDisplay.width)
   , mDisplayHeight(aConfig.mDisplay.height)
+  , mInputIncoming(0)
+  , mIsShutDown(false)
   , mUseSoftwareImages(false)
   , mIs106(!nsCocoaFeatures::OnLionOrLater())
+  , mMonitor("AppleVideoDecoder")
+  , mIsFlushing(false)
   , mDecoder(nullptr)
 {
   MOZ_COUNT_CTOR(AppleVDADecoder);
   // TODO: Verify aConfig.mime_type.
 
   mExtraData = aConfig.mExtraData;
   mMaxRefFrames = 4;
   // Retrieve video dimensions from H264 SPS NAL.
@@ -77,69 +81,116 @@ nsRefPtr<MediaDataDecoder::InitPromise>
 AppleVDADecoder::Init()
 {
   return InitPromise::CreateAndResolve(TrackType::kVideoTrack, __func__);
 }
 
 nsresult
 AppleVDADecoder::Shutdown()
 {
+  MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown);
+  mIsShutDown = true;
+  if (mTaskQueue) {
+    nsCOMPtr<nsIRunnable> runnable =
+      NS_NewRunnableMethod(this, &AppleVDADecoder::ProcessShutdown);
+    mTaskQueue->Dispatch(runnable.forget());
+  } else {
+    ProcessShutdown();
+  }
+  return NS_OK;
+}
+
+void
+AppleVDADecoder::ProcessShutdown()
+{
   if (mDecoder) {
     LOG("%s: cleaning up decoder %p", __func__, mDecoder);
     VDADecoderDestroy(mDecoder);
     mDecoder = nullptr;
   }
-  return NS_OK;
 }
 
 nsresult
 AppleVDADecoder::Input(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+
   LOG("mp4 input sample %p pts %lld duration %lld us%s %d bytes",
       aSample,
       aSample->mTime,
       aSample->mDuration,
       aSample->mKeyframe ? " keyframe" : "",
       aSample->Size());
 
+  mInputIncoming++;
+
   nsCOMPtr<nsIRunnable> runnable =
       NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
           this,
           &AppleVDADecoder::SubmitFrame,
           nsRefPtr<MediaRawData>(aSample));
   mTaskQueue->Dispatch(runnable.forget());
   return NS_OK;
 }
 
 nsresult
 AppleVDADecoder::Flush()
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+  mIsFlushing = true;
   mTaskQueue->Flush();
+  nsCOMPtr<nsIRunnable> runnable =
+    NS_NewRunnableMethod(this, &AppleVDADecoder::ProcessFlush);
+  MonitorAutoLock mon(mMonitor);
+  mTaskQueue->Dispatch(runnable.forget());
+  while (mIsFlushing) {
+    mon.Wait();
+  }
+  mInputIncoming = 0;
+  return NS_OK;
+}
+
+nsresult
+AppleVDADecoder::Drain()
+{
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+  nsCOMPtr<nsIRunnable> runnable =
+    NS_NewRunnableMethod(this, &AppleVDADecoder::ProcessDrain);
+  mTaskQueue->Dispatch(runnable.forget());
+  return NS_OK;
+}
+
+void
+AppleVDADecoder::ProcessFlush()
+{
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
   OSStatus rv = VDADecoderFlush(mDecoder, 0 /*dont emit*/);
   if (rv != noErr) {
     LOG("AppleVDADecoder::Flush failed waiting for platform decoder "
         "with error:%d.", rv);
   }
   ClearReorderedFrames();
-
-  return NS_OK;
+  MonitorAutoLock mon(mMonitor);
+  mIsFlushing = false;
+  mon.NotifyAll();
 }
 
-nsresult
-AppleVDADecoder::Drain()
+void
+AppleVDADecoder::ProcessDrain()
 {
-  mTaskQueue->AwaitIdle();
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
   OSStatus rv = VDADecoderFlush(mDecoder, kVDADecoderFlush_EmitFrames);
   if (rv != noErr) {
     LOG("AppleVDADecoder::Drain failed waiting for platform decoder "
         "with error:%d.", rv);
   }
   DrainReorderedFrames();
   mCallback->DrainComplete();
-  return NS_OK;
 }
 
 //
 // Implementation details.
 //
 
 // Callback passed to the VideoToolbox decoder for returning data.
 // This needs to be static because the API takes a C-style pair of
@@ -194,27 +245,29 @@ PlatformCallback(void* decompressionOutp
   char is_sync_point;
 
   CFNumberGetValue(ptsref, kCFNumberSInt64Type, &pts);
   CFNumberGetValue(dtsref, kCFNumberSInt64Type, &dts);
   CFNumberGetValue(durref, kCFNumberSInt64Type, &duration);
   CFNumberGetValue(boref, kCFNumberSInt64Type, &byte_offset);
   CFNumberGetValue(kfref, kCFNumberSInt8Type, &is_sync_point);
 
-  nsAutoPtr<AppleVDADecoder::AppleFrameRef> frameRef(
-    new AppleVDADecoder::AppleFrameRef(
+  AppleVDADecoder::AppleFrameRef frameRef(
       media::TimeUnit::FromMicroseconds(dts),
       media::TimeUnit::FromMicroseconds(pts),
       media::TimeUnit::FromMicroseconds(duration),
       byte_offset,
-      is_sync_point == 1));
+      is_sync_point == 1);
 
   // Forward the data back to an object method which can access
-  // the correct MP4Reader callback.
-  decoder->OutputFrame(image, frameRef);
+  // the correct reader's callback.
+  nsCOMPtr<nsIRunnable> task =
+    NS_NewRunnableMethodWithArgs<CFRefPtr<CVPixelBufferRef>, AppleVDADecoder::AppleFrameRef>(
+      decoder, &AppleVDADecoder::OutputFrame, image, frameRef);
+  decoder->DispatchOutputTask(task.forget());
 }
 
 AppleVDADecoder::AppleFrameRef*
 AppleVDADecoder::CreateAppleFrameRef(const MediaRawData* aSample)
 {
   MOZ_ASSERT(aSample);
   return new AppleFrameRef(*aSample);
 }
@@ -232,25 +285,32 @@ AppleVDADecoder::ClearReorderedFrames()
 {
   while (!mReorderQueue.IsEmpty()) {
     mReorderQueue.Pop();
   }
 }
 
 // Copy and return a decoded frame.
 nsresult
-AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
-                             nsAutoPtr<AppleVDADecoder::AppleFrameRef> aFrameRef)
+AppleVDADecoder::OutputFrame(CFRefPtr<CVPixelBufferRef> aImage,
+                             AppleVDADecoder::AppleFrameRef aFrameRef)
 {
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
+  if (mIsFlushing) {
+    // We are in the process of flushing; ignore frame.
+    return NS_OK;
+  }
+
   LOG("mp4 output frame %lld dts %lld pts %lld duration %lld us%s",
-      aFrameRef->byte_offset,
-      aFrameRef->decode_timestamp.ToMicroseconds(),
-      aFrameRef->composition_timestamp.ToMicroseconds(),
-      aFrameRef->duration.ToMicroseconds(),
-      aFrameRef->is_sync_point ? " keyframe" : ""
+      aFrameRef.byte_offset,
+      aFrameRef.decode_timestamp.ToMicroseconds(),
+      aFrameRef.composition_timestamp.ToMicroseconds(),
+      aFrameRef.duration.ToMicroseconds(),
+      aFrameRef.is_sync_point ? " keyframe" : ""
   );
 
   // Where our resulting image will end up.
   nsRefPtr<VideoData> data;
   // Bounds.
   VideoInfo info;
   info.mDisplay = nsIntSize(mDisplayWidth, mDisplayHeight);
   gfx::IntRect visible = gfx::IntRect(0,
@@ -298,22 +358,22 @@ AppleVDADecoder::OutputFrame(CVPixelBuff
     buffer.mPlanes[2].mOffset = 1;
     buffer.mPlanes[2].mSkip = 1;
 
     // Copy the image data into our own format.
     data =
       VideoData::Create(info,
                         mImageContainer,
                         nullptr,
-                        aFrameRef->byte_offset,
-                        aFrameRef->composition_timestamp.ToMicroseconds(),
-                        aFrameRef->duration.ToMicroseconds(),
+                        aFrameRef.byte_offset,
+                        aFrameRef.composition_timestamp.ToMicroseconds(),
+                        aFrameRef.duration.ToMicroseconds(),
                         buffer,
-                        aFrameRef->is_sync_point,
-                        aFrameRef->decode_timestamp.ToMicroseconds(),
+                        aFrameRef.is_sync_point,
+                        aFrameRef.decode_timestamp.ToMicroseconds(),
                         visible);
     // Unlock the returned image data.
     CVPixelBufferUnlockBaseAddress(aImage, kCVPixelBufferLock_ReadOnly);
   } else {
     IOSurfacePtr surface = MacIOSurfaceLib::CVPixelBufferGetIOSurface(aImage);
     MOZ_ASSERT(surface, "Decoder didn't return an IOSurface backed buffer");
 
     nsRefPtr<MacIOSurface> macSurface = new MacIOSurface(surface);
@@ -322,22 +382,22 @@ AppleVDADecoder::OutputFrame(CVPixelBuff
       mImageContainer->CreateImage(ImageFormat::MAC_IOSURFACE);
     layers::MacIOSurfaceImage* videoImage =
       static_cast<layers::MacIOSurfaceImage*>(image.get());
     videoImage->SetSurface(macSurface);
 
     data =
       VideoData::CreateFromImage(info,
                                  mImageContainer,
-                                 aFrameRef->byte_offset,
-                                 aFrameRef->composition_timestamp.ToMicroseconds(),
-                                 aFrameRef->duration.ToMicroseconds(),
+                                 aFrameRef.byte_offset,
+                                 aFrameRef.composition_timestamp.ToMicroseconds(),
+                                 aFrameRef.duration.ToMicroseconds(),
                                  image.forget(),
-                                 aFrameRef->is_sync_point,
-                                 aFrameRef->decode_timestamp.ToMicroseconds(),
+                                 aFrameRef.is_sync_point,
+                                 aFrameRef.decode_timestamp.ToMicroseconds(),
                                  visible);
   }
 
   if (!data) {
     NS_ERROR("Couldn't create VideoData for frame");
     mCallback->Error();
     return NS_ERROR_FAILURE;
   }
@@ -352,16 +412,20 @@ AppleVDADecoder::OutputFrame(CVPixelBuff
       static_cast<unsigned long long>(mReorderQueue.Length()));
 
   return NS_OK;
 }
 
 nsresult
 AppleVDADecoder::SubmitFrame(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
+  mInputIncoming--;
+
   AutoCFRelease<CFDataRef> block =
     CFDataCreate(kCFAllocatorDefault, aSample->Data(), aSample->Size());
   if (!block) {
     NS_ERROR("Couldn't create CFData");
     return NS_ERROR_FAILURE;
   }
 
   AutoCFRelease<CFNumberRef> pts =
@@ -425,17 +489,17 @@ AppleVDADecoder::SubmitFrame(MediaRawDat
     // This dictionary can contain client provided information associated with
     // the frame being decoded, for example presentation time.
     // The CFDictionaryRef will be retained by the framework.
     // In 10.6, it is released one too many. So retain it.
     CFRetain(frameInfo);
   }
 
   // Ask for more data.
-  if (mTaskQueue->IsEmpty()) {
+  if (!mInputIncoming) {
     LOG("AppleVDADecoder task queue empty; requesting more data");
     mCallback->InputExhausted();
   }
 
   return NS_OK;
 }
 
 nsresult
--- a/dom/media/platforms/apple/AppleVDADecoder.h
+++ b/dom/media/platforms/apple/AppleVDADecoder.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_AppleVDADecoder_h
 #define mozilla_AppleVDADecoder_h
 
 #include "PlatformDecoderModule.h"
+#include "mozilla/Atomics.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "MP4Decoder.h"
 #include "nsIThread.h"
 #include "ReorderQueue.h"
 #include "TimeUnits.h"
 
 #include "VideoDecodeAcceleration/VDADecoder.h"
 
@@ -75,45 +76,70 @@ public:
   virtual nsresult Flush() override;
   virtual nsresult Drain() override;
   virtual nsresult Shutdown() override;
   virtual bool IsHardwareAccelerated() const override
   {
     return true;
   }
 
-  nsresult OutputFrame(CVPixelBufferRef aImage,
-                       nsAutoPtr<AppleFrameRef> aFrameRef);
+  void DispatchOutputTask(already_AddRefed<nsIRunnable> aTask)
+  {
+    nsCOMPtr<nsIRunnable> task = aTask;
+    if (mIsShutDown || mIsFlushing) {
+      return;
+    }
+    mTaskQueue->Dispatch(task.forget());
+  }
 
-  // Method to set up the decompression session.
-  nsresult InitializeSession();
+  nsresult OutputFrame(CFRefPtr<CVPixelBufferRef> aImage,
+                       AppleFrameRef aFrameRef);
 
- protected:
+protected:
+  // Flush and Drain operation, always run
+  virtual void ProcessFlush();
+  virtual void ProcessDrain();
+  virtual void ProcessShutdown();
+
   AppleFrameRef* CreateAppleFrameRef(const MediaRawData* aSample);
   void DrainReorderedFrames();
   void ClearReorderedFrames();
   CFDictionaryRef CreateOutputConfiguration();
-  nsresult InitDecoder();
 
   nsRefPtr<MediaByteBuffer> mExtraData;
   nsRefPtr<FlushableTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
   nsRefPtr<layers::ImageContainer> mImageContainer;
   ReorderQueue mReorderQueue;
   uint32_t mPictureWidth;
   uint32_t mPictureHeight;
   uint32_t mDisplayWidth;
   uint32_t mDisplayHeight;
   uint32_t mMaxRefFrames;
+  // Increased when Input is called, and decreased when ProcessFrame runs.
+  // Reaching 0 indicates that there's no pending Input.
+  Atomic<uint32_t> mInputIncoming;
+  Atomic<bool> mIsShutDown;
+
   bool mUseSoftwareImages;
   bool mIs106;
 
+  // For wait on mIsFlushing during Shutdown() process.
+  Monitor mMonitor;
+  // Set on reader/decode thread calling Flush() to indicate that output is
+  // not required and so input samples on mTaskQueue need not be processed.
+  // Cleared on mTaskQueue in ProcessDrain().
+  Atomic<bool> mIsFlushing;
+
 private:
   VDADecoder mDecoder;
 
+  // Method to set up the decompression session.
+  nsresult InitializeSession();
+
   // Method to pass a frame to VideoToolbox for decoding.
   nsresult SubmitFrame(MediaRawData* aSample);
   CFDictionaryRef CreateDecoderSpecification();
 };
 
 } // namespace mozilla
 
 #endif // mozilla_AppleVDADecoder_h
--- a/dom/media/platforms/apple/AppleVTDecoder.cpp
+++ b/dom/media/platforms/apple/AppleVTDecoder.cpp
@@ -58,36 +58,37 @@ AppleVTDecoder::Init()
 
   if (NS_SUCCEEDED(rv)) {
     return InitPromise::CreateAndResolve(TrackType::kVideoTrack, __func__);
   }
 
   return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
 }
 
-nsresult
-AppleVTDecoder::Shutdown()
+void
+AppleVTDecoder::ProcessShutdown()
 {
   if (mSession) {
     LOG("%s: cleaning up session %p", __func__, mSession);
     VTDecompressionSessionInvalidate(mSession);
     CFRelease(mSession);
     mSession = nullptr;
   }
   if (mFormat) {
     LOG("%s: releasing format %p", __func__, mFormat);
     CFRelease(mFormat);
     mFormat = nullptr;
   }
-  return NS_OK;
 }
 
 nsresult
 AppleVTDecoder::Input(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+
   LOG("mp4 input sample %p pts %lld duration %lld us%s %d bytes",
       aSample,
       aSample->mTime,
       aSample->mDuration,
       aSample->mKeyframe ? " keyframe" : "",
       aSample->Size());
 
 #ifdef LOG_MEDIA_SHA1
@@ -97,51 +98,51 @@ AppleVTDecoder::Input(MediaRawData* aSam
   hash.finish(digest_buf);
   nsAutoCString digest;
   for (size_t i = 0; i < sizeof(digest_buf); i++) {
     digest.AppendPrintf("%02x", digest_buf[i]);
   }
   LOG("    sha1 %s", digest.get());
 #endif // LOG_MEDIA_SHA1
 
+  mInputIncoming++;
+
   nsCOMPtr<nsIRunnable> runnable =
       NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
-          this,
-          &AppleVTDecoder::SubmitFrame,
-          nsRefPtr<MediaRawData>(aSample));
+          this, &AppleVTDecoder::SubmitFrame, aSample);
   mTaskQueue->Dispatch(runnable.forget());
   return NS_OK;
 }
 
-nsresult
-AppleVTDecoder::Flush()
+void
+AppleVTDecoder::ProcessFlush()
 {
-  mTaskQueue->Flush();
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   nsresult rv = WaitForAsynchronousFrames();
   if (NS_FAILED(rv)) {
     LOG("AppleVTDecoder::Flush failed waiting for platform decoder "
         "with error:%d.", rv);
   }
   ClearReorderedFrames();
-
-  return rv;
+  MonitorAutoLock mon(mMonitor);
+  mIsFlushing = false;
+  mon.NotifyAll();
 }
 
-nsresult
-AppleVTDecoder::Drain()
+void
+AppleVTDecoder::ProcessDrain()
 {
-  mTaskQueue->AwaitIdle();
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   nsresult rv = WaitForAsynchronousFrames();
   if (NS_FAILED(rv)) {
     LOG("AppleVTDecoder::Drain failed waiting for platform decoder "
         "with error:%d.", rv);
   }
   DrainReorderedFrames();
   mCallback->DrainComplete();
-  return NS_OK;
 }
 
 //
 // Implementation details.
 //
 
 // Callback passed to the VideoToolbox decoder for returning data.
 // This needs to be static because the API takes a C-style pair of
@@ -169,19 +170,20 @@ PlatformCallback(void* decompressionOutp
     return;
   }
   if (flags & kVTDecodeInfo_FrameDropped) {
     NS_WARNING("  ...frame tagged as dropped...");
   }
   MOZ_ASSERT(CFGetTypeID(image) == CVPixelBufferGetTypeID(),
     "VideoToolbox returned an unexpected image type");
 
-  // Forward the data back to an object method which can access
-  // the correct MP4Reader callback.
-  decoder->OutputFrame(image, frameRef);
+  nsCOMPtr<nsIRunnable> task =
+    NS_NewRunnableMethodWithArgs<CFRefPtr<CVPixelBufferRef>, AppleVTDecoder::AppleFrameRef>(
+      decoder, &AppleVTDecoder::OutputFrame, image, *frameRef);
+  decoder->DispatchOutputTask(task.forget());
 }
 
 nsresult
 AppleVTDecoder::WaitForAsynchronousFrames()
 {
   OSStatus rv = VTDecompressionSessionWaitForAsynchronousFrames(mSession);
   if (rv != noErr) {
     LOG("AppleVTDecoder: Error %d waiting for asynchronous frames", rv);
@@ -203,16 +205,18 @@ TimingInfoFromSample(MediaRawData* aSamp
     CMTimeMake(aSample->mTimecode, USECS_PER_S);
 
   return timestamp;
 }
 
 nsresult
 AppleVTDecoder::SubmitFrame(MediaRawData* aSample)
 {
+  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+  mInputIncoming--;
   // For some reason this gives me a double-free error with stagefright.
   AutoCFRelease<CMBlockBufferRef> block = nullptr;
   AutoCFRelease<CMSampleBufferRef> sample = nullptr;
   VTDecodeInfoFlags infoFlags;
   OSStatus rv;
 
   // FIXME: This copies the sample data. I think we can provide
   // a custom block source which reuses the aSample buffer.
@@ -248,17 +252,17 @@ AppleVTDecoder::SubmitFrame(MediaRawData
   if (rv != noErr && !(infoFlags & kVTDecodeInfo_FrameDropped)) {
     LOG("AppleVTDecoder: Error %d VTDecompressionSessionDecodeFrame", rv);
     NS_WARNING("Couldn't pass frame to decoder");
     mCallback->Error();
     return NS_ERROR_FAILURE;
   }
 
   // Ask for more data.
-  if (mTaskQueue->IsEmpty()) {
+  if (!mInputIncoming) {
     LOG("AppleVTDecoder task queue empty; requesting more data");
     mCallback->InputExhausted();
   }
 
   return NS_OK;
 }
 
 nsresult
--- a/dom/media/platforms/apple/AppleVTDecoder.h
+++ b/dom/media/platforms/apple/AppleVTDecoder.h
@@ -17,24 +17,26 @@ class AppleVTDecoder : public AppleVDADe
 public:
   AppleVTDecoder(const VideoInfo& aConfig,
                  FlushableTaskQueue* aVideoTaskQueue,
                  MediaDataDecoderCallback* aCallback,
                  layers::ImageContainer* aImageContainer);
   virtual ~AppleVTDecoder();
   virtual nsRefPtr<InitPromise> Init() override;
   virtual nsresult Input(MediaRawData* aSample) override;
-  virtual nsresult Flush() override;
-  virtual nsresult Drain() override;
-  virtual nsresult Shutdown() override;
   virtual bool IsHardwareAccelerated() const override
   {
     return mIsHardwareAccelerated;
   }
 
+protected:
+  void ProcessFlush() override;
+  void ProcessDrain() override;
+  void ProcessShutdown() override;
+
 private:
   CMVideoFormatDescriptionRef mFormat;
   VTDecompressionSessionRef mSession;
 
   // Method to pass a frame to VideoToolbox for decoding.
   nsresult SubmitFrame(MediaRawData* aSample);
   // Method to set up the decompression session.
   nsresult InitializeSession();
--- a/dom/media/tests/mochitest/ipc/mochitest.ini
+++ b/dom/media/tests/mochitest/ipc/mochitest.ini
@@ -1,9 +1,9 @@
 [DEFAULT]
 tags=msg
 support-files =
   ipc.json
 
 skip-if = e10s
 
 [test_ipc.html]
-skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #bug 910661 # b2g(nested ipc not working) b2g-debug(debug-only failure) b2g-desktop(nested ipc not working)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || os == 'win' #bug 910661 # b2g(nested ipc not working) b2g-debug(debug-only failure) b2g-desktop(nested ipc not working)(win : Bug 1179826)
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -97,17 +97,17 @@ skip-if = toolkit == 'gonk' || buildapp 
 [test_peerConnection_captureStream_canvas_webgl.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 # [test_peerConnection_certificates.html] # bug 1180968
 # skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
 [test_peerConnection_close.html]
 [test_peerConnection_closeDuringIce.html]
 [test_peerConnection_errorCallbacks.html]
 [test_peerConnection_iceFailure.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' # Disabling because of test failures on B2G emulator
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' || os == 'linux' || os == 'mac' || os == 'win' # Disabling because of test failures on B2G emulator (Bug 1180388 for win, mac and linux)
 [test_peerConnection_forwarding_basicAudioVideoCombined.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_noTrickleAnswer.html]
 skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
 [test_peerConnection_noTrickleOffer.html]
 skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
 [test_peerConnection_noTrickleOfferAnswer.html]
 skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
--- a/dom/media/webaudio/BufferDecoder.cpp
+++ b/dom/media/webaudio/BufferDecoder.cpp
@@ -125,17 +125,17 @@ BufferDecoder::MetadataLoaded(nsAutoPtr<
 
 void
 BufferDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo, MediaDecoderEventVisibility aEventVisibility)
 {
   // ignore
 }
 
 void
-BufferDecoder::QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags)
+BufferDecoder::QueueMetadata(const media::TimeUnit& aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags)
 {
   // ignore
 }
 
 void
 BufferDecoder::RemoveMediaTracks()
 {
   // ignore
--- a/dom/media/webaudio/BufferDecoder.h
+++ b/dom/media/webaudio/BufferDecoder.h
@@ -53,17 +53,17 @@ public:
 
   virtual bool IsTransportSeekable() final override;
 
   virtual bool IsMediaSeekable() final override;
 
   virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
                               nsAutoPtr<MetadataTags> aTags,
                               MediaDecoderEventVisibility aEventVisibility) final override;
-  virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) final override;
+  virtual void QueueMetadata(const media::TimeUnit& aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) final override;
   virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
                                 MediaDecoderEventVisibility aEventVisibility) final override;
 
   virtual void RemoveMediaTracks() final override;
 
   virtual void OnReadMetadataCompleted() final override;
 
   virtual MediaDecoderOwner* GetOwner() final override;
--- a/dom/mobilemessage/ipc/SmsChild.cpp
+++ b/dom/mobilemessage/ipc/SmsChild.cpp
@@ -194,17 +194,16 @@ SmsRequestChild::ActorDestroy(ActorDestr
   // Nothing needed here.
 }
 
 bool
 SmsRequestChild::Recv__delete__(const MessageReply& aReply)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mReplyRequest);
-  nsCOMPtr<SmsMessage> message;
   switch(aReply.type()) {
     case MessageReply::TReplyMessageSend: {
         const MobileMessageData& data =
           aReply.get_ReplyMessageSend().messageData();
         nsCOMPtr<nsISupports> msg = CreateMessageFromMessageData(data);
         mReplyRequest->NotifyMessageSent(msg);
       }
       break;
--- a/dom/notification/DesktopNotification.cpp
+++ b/dom/notification/DesktopNotification.cpp
@@ -168,26 +168,24 @@ DesktopNotification::~DesktopNotificatio
 
 void
 DesktopNotification::DispatchNotificationEvent(const nsString& aName)
 {
   if (NS_FAILED(CheckInnerWindowCorrectness())) {
     return;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  if (NS_SUCCEEDED(rv)) {
-    // it doesn't bubble, and it isn't cancelable
-    rv = event->InitEvent(aName, false, false);
-    if (NS_SUCCEEDED(rv)) {
-      event->SetTrusted(true);
-      DispatchDOMEvent(nullptr, event, nullptr, nullptr);
-    }
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
+  // it doesn't bubble, and it isn't cancelable
+  nsresult rv = event->InitEvent(aName, false, false);
+  if (NS_FAILED(rv)) {
+    return;
   }
+  event->SetTrusted(true);
+  DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
 nsresult
 DesktopNotification::SetAllow(bool aAllow)
 {
   mAllow = aAllow;
 
   // if we have called Show() already, lets go ahead and post a notification
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -1072,18 +1072,17 @@ Notification::DispatchNotificationClickE
   // Client.focus() API if it wishes.
   return false;
 }
 
 bool
 Notification::DispatchClickEvent()
 {
   AssertIsOnTargetThread();
-  nsCOMPtr<nsIDOMEvent> event;
-  NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
   nsresult rv = event->InitEvent(NS_LITERAL_STRING("click"), false, true);
   NS_ENSURE_SUCCESS(rv, false);
   event->SetTrusted(true);
   WantsPopupControlCheck popupControlCheck(event);
   bool doDefaultAction = true;
   DispatchEvent(event, &doDefaultAction);
   return doDefaultAction;
 }
--- a/dom/offline/nsDOMOfflineResourceList.cpp
+++ b/dom/offline/nsDOMOfflineResourceList.cpp
@@ -16,16 +16,17 @@
 #include "nsServiceManagerUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIOfflineCacheUpdate.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsIObserverService.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIWebNavigation.h"
+#include "mozilla/dom/Event.h"
 #include "mozilla/dom/OfflineResourceListBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Preferences.h"
 
 #include "nsXULAppAPI.h"
 #define IS_CHILD_PROCESS() \
     (GeckoProcessType_Default != XRE_GetProcessType())
 
@@ -542,21 +543,17 @@ nsDOMOfflineResourceList::SendEvent(cons
   if (!GetOwner()) {
     return NS_OK;
   }
 
   if (!GetOwner()->GetDocShell()) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  nsresult rv = EventDispatcher::CreateEvent(this, nullptr, nullptr,
-                                             NS_LITERAL_STRING("Events"),
-                                             getter_AddRefs(event));
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
   event->InitEvent(aEventName, false, true);
 
   // We assume anyone that managed to call SendEvent is trusted
   event->SetTrusted(true);
 
   // If the window is frozen or we're still catching up on events that were
   // queued while frozen, save the event for later.
   if (GetOwner()->IsFrozen() || mPendingEvents.Count() > 0) {
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -637,33 +637,27 @@ NS_IMETHODIMP
 nsPluginInstanceOwner::RedrawPlugin()
 {
   if (mPluginFrame) {
     mPluginFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN);
   }
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
+#if defined(XP_WIN)
+nsIWidget*
+nsPluginInstanceOwner::GetContainingWidgetIfOffset()
 {
-  if (!mPluginFrame) {
-    NS_WARNING("plugin owner has no owner in getting doc's window handle");
-    return NS_ERROR_FAILURE;
-  }
-
-#if defined(XP_WIN)
-  void** pvalue = (void**)value;
-  nsViewManager* vm = mPluginFrame->PresContext()->GetPresShell()->GetViewManager();
-  if (!vm)
-    return NS_ERROR_FAILURE;
+  MOZ_ASSERT(mPluginFrame, "Caller should have checked for null mPluginFrame.");
+
   // This property is provided to allow a "windowless" plugin to determine the window it is drawing
   // in, so it can translate mouse coordinates it receives directly from the operating system
   // to coordinates relative to itself.
 
-  // The original code (outside this #if) returns the document's window, which is OK if the window the "windowless" plugin
+  // The original code returns the document's window, which is OK if the window the "windowless" plugin
   // is drawing into has the same origin as the document's window, but this is not the case for "windowless" plugins inside of scrolling DIVs etc
 
   // To make sure "windowless" plugins always get the right origin for translating mouse coordinates, this code
   // determines the window handle of the mozilla window containing the "windowless" plugin.
 
   // Given that this HWND may not be that of the document's window, there is a slight risk
   // of confusing a plugin that is using this HWND for illicit purposes, but since the documentation
   // does not suggest this HWND IS that of the document window, rather that of the window
@@ -687,27 +681,63 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
     if (win) {
       nsView *view = nsView::GetViewFor(win);
       NS_ASSERTION(view, "No view for widget");
       nsPoint offset = view->GetOffsetTo(nullptr);
 
       if (offset.x || offset.y) {
         // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window
         // so that mouse co-ordinates are not messed up.
-        *pvalue = (void*)win->GetNativeData(NS_NATIVE_WINDOW);
-        if (*pvalue)
-          return NS_OK;
+        return win;
       }
     }
   }
+
+  return nullptr;
+}
+
+static already_AddRefed<nsIWidget>
+GetRootWidgetForPluginFrame(const nsPluginFrame* aPluginFrame)
+{
+  MOZ_ASSERT(aPluginFrame);
+
+  nsViewManager* vm =
+    aPluginFrame->PresContext()->GetPresShell()->GetViewManager();
+  if (!vm) {
+    NS_WARNING("Could not find view manager for plugin frame.");
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIWidget> rootWidget;
+  vm->GetRootWidget(getter_AddRefs(rootWidget));
+  return rootWidget.forget();
+}
+#endif
+
+NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
+{
+  if (!mPluginFrame) {
+    NS_WARNING("plugin owner has no owner in getting doc's window handle");
+    return NS_ERROR_FAILURE;
+  }
+
+#if defined(XP_WIN)
+  void** pvalue = (void**)value;
+  nsIWidget* offsetContainingWidget = GetContainingWidgetIfOffset();
+  if (offsetContainingWidget) {
+    *pvalue = (void*)offsetContainingWidget->GetNativeData(NS_NATIVE_WINDOW);
+    if (*pvalue) {
+      return NS_OK;
+    }
+  }
+
   // simply return the topmost document window
-  nsCOMPtr<nsIWidget> widget;
-  vm->GetRootWidget(getter_AddRefs(widget));
+  nsCOMPtr<nsIWidget> widget = GetRootWidgetForPluginFrame(mPluginFrame);
   if (widget) {
-    *pvalue = (void*)widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
+    *pvalue = widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
   } else {
     NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
   }
 
   return NS_OK;
 #elif (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)) && defined(MOZ_X11)
   // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
   nsIWidget* win = mPluginFrame->GetNearestWidget();
@@ -715,16 +745,58 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
     return NS_ERROR_FAILURE;
   *static_cast<Window*>(value) = (long unsigned int)win->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 }
 
+#if defined(XP_WIN)
+void
+nsPluginInstanceOwner::SetWidgetWindowAsParent(HWND aWindowToAdopt)
+{
+  if (!mWidget) {
+    NS_ERROR("mWidget should exist before this gets called.");
+    return;
+  }
+
+  mWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
+                         reinterpret_cast<uintptr_t>(aWindowToAdopt));
+}
+
+nsresult
+nsPluginInstanceOwner::SetNetscapeWindowAsParent(HWND aWindowToAdopt)
+{
+  if (!mPluginFrame) {
+    NS_WARNING("Plugin owner has no plugin frame.");
+    return NS_ERROR_FAILURE;
+  }
+
+  // If there is a containing window that is offset then ask that to adopt.
+  nsIWidget* offsetWidget = GetContainingWidgetIfOffset();
+  if (offsetWidget) {
+    offsetWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
+                                reinterpret_cast<uintptr_t>(aWindowToAdopt));
+    return NS_OK;
+  }
+
+  // Otherwise ask the topmost document window to adopt.
+  nsCOMPtr<nsIWidget> rootWidget = GetRootWidgetForPluginFrame(mPluginFrame);
+  if (!rootWidget) {
+    NS_ASSERTION(rootWidget, "Couldn't get topmost document's widget.");
+    return NS_ERROR_FAILURE;
+  }
+
+  rootWidget->SetNativeData(NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW,
+                            reinterpret_cast<uintptr_t>(aWindowToAdopt));
+  return NS_OK;
+}
+#endif
+
 NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel)
 {
 #ifdef XP_MACOSX
   mEventModel = static_cast<NPEventModel>(eventModel);
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -107,16 +107,21 @@ public:
   //locals
   
   nsresult Init(nsIContent* aContent);
   
   void* GetPluginPort();
   void ReleasePluginPort(void* pluginPort);
 
   nsEventStatus ProcessEvent(const mozilla::WidgetGUIEvent& anEvent);
+
+#if defined(XP_WIN)
+  void SetWidgetWindowAsParent(HWND aWindowToAdopt);
+  nsresult SetNetscapeWindowAsParent(HWND aWindowToAdopt);
+#endif
   
 #ifdef XP_MACOSX
   enum { ePluginPaintEnable, ePluginPaintDisable };
 
   void WindowFocusMayHaveChanged();
   void ResolutionMayHaveChanged();
 
   bool WindowIsActive();
@@ -268,16 +273,20 @@ private:
 #ifdef MOZ_WIDGET_ANDROID
   mozilla::LayoutDeviceRect GetPluginRect();
   bool AddPluginView(const mozilla::LayoutDeviceRect& aRect = mozilla::LayoutDeviceRect(0, 0, 0, 0));
   void RemovePluginView();
 
   bool mFullScreen;
   void* mJavaView;
 #endif 
+
+#if defined(XP_WIN)
+  nsIWidget* GetContainingWidgetIfOffset();
+#endif
  
   nsPluginNativeWindow       *mPluginWindow;
   nsRefPtr<nsNPAPIPluginInstance> mInstance;
   nsPluginFrame              *mPluginFrame;
   nsWeakPtr                   mContent; // WEAK, content owns us
   nsCString                   mDocumentBase;
   bool                        mWidgetCreationComplete;
   nsCOMPtr<nsIWidget>         mWidget;
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -65,18 +65,21 @@ intr protocol PPluginInstance
   manages PStreamNotify;
   manages PPluginSurface;
 
 child:
   intr __delete__();
 
   // This is only used on Windows and, for windowed plugins, must be called
   // before the first call to NPP_SetWindow.
-  intr CreateChildPluginWindow(NPRemoteWindow window)
-    returns (NPRemoteWindow createdChild);
+  intr CreateChildPluginWindow()
+    returns (NativeWindowHandle childPluginWindow);
+
+  // This is only used on Windows and, for windowless plugins.
+  async CreateChildPopupSurrogate(NativeWindowHandle netscapeWindow);
 
   intr NPP_SetWindow(NPRemoteWindow window);
 
   intr NPP_GetValue_NPPVpluginWantsAllNetworkStreams()
     returns (bool value, NPError result);
 
   // this message is not used on non-X platforms
   intr NPP_GetValue_NPPVpluginNeedsXEmbed()
@@ -214,16 +217,20 @@ parent:
   // Send notification that a plugin tried to negotiate Carbon NPAPI so that
   // users can be notified that restarting the browser in i386 mode may allow
   // them to use the plugin.
   sync NegotiatedCarbon();
 
   // Notifies the parent of its NPP_New result code.
   async AsyncNPP_NewResult(NPError aResult);
 
+  // Sends a native window to be adopted by the native window that would be
+  // returned by NPN_GetValue_NPNVnetscapeWindow. Only used on Windows.
+  async SetNetscapeWindowAsParent(NativeWindowHandle childWindow);
+
 both:
   async PPluginScriptableObject();
 
 child:
   /* NPP_NewStream */
   async PBrowserStream(nsCString url,
                        uint32_t length,
                        uint32_t lastmodified,
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -192,27 +192,27 @@ PluginInstanceChild::PluginInstanceChild
     mWsInfo.display = DefaultXDisplay();
 #endif
 #endif // MOZ_X11 && XP_UNIX && !XP_MACOSX
 #if defined(OS_WIN)
     memset(&mAlphaExtract, 0, sizeof(mAlphaExtract));
 #endif // OS_WIN
 #if defined(OS_WIN)
     InitPopupMenuHook();
-    if (GetQuirks() & PluginModuleChild::QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) {
+    if (GetQuirks() & QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) {
         SetUnityHooks();
     }
 #endif // OS_WIN
 }
 
 PluginInstanceChild::~PluginInstanceChild()
 {
 #if defined(OS_WIN)
     NS_ASSERTION(!mPluginWindowHWND, "Destroying PluginInstanceChild without NPP_Destroy?");
-    if (GetQuirks() & PluginModuleChild::QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) {
+    if (GetQuirks() & QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) {
         ClearUnityHooks();
     }
 #endif
 #if defined(MOZ_WIDGET_COCOA)
     if (mShColorSpace) {
         ::CGColorSpaceRelease(mShColorSpace);
     }
     if (mShContext) {
@@ -400,17 +400,17 @@ PluginInstanceChild::NPN_GetValue(NPNVar
     case NPNVdocumentOrigin: {
         nsCString v;
         NPError result;
         if (!CallNPN_GetValue_NPNVdocumentOrigin(&v, &result)) {
             return NPERR_GENERIC_ERROR;
         }
         if (result == NPERR_NO_ERROR ||
             (GetQuirks() &
-                PluginModuleChild::QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN)) {
+                QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN)) {
             *static_cast<char**>(aValue) = ToNewCString(v);
         }
         return result;
     }
 
     case NPNVWindowNPObject: // Intentional fall-through
     case NPNVPluginElementNPObject: {
         NPObject* object;
@@ -1023,17 +1023,17 @@ PluginInstanceChild::AnswerNPP_HandleEve
                 PLUGIN_LOG_DEBUG(("Plugin requested CoreAnimation but did not "
                                   "provide CALayer."));
                 *handled = false;
                 return false;
             }
 
             mCARenderer->SetupRenderer(caLayer, mWindow.width, mWindow.height,
                             mContentsScaleFactor,
-                            GetQuirks() & PluginModuleChild::QUIRK_ALLOW_OFFLINE_RENDERER ?
+                            GetQuirks() & QUIRK_ALLOW_OFFLINE_RENDERER ?
                             ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER);
 
             // Flash needs to have the window set again after this step
             if (mPluginIface->setwindow)
                 (void) mPluginIface->setwindow(&mData, &mWindow);
         }
     } else {
         PLUGIN_LOG_DEBUG(("Invalid event type for "
@@ -1141,35 +1141,41 @@ void PluginInstanceChild::DeleteWindow()
 #endif
 
   // We don't have to keep the plug-in window ID any longer.
   mWindow.window = nullptr;
 }
 #endif
 
 bool
-PluginInstanceChild::AnswerCreateChildPluginWindow(const NPRemoteWindow& aWindow,
-                                                   NPRemoteWindow* aCreatedChild)
+PluginInstanceChild::AnswerCreateChildPluginWindow(NativeWindowHandle* aChildPluginWindow)
 {
 #if defined(XP_WIN)
-    MOZ_ASSERT(aWindow.type == NPWindowTypeWindow);
     MOZ_ASSERT(!mPluginWindowHWND);
 
-    if ((GetQuirks() & PluginModuleChild::QUIRK_QUICKTIME_AVOID_SETWINDOW) &&
-        aWindow.width == 0 && aWindow.height == 0) {
-
-        // Skip CreateChildPluginWindow call for hidden QuickTime plugins.
-        return true;
-    }
-
     if (!CreatePluginWindow()) {
         return false;
     }
 
-    aCreatedChild->window = reinterpret_cast<uint64_t>(mPluginWindowHWND);
+    MOZ_ASSERT(mPluginWindowHWND);
+
+    *aChildPluginWindow = mPluginWindowHWND;
+    return true;
+#else
+    NS_NOTREACHED("PluginInstanceChild::CreateChildPluginWindow not implemented!");
+    return false;
+#endif
+}
+
+bool
+PluginInstanceChild::RecvCreateChildPopupSurrogate(const NativeWindowHandle& aNetscapeWindow)
+{
+#if defined(XP_WIN)
+    mCachedWinlessPluginHWND = aNetscapeWindow;
+    CreateWinlessPopupSurrogate();
     return true;
 #else
     NS_NOTREACHED("PluginInstanceChild::CreateChildPluginWindow not implemented!");
     return false;
 #endif
 }
 
 bool
@@ -1249,22 +1255,20 @@ PluginInstanceChild::AnswerNPP_SetWindow
 
     if (mPluginIface->setwindow)
         (void) mPluginIface->setwindow(&mData, &mWindow);
 
 #elif defined(OS_WIN)
     switch (aWindow.type) {
       case NPWindowTypeWindow:
       {
-          if ((GetQuirks() & PluginModuleChild::QUIRK_QUICKTIME_AVOID_SETWINDOW) &&
-              aWindow.width == 0 &&
-              aWindow.height == 0) {
-            // Skip SetWindow call for hidden QuickTime plugins
-            return true;
-          }
+          // This check is now done in PluginInstanceParent before this call, so
+          // we should never see it here.
+          MOZ_ASSERT(!(GetQuirks() & QUIRK_QUICKTIME_AVOID_SETWINDOW) ||
+                     aWindow.width != 0 || aWindow.height != 0);
 
           MOZ_ASSERT(mPluginWindowHWND,
                      "Child plugin window must exist before call to SetWindow");
 
           HWND parentHWND =  reinterpret_cast<HWND>(aWindow.window);
           if (mPluginWindowHWND != parentHWND) {
               mPluginParentHWND = parentHWND;
               ShowWindow(mPluginWindowHWND, SW_SHOWNA);
@@ -1293,19 +1297,17 @@ PluginInstanceChild::AnswerNPP_SetWindow
               RemoveProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty);
               HookSetWindowLongPtr();
           }
       }
       break;
 
       case NPWindowTypeDrawable:
           mWindow.type = aWindow.type;
-          if (GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK)
-              CreateWinlessPopupSurrogate();
-          if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
+          if (GetQuirks() & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
               SetupFlashMsgThrottle();
           return SharedSurfaceSetWindow(aWindow);
       break;
 
       default:
           NS_NOTREACHED("Bad plugin window type.");
           return false;
       break;
@@ -1549,34 +1551,34 @@ PluginInstanceChild::PluginWindowProcInt
         }
     }
 
     if (message == WM_KILLFOCUS) {
       self->CallPluginFocusChange(false);
     }
 
     if (message == WM_USER+1 &&
-        (self->GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)) {
+        (self->GetQuirks() & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)) {
         self->FlashThrottleMessage(hWnd, message, wParam, lParam, true);
         return 0;
     }
 
     NS_ASSERTION(self->mPluginWndProc != PluginWindowProc,
       "Self-referential windowproc happened inside our hook proc. "
       "Infinite recursion will happen soon.");
 
     LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
                                  lParam);
 
     // Make sure capture is released by the child on mouse events. Fixes a
     // problem with flash full screen mode mouse input. Appears to be
     // caused by a bug in flash, since we are not setting the capture
     // on the window.
     if (message == WM_LBUTTONDOWN &&
-        self->GetQuirks() & PluginModuleChild::QUIRK_FLASH_FIXUP_MOUSE_CAPTURE) {
+        self->GetQuirks() & QUIRK_FLASH_FIXUP_MOUSE_CAPTURE) {
       wchar_t szClass[26];
       HWND hwnd = GetForegroundWindow();
       if (hwnd && GetClassNameW(hwnd, szClass,
                                 sizeof(szClass)/sizeof(char16_t)) &&
           !wcscmp(szClass, kFlashFullscreenClass)) {
         ReleaseCapture();
         SetFocus(hwnd);
       }
@@ -1727,17 +1729,17 @@ PluginInstanceChild::SetWindowLongWHook(
         NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Infinite recursion coming up!");
     }
     return proc;
 }
 
 void
 PluginInstanceChild::HookSetWindowLongPtr()
 {
-    if (!(GetQuirks() & PluginModuleChild::QUIRK_FLASH_HOOK_SETLONGPTR))
+    if (!(GetQuirks() & QUIRK_FLASH_HOOK_SETLONGPTR))
         return;
 
     sUser32Intercept.Init("user32.dll");
 #ifdef _WIN64
     if (!sUser32SetWindowLongAHookStub)
         sUser32Intercept.AddHook("SetWindowLongPtrA", reinterpret_cast<intptr_t>(SetWindowLongPtrAHook),
                                  (void**) &sUser32SetWindowLongAHookStub);
     if (!sUser32SetWindowLongWHookStub)
@@ -1814,17 +1816,17 @@ PluginInstanceChild::SetCaptureHook(HWND
         sSetCaptureHookData = new SetCaptureHookData(aHwnd);
     }
     return sUser32SetCaptureHookStub(aHwnd);
 }
 
 void
 PluginInstanceChild::SetUnityHooks()
 {
-    if (!(GetQuirks() & PluginModuleChild::QUIRK_UNITY_FIXUP_MOUSE_CAPTURE)) {
+    if (!(GetQuirks() & QUIRK_UNITY_FIXUP_MOUSE_CAPTURE)) {
         return;
     }
 
     sUser32Intercept.Init("user32.dll");
     if (!sUser32SetCaptureHookStub) {
         sUser32Intercept.AddHook("SetCapture",
                                  reinterpret_cast<intptr_t>(SetCaptureHook),
                                  (void**) &sUser32SetCaptureHookStub);
@@ -1941,17 +1943,17 @@ PluginInstanceChild::TrackPopupHookProc(
   }
 
   return res;
 }
 
 void
 PluginInstanceChild::InitPopupMenuHook()
 {
-    if (!(GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) ||
+    if (!(GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK) ||
         sUser32TrackPopupMenuStub)
         return;
 
     // Note, once WindowsDllInterceptor is initialized for a module,
     // it remains initialized for that particular module for it's
     // lifetime. Additional instances are needed if other modules need
     // to be hooked.
     if (!sUser32TrackPopupMenuStub) {
@@ -1963,31 +1965,25 @@ PluginInstanceChild::InitPopupMenuHook()
 
 void
 PluginInstanceChild::CreateWinlessPopupSurrogate()
 {
     // already initialized
     if (mWinlessPopupSurrogateHWND)
         return;
 
-    HWND hwnd = nullptr;
-    NPError result;
-    if (!CallNPN_GetValue_NPNVnetscapeWindow(&hwnd, &result)) {
-        NS_ERROR("CallNPN_GetValue_NPNVnetscapeWindow failed.");
-        return;
-    }
-
     mWinlessPopupSurrogateHWND =
-        CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", nullptr, WS_CHILD,
-                       0, 0, 0, 0, hwnd, 0, GetModuleHandle(nullptr), 0);
+        CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", nullptr, WS_POPUP,
+                       0, 0, 0, 0, nullptr, 0, GetModuleHandle(nullptr), 0);
     if (!mWinlessPopupSurrogateHWND) {
         NS_ERROR("CreateWindowEx failed for winless placeholder!");
         return;
     }
-    return;
+
+    SendSetNetscapeWindowAsParent(mWinlessPopupSurrogateHWND);
 }
 
 void
 PluginInstanceChild::DestroyWinlessPopupSurrogate()
 {
     if (mWinlessPopupSurrogateHWND)
         DestroyWindow(mWinlessPopupSurrogateHWND);
     mWinlessPopupSurrogateHWND = nullptr;
@@ -2003,17 +1999,17 @@ PluginInstanceChild::WinlessHandleEvent(
     // special handling during delivery.
     int16_t handled;
     
     HWND focusHwnd = nullptr;
 
     // TrackPopupMenu will fail if the parent window is not associated with
     // our ui thread. So we hook TrackPopupMenu so we can hand in a surrogate
     // parent created in the child process.
-    if ((GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) && // XXX turn on by default?
+    if ((GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK) && // XXX turn on by default?
           (event.event == WM_RBUTTONDOWN || // flash
            event.event == WM_RBUTTONUP)) {  // silverlight
       sWinlessPopupSurrogateHWND = mWinlessPopupSurrogateHWND;
       
       // A little trick scrounged from chromium's code - set the focus
       // to our surrogate parent so keyboard nav events go to the menu. 
       focusHwnd = SetFocus(mWinlessPopupSurrogateHWND);
     }
@@ -2395,17 +2391,17 @@ PluginInstanceChild::AnswerSetPluginFocu
 
 #if defined(OS_WIN)
     // Parent is letting us know the dom set focus to the plugin. Note,
     // focus can change during transit in certain edge cases, for example
     // when a button click brings up a full screen window. Since we send
     // this in response to a WM_SETFOCUS event on our parent, the parent
     // should have focus when we receive this. If not, ignore the call.
     if (::GetFocus() == mPluginWindowHWND ||
-        ((GetQuirks() & PluginModuleChild::QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT) &&
+        ((GetQuirks() & QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT) &&
          (::GetFocus() != mPluginParentHWND)))
         return true;
     ::SetFocus(mPluginWindowHWND);
     return true;
 #else
     NS_NOTREACHED("PluginInstanceChild::AnswerSetPluginFocus not implemented!");
     return false;
 #endif
@@ -2820,27 +2816,25 @@ PluginInstanceChild::DoAsyncSetWindow(co
     mWindow.width = aWindow.width;
     mWindow.height = aWindow.height;
     mWindow.clipRect = aWindow.clipRect;
     mWindow.type = aWindow.type;
 #ifdef XP_MACOSX
     mContentsScaleFactor = aWindow.contentsScaleFactor;
 #endif
 
-    if (GetQuirks() & PluginModuleChild::QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT)
+    if (GetQuirks() & QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT)
         mIsTransparent = true;
 
     mLayersRendering = true;
     mSurfaceType = aSurfaceType;
     UpdateWindowAttributes(true);
 
 #ifdef XP_WIN
-    if (GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK)
-        CreateWinlessPopupSurrogate();
-    if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
+    if (GetQuirks() & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
         SetupFlashMsgThrottle();
 #endif
 
     if (!mAccumulatedInvalidRect.IsEmpty()) {
         AsyncShowPluginFrame();
     }
 }
 
@@ -3022,17 +3016,17 @@ PluginInstanceChild::EnsureCurrentBuffer
     return true;
 #elif defined(XP_MACOSX)
 
     if (!mDoubleBufferCARenderer.HasCALayer()) {
         void *caLayer = nullptr;
         if (mDrawingModel == NPDrawingModelCoreGraphics) {
             if (!mCGLayer) {
                 bool avoidCGCrashes = !nsCocoaFeatures::OnMountainLionOrLater() &&
-                  (GetQuirks() & PluginModuleChild::QUIRK_FLASH_AVOID_CGMODE_CRASHES);
+                  (GetQuirks() & QUIRK_FLASH_AVOID_CGMODE_CRASHES);
                 caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, this,
                                                                        avoidCGCrashes,
                                                                        mContentsScaleFactor);
 
                 if (!caLayer) {
                     PLUGIN_LOG_DEBUG(("GetCGLayer failed."));
                     return false;
                 }
@@ -3056,17 +3050,17 @@ PluginInstanceChild::EnsureCurrentBuffer
          mDoubleBufferCARenderer.GetFrontSurfaceHeight() != mWindow.height ||
          mDoubleBufferCARenderer.GetContentsScaleFactor() != mContentsScaleFactor)) {
         mDoubleBufferCARenderer.ClearFrontSurface();
     }
 
     if (!mDoubleBufferCARenderer.HasFrontSurface()) {
         bool allocSurface = mDoubleBufferCARenderer.InitFrontSurface(
                                 mWindow.width, mWindow.height, mContentsScaleFactor,
-                                GetQuirks() & PluginModuleChild::QUIRK_ALLOW_OFFLINE_RENDERER ?
+                                GetQuirks() & QUIRK_ALLOW_OFFLINE_RENDERER ?
                                 ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER);
         if (!allocSurface) {
             PLUGIN_LOG_DEBUG(("Fail to allocate front IOSurface"));
             return false;
         }
 
         if (mPluginIface->setwindow)
             (void) mPluginIface->setwindow(&mData, &mWindow);
@@ -3229,17 +3223,17 @@ void
 PluginInstanceChild::PaintRectToSurface(const nsIntRect& aRect,
                                         gfxASurface* aSurface,
                                         const gfxRGBA& aColor)
 {
     // Render using temporary X surface, with copy to image surface
     nsIntRect plPaintRect(aRect);
     nsRefPtr<gfxASurface> renderSurface = aSurface;
 #ifdef MOZ_X11
-    if (mIsTransparent && (GetQuirks() & PluginModuleChild::QUIRK_FLASH_EXPOSE_COORD_TRANSLATION)) {
+    if (mIsTransparent && (GetQuirks() & QUIRK_FLASH_EXPOSE_COORD_TRANSLATION)) {
         // Work around a bug in Flash up to 10.1 d51 at least, where expose event
         // top left coordinates within the plugin-rect and not at the drawable
         // origin are misinterpreted.  (We can move the top left coordinate
         // provided it is within the clipRect.), see bug 574583
         plPaintRect.SetRect(0, 0, aRect.XMost(), aRect.YMost());
     }
     if (mHelperSurface) {
         // On X11 we can paint to non Xlib surface only with HelperSurface
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -60,20 +60,24 @@ class PluginInstanceChild : public PPlug
                                              LPARAM lParam);
     static LRESULT CALLBACK PluginWindowProcInternal(HWND hWnd,
                                                      UINT message,
                                                      WPARAM wParam,
                                                      LPARAM lParam);
 #endif
 
 protected:
-    bool AnswerCreateChildPluginWindow(const NPRemoteWindow& window,
-                                       NPRemoteWindow* aCreatedChild) override;
+    virtual bool
+    AnswerCreateChildPluginWindow(NativeWindowHandle* aChildPluginWindow) override;
 
-    bool AnswerNPP_SetWindow(const NPRemoteWindow& window) override;
+    virtual bool
+    RecvCreateChildPopupSurrogate(const NativeWindowHandle& aNetscapeWindow) override;
+
+    virtual bool
+    AnswerNPP_SetWindow(const NPRemoteWindow& window) override;
 
     virtual bool
     AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(bool* wantsAllStreams, NPError* rv) override;
     virtual bool
     AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(bool* needs, NPError* rv) override;
     virtual bool
     AnswerNPP_GetValue_NPPVpluginScriptableNPObject(PPluginScriptableObjectChild** value,
                                                     NPError* result) override;
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -46,16 +46,17 @@
 #if defined(OS_WIN)
 #include <windowsx.h>
 #include "gfxWindowsPlatform.h"
 #include "mozilla/plugins/PluginSurfaceParent.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIWidget.h"
 #include "nsPluginNativeWindow.h"
+#include "PluginQuirks.h"
 extern const wchar_t* kFlashFullscreenClass;
 #elif defined(MOZ_WIDGET_GTK)
 #include <gdk/gdk.h>
 #elif defined(XP_MACOSX)
 #include <ApplicationServices/ApplicationServices.h>
 #endif // defined(XP_MACOSX)
 
 // This is the pref used to determine whether to use Shumway on a Flash object
@@ -674,16 +675,21 @@ PluginInstanceParent::AsyncSetWindow(NPW
     window.height = aWindow->height;
     window.clipRect = aWindow->clipRect;
     window.type = aWindow->type;
 #ifdef XP_MACOSX
     double scaleFactor = 1.0;
     mNPNIface->getvalue(mNPP, NPNVcontentsScaleFactor, &scaleFactor);
     window.contentsScaleFactor = scaleFactor;
 #endif
+
+#if defined(OS_WIN)
+    MaybeCreateChildPopupSurrogate();
+#endif
+
     if (!SendAsyncSetWindow(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType(),
                             window))
         return NS_ERROR_FAILURE;
 
     return NS_OK;
 }
 
 nsresult
@@ -962,26 +968,39 @@ PluginInstanceParent::NPP_SetWindow(cons
 
 #if defined(OS_WIN)
     // On windowless controls, reset the shared memory surface as needed.
     if (mWindowType == NPWindowTypeDrawable) {
         // SharedSurfaceSetWindow will take care of NPRemoteWindow.
         if (!SharedSurfaceSetWindow(aWindow, window)) {
           return NPERR_OUT_OF_MEMORY_ERROR;
         }
-    }
-    else {
+
+        MaybeCreateChildPopupSurrogate();
+    } else {
         SubclassPluginWindow(reinterpret_cast<HWND>(aWindow->window));
 
+        // Skip SetWindow call for hidden QuickTime plugins.
+        if ((mParent->GetQuirks() & QUIRK_QUICKTIME_AVOID_SETWINDOW) &&
+            aWindow->width == 0 && aWindow->height == 0) {
+            return NPERR_NO_ERROR;
+        }
+
         window.window = reinterpret_cast<uint64_t>(aWindow->window);
         window.x = aWindow->x;
         window.y = aWindow->y;
         window.width = aWindow->width;
         window.height = aWindow->height;
         window.type = aWindow->type;
+
+        // On Windows we need to create and set the parent before we set the
+        // window on the plugin, or keyboard interaction will not work.
+        if (!MaybeCreateAndParentChildPluginWindow()) {
+            return NPERR_GENERIC_ERROR;
+        }
     }
 #else
     window.window = reinterpret_cast<uint64_t>(aWindow->window);
     window.x = aWindow->x;
     window.y = aWindow->y;
     window.width = aWindow->width;
     window.height = aWindow->height;
     window.clipRect = aWindow->clipRect; // MacOS specific
@@ -1022,43 +1041,16 @@ PluginInstanceParent::NPP_SetWindow(cons
 
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     const NPSetWindowCallbackStruct* ws_info =
       static_cast<NPSetWindowCallbackStruct*>(aWindow->ws_info);
     window.visualID = ws_info->visual ? ws_info->visual->visualid : None;
     window.colormap = ws_info->colormap;
 #endif
 
-#if defined(XP_WIN)
-    // On Windows we need to create and set the parent before we set the window
-    // on the plugin, or certain things like keyboard interaction will not work.
-    if (!mChildPluginHWND && mWindowType == NPWindowTypeWindow) {
-        NPRemoteWindow childWindow;
-        if (!CallCreateChildPluginWindow(window, &childWindow)) {
-            return NPERR_GENERIC_ERROR;
-        }
-
-        mChildPluginHWND = reinterpret_cast<HWND>(childWindow.window);
-    }
-
-    // It's not clear if the parent window would ever change, but when this was
-    // done in the NPAPI child it used to allow for this.
-    if (mChildPluginHWND && mPluginHWND != mChildPluginsParentHWND) {
-        nsCOMPtr<nsIWidget> widget;
-        static_cast<const nsPluginNativeWindow*>(aWindow)->
-            GetPluginWidget(getter_AddRefs(widget));
-        if (widget) {
-            widget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
-                                  reinterpret_cast<uintptr_t>(mChildPluginHWND));
-        }
-
-        mChildPluginsParentHWND = mPluginHWND;
-    }
-#endif
-
     if (!CallNPP_SetWindow(window)) {
         return NPERR_GENERIC_ERROR;
     }
 
     return NPERR_NO_ERROR;
 }
 
 NPError
@@ -1801,16 +1793,32 @@ PluginInstanceParent::RecvAsyncNPP_NewRe
     owner->NotifyHostCreateWidget();
 
     MOZ_ASSERT(mSurrogate);
     mSurrogate->OnInstanceCreated(this);
 
     return true;
 }
 
+bool
+PluginInstanceParent::RecvSetNetscapeWindowAsParent(const NativeWindowHandle& childWindow)
+{
+#if defined(XP_WIN)
+    nsPluginInstanceOwner* owner = GetOwner();
+    if (!owner || NS_FAILED(owner->SetNetscapeWindowAsParent(childWindow))) {
+        NS_WARNING("Failed to set Netscape window as parent.");
+    }
+
+    return true;
+#else
+    NS_NOTREACHED("PluginInstanceParent::RecvSetNetscapeWindowAsParent not implemented!");
+    return false;
+#endif
+}
+
 #if defined(OS_WIN)
 
 /*
   plugin focus changes between processes
 
   focus from dom -> child:
     Focus manager calls on widget to set the focus on the window.
     We pick up the resulting wm_setfocus event here, and forward
@@ -2045,16 +2053,75 @@ PluginInstanceParent::SharedSurfaceAfter
              dirtyRect.width,
              dirtyRect.height,
              mSharedSurfaceDib.GetHDC(),
              dirtyRect.x,
              dirtyRect.y,
              SRCCOPY);
 }
 
+bool
+PluginInstanceParent::MaybeCreateAndParentChildPluginWindow()
+{
+    // On Windows we need to create and set the parent before we set the
+    // window on the plugin, or keyboard interaction will not work.
+    if (!mChildPluginHWND) {
+        if (!CallCreateChildPluginWindow(&mChildPluginHWND) ||
+            !mChildPluginHWND) {
+            return false;
+        }
+    }
+
+    // It's not clear if the parent window would ever change, but when this
+    // was done in the NPAPI child it used to allow for this.
+    if (mPluginHWND == mChildPluginsParentHWND) {
+        return true;
+    }
+
+    nsPluginInstanceOwner* owner = GetOwner();
+    if (!owner) {
+        // We can't reparent without an owner, the plugin is probably shutting
+        // down, just return true to allow any calls to continue.
+        return true;
+    }
+
+    // Note that this call will probably cause a sync native message to the
+    // process that owns the child window.
+    owner->SetWidgetWindowAsParent(mChildPluginHWND);
+    mChildPluginsParentHWND = mPluginHWND;
+    return true;
+}
+
+void
+PluginInstanceParent::MaybeCreateChildPopupSurrogate()
+{
+    // Already created or not required for this plugin.
+    if (mChildPluginHWND || mWindowType != NPWindowTypeDrawable ||
+        !(mParent->GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK)) {
+        return;
+    }
+
+    // We need to pass the netscape window down to be cached as part of the call
+    // to create the surrogate, because the reparenting of the surrogate in the
+    // main process can cause sync Windows messages to the plugin process, which
+    // then cause sync messages from the plugin child for the netscape window
+    // which causes a deadlock.
+    NativeWindowHandle netscapeWindow;
+    NPError result = mNPNIface->getvalue(mNPP, NPNVnetscapeWindow,
+                                         &netscapeWindow);
+    if (NPERR_NO_ERROR != result) {
+        NS_WARNING("Can't get netscape window to pass to plugin child.");
+        return;
+    }
+
+    if (!SendCreateChildPopupSurrogate(netscapeWindow)) {
+        NS_WARNING("Failed to create popup surrogate in child.");
+    }
+}
+
 #endif // defined(OS_WIN)
 
 bool
 PluginInstanceParent::AnswerPluginFocusChange(const bool& gotFocus)
 {
     PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
 
     // Currently only in use on windows - an event we receive from the child
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -216,16 +216,19 @@ public:
     RecvRedrawPlugin() override;
 
     virtual bool
     RecvNegotiatedCarbon() override;
 
     virtual bool
     RecvAsyncNPP_NewResult(const NPError& aResult) override;
 
+    virtual bool
+    RecvSetNetscapeWindowAsParent(const NativeWindowHandle& childWindow) override;
+
     NPError NPP_SetWindow(const NPWindow* aWindow);
 
     NPError NPP_GetValue(NPPVariable variable, void* retval);
     NPError NPP_SetValue(NPNVariable variable, void* value);
 
     void NPP_URLRedirectNotify(const char* url, int32_t status,
                                void* notifyData);
 
@@ -356,21 +359,26 @@ private:
     void SharedSurfaceAfterPaint(NPEvent* npevent);
     void SharedSurfaceRelease();
     // Used in handling parent/child forwarding of events.
     static LRESULT CALLBACK PluginWindowHookProc(HWND hWnd, UINT message,
                                                  WPARAM wParam, LPARAM lParam);
     void SubclassPluginWindow(HWND aWnd);
     void UnsubclassPluginWindow();
 
+    bool MaybeCreateAndParentChildPluginWindow();
+    void MaybeCreateChildPopupSurrogate();
+
 private:
     gfx::SharedDIBWin  mSharedSurfaceDib;
     nsIntRect          mPluginPort;
     nsIntRect          mSharedSize;
     HWND               mPluginHWND;
+    // This is used for the normal child plugin HWND for windowed plugins and,
+    // if needed, also the child popup surrogate HWND for windowless plugins.
     HWND               mChildPluginHWND;
     HWND               mChildPluginsParentHWND;
     WNDPROC            mPluginWndProc;
     bool               mNestedEventState;
 
     // This will automatically release the textures when this object goes away.
     nsRefPtrHashtable<nsPtrHashKey<void>, ID3D10Texture2D> mTextureMap;
 #endif // defined(XP_WIN)
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -2106,65 +2106,21 @@ PluginModuleChild::AllocPPluginInstanceC
 
     return new PluginInstanceChild(&mFunctions, aMimeType, aMode, aNames,
                                    aValues);
 }
 
 void
 PluginModuleChild::InitQuirksModes(const nsCString& aMimeType)
 {
-    if (mQuirks != QUIRKS_NOT_INITIALIZED)
+    if (mQuirks != QUIRKS_NOT_INITIALIZED) {
       return;
-    mQuirks = 0;
-
-    nsPluginHost::SpecialType specialType = nsPluginHost::GetSpecialType(aMimeType);
-
-    if (specialType == nsPluginHost::eSpecialType_Silverlight) {
-        mQuirks |= QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT;
-#ifdef OS_WIN
-        mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK;
-        mQuirks |= QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT;
-#endif
-    }
-
-    if (specialType == nsPluginHost::eSpecialType_Flash) {
-        mQuirks |= QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN;
-#ifdef OS_WIN
-        mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK;
-        mQuirks |= QUIRK_FLASH_THROTTLE_WMUSER_EVENTS;
-        mQuirks |= QUIRK_FLASH_HOOK_SETLONGPTR;
-        mQuirks |= QUIRK_FLASH_HOOK_GETWINDOWINFO;
-        mQuirks |= QUIRK_FLASH_FIXUP_MOUSE_CAPTURE;
-#endif
     }
 
-#ifdef OS_WIN
-    // QuickTime plugin usually loaded with audio/mpeg mimetype
-    NS_NAMED_LITERAL_CSTRING(quicktime, "npqtplugin");
-    if (FindInReadable(quicktime, mPluginFilename)) {
-        mQuirks |= QUIRK_QUICKTIME_AVOID_SETWINDOW;
-    }
-#endif
-
-#ifdef XP_MACOSX
-    // Whitelist Flash and Quicktime to support offline renderer
-    NS_NAMED_LITERAL_CSTRING(quicktime, "QuickTime Plugin.plugin");
-    if (specialType == nsPluginHost::eSpecialType_Flash) {
-        mQuirks |= QUIRK_FLASH_AVOID_CGMODE_CRASHES;
-        mQuirks |= QUIRK_ALLOW_OFFLINE_RENDERER;
-    } else if (FindInReadable(quicktime, mPluginFilename)) {
-        mQuirks |= QUIRK_ALLOW_OFFLINE_RENDERER;
-    }
-#endif
-
-#ifdef OS_WIN
-    if (specialType == nsPluginHost::eSpecialType_Unity) {
-        mQuirks |= QUIRK_UNITY_FIXUP_MOUSE_CAPTURE;
-    }
-#endif
+    mQuirks = GetQuirksFromMimeTypeAndFilename(aMimeType, mPluginFilename);
 }
 
 bool
 PluginModuleChild::RecvPPluginInstanceConstructor(PPluginInstanceChild* aActor,
                                                   const nsCString& aMimeType,
                                                   const uint16_t& aMode,
                                                   InfallibleTArray<nsCString>&& aNames,
                                                   InfallibleTArray<nsCString>&& aValues)
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -26,16 +26,17 @@
 
 #ifdef MOZ_WIDGET_COCOA
 #include "PluginInterposeOSX.h"
 #endif
 
 #include "mozilla/plugins/PPluginModuleChild.h"
 #include "mozilla/plugins/PluginInstanceChild.h"
 #include "mozilla/plugins/PluginMessageUtils.h"
+#include "mozilla/plugins/PluginQuirks.h"
 
 // NOTE: stolen from nsNPAPIPlugin.h
 
 #if defined(XP_WIN)
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name)
 #else
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (* _name)
 #endif
@@ -237,66 +238,16 @@ public:
         SendPopCursor();
     }
 
     bool GetNativeCursorsSupported() {
         return Settings().nativeCursorsSupported();
     }
 #endif
 
-    // Quirks mode support for various plugin mime types
-    enum PluginQuirks {
-        QUIRKS_NOT_INITIALIZED                          = 0,
-        // Silverlight assumes it is transparent in windowless mode. This quirk
-        // matches the logic in nsNPAPIPluginInstance::SetWindowless.
-        QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT           = 1 << 0,
-        // Win32: Hook TrackPopupMenu api so that we can swap out parent
-        // hwnds. The api will fail with parents not associated with our
-        // child ui thread. See WinlessHandleEvent for details.
-        QUIRK_WINLESS_TRACKPOPUP_HOOK                   = 1 << 1,
-        // Win32: Throttle flash WM_USER+1 heart beat messages to prevent
-        // flooding chromium's dispatch loop, which can cause ipc traffic
-        // processing lag.
-        QUIRK_FLASH_THROTTLE_WMUSER_EVENTS              = 1 << 2,
-        // Win32: Catch resets on our subclass by hooking SetWindowLong.
-        QUIRK_FLASH_HOOK_SETLONGPTR                     = 1 << 3,
-        // X11: Work around a bug in Flash up to 10.1 d51 at least, where
-        // expose event top left coordinates within the plugin-rect and
-        // not at the drawable origin are misinterpreted.
-        QUIRK_FLASH_EXPOSE_COORD_TRANSLATION            = 1 << 4,
-        // Win32: Catch get window info calls on the browser and tweak the
-        // results so mouse input works when flash is displaying it's settings
-        // window.
-        QUIRK_FLASH_HOOK_GETWINDOWINFO                  = 1 << 5,
-        // Win: Addresses a flash bug with mouse capture and full screen
-        // windows.
-        QUIRK_FLASH_FIXUP_MOUSE_CAPTURE                 = 1 << 6,
-        // Win: QuickTime steals focus on SetWindow calls even if it's hidden.
-        // Avoid calling SetWindow in that case.
-        QUIRK_QUICKTIME_AVOID_SETWINDOW                 = 1 << 7,
-        // Win: Check to make sure the parent window has focus before calling
-        // set focus on the child. Addresses a full screen dialog prompt
-        // problem in Silverlight.
-        QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT            = 1 << 8,
-        // Mac: Allow the plugin to use offline renderer mode.
-        // Use this only if the plugin is certified the support the offline renderer.
-        QUIRK_ALLOW_OFFLINE_RENDERER                    = 1 << 9,
-        // Mac: Work around a Flash bug that can cause plugin process crashes
-        // in CoreGraphics mode:  The Flash plugin sometimes accesses the
-        // CGContextRef we pass to it in NPP_HandleEvent(NPCocoaEventDrawRect)
-        // outside of that call.  See bug 804606.
-        QUIRK_FLASH_AVOID_CGMODE_CRASHES                = 1 << 10,
-        // Work around a Flash bug where it fails to check the error code of a
-        // NPN_GetValue(NPNVdocumentOrigin) call before trying to dereference
-        // its char* output.
-        QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN        = 1 << 11,
-        // Win: Addresses a Unity bug with mouse capture.
-        QUIRK_UNITY_FIXUP_MOUSE_CAPTURE                 = 1 << 12,
-    };
-
     int GetQuirks() { return mQuirks; }
 
     const PluginSettings& Settings() const { return mCachedSettings; }
 
 private:
     NPError DoNP_Initialize(const PluginSettings& aSettings);
     void AddQuirk(PluginQuirks quirk) {
       if (mQuirks == QUIRKS_NOT_INITIALIZED)
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -31,16 +31,17 @@
 #include "mozilla/unused.h"
 #include "nsAutoPtr.h"
 #include "nsCRT.h"
 #include "nsIFile.h"
 #include "nsIObserverService.h"
 #include "nsNPAPIPlugin.h"
 #include "nsPrintfCString.h"
 #include "prsystem.h"
+#include "PluginQuirks.h"
 #include "GeckoProfiler.h"
 #include "nsPluginTags.h"
 #include "nsUnicharUtils.h"
 
 #ifdef XP_WIN
 #include "mozilla/plugins/PluginSurfaceParent.h"
 #include "mozilla/widget/AudioSession.h"
 #include "PluginHangUIParent.h"
@@ -620,17 +621,18 @@ PluginModuleChromeParent::WaitForIPCConn
     process->SetCallRunnableImmediately(true);
     if (!process->WaitUntilConnected()) {
         return false;
     }
     return true;
 }
 
 PluginModuleParent::PluginModuleParent(bool aIsChrome)
-    : mIsChrome(aIsChrome)
+    : mQuirks(QUIRKS_NOT_INITIALIZED)
+    , mIsChrome(aIsChrome)
     , mShutdown(false)
     , mHadLocalInstance(false)
     , mClearSiteDataSupported(false)
     , mGetSitesWithDataSupported(false)
     , mNPNIface(nullptr)
     , mNPPIface(nullptr)
     , mPlugin(nullptr)
     , mTaskFactory(this)
@@ -1338,20 +1340,31 @@ PluginModuleParent::GetPluginDetails()
         return false;
     }
     nsPluginTag* pluginTag = host->TagForPlugin(mPlugin);
     if (!pluginTag) {
         return false;
     }
     mPluginName = pluginTag->Name();
     mPluginVersion = pluginTag->Version();
+    mPluginFilename = pluginTag->FileName();
     mIsFlashPlugin = pluginTag->mIsFlashPlugin;
     return true;
 }
 
+void
+PluginModuleParent::InitQuirksModes(const nsCString& aMimeType)
+{
+    if (mQuirks != QUIRKS_NOT_INITIALIZED) {
+      return;
+    }
+
+    mQuirks = GetQuirksFromMimeTypeAndFilename(aMimeType, mPluginFilename);
+}
+
 #ifdef XP_WIN
 void
 PluginModuleChromeParent::EvaluateHangUIState(const bool aReset)
 {
     int32_t minDispSecs = Preferences::GetInt(kHangUIMinDisplayPref, 10);
     int32_t autoStopSecs = Preferences::GetInt(kChildTimeoutPref, 0);
     int32_t timeoutSecs = 0;
     if (autoStopSecs > 0 && autoStopSecs < minDispSecs) {
@@ -2534,16 +2547,17 @@ PluginModuleParent::NPP_New(NPMIMEType p
             mSurrogateInstances.AppendElement(surrogate);
             *error = NPERR_NO_ERROR;
             return NS_PLUGIN_INIT_PENDING;
         }
     }
 
     if (mPluginName.IsEmpty()) {
         GetPluginDetails();
+        InitQuirksModes(nsDependentCString(pluginType));
         /** mTimeBlocked measures the time that the main thread has been blocked
          *  on plugin module initialization. As implemented, this is the sum of
          *  plugin-container launch + toolhelp32 snapshot + NP_Initialize.
          *  We don't accumulate its value until here because the plugin info
          *  is not available until *after* NP_Initialize.
          */
         Telemetry::Accumulate(Telemetry::BLOCKED_ON_PLUGIN_MODULE_INIT_MS,
                               GetHistogramKey(),
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -132,16 +132,18 @@ public:
         return mPluginName + mPluginVersion;
     }
 
     virtual nsresult GetRunID(uint32_t* aRunID) override;
     virtual void SetHasLocalInstance() override {
         mHadLocalInstance = true;
     }
 
+    int GetQuirks() { return mQuirks; }
+
 protected:
     virtual mozilla::ipc::RacyInterruptPolicy
     MediateInterruptRace(const Message& parent, const Message& child) override
     {
         return MediateRace(parent, child);
     }
 
     virtual bool
@@ -273,16 +275,20 @@ protected:
     virtual nsresult NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge,
                                        nsCOMPtr<nsIClearSiteDataCallback> callback) override;
     virtual nsresult NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback) override;
 
 private:
     std::map<uint64_t, nsCOMPtr<nsIClearSiteDataCallback>> mClearSiteDataCallbacks;
     std::map<uint64_t, nsCOMPtr<nsIGetSitesWithDataCallback>> mSitesWithDataCallbacks;
 
+    nsCString mPluginFilename;
+    int mQuirks;
+    void InitQuirksModes(const nsCString& aMimeType);
+
 public:
 
 #if defined(XP_MACOSX)
     virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing) override;
     virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor) override;
 #endif
 
     void InitAsyncSurrogates();
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/PluginQuirks.cpp
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * 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 "PluginQuirks.h"
+
+#include "nsPluginHost.h"
+
+namespace mozilla {
+namespace plugins {
+
+int GetQuirksFromMimeTypeAndFilename(const nsCString& aMimeType,
+                                     const nsCString& aPluginFilename)
+{
+    int quirks = 0;
+
+    nsPluginHost::SpecialType specialType = nsPluginHost::GetSpecialType(aMimeType);
+
+    if (specialType == nsPluginHost::eSpecialType_Silverlight) {
+        quirks |= QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT;
+#ifdef OS_WIN
+        quirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK;
+        quirks |= QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT;
+#endif
+    }
+
+    if (specialType == nsPluginHost::eSpecialType_Flash) {
+        quirks |= QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN;
+#ifdef OS_WIN
+        quirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK;
+        quirks |= QUIRK_FLASH_THROTTLE_WMUSER_EVENTS;
+        quirks |= QUIRK_FLASH_HOOK_SETLONGPTR;
+        quirks |= QUIRK_FLASH_HOOK_GETWINDOWINFO;
+        quirks |= QUIRK_FLASH_FIXUP_MOUSE_CAPTURE;
+#endif
+    }
+
+#ifdef OS_WIN
+    // QuickTime plugin usually loaded with audio/mpeg mimetype
+    NS_NAMED_LITERAL_CSTRING(quicktime, "npqtplugin");
+    if (FindInReadable(quicktime, aPluginFilename)) {
+        quirks |= QUIRK_QUICKTIME_AVOID_SETWINDOW;
+    }
+#endif
+
+#ifdef XP_MACOSX
+    // Whitelist Flash and Quicktime to support offline renderer
+    NS_NAMED_LITERAL_CSTRING(quicktime, "QuickTime Plugin.plugin");
+    if (specialType == nsPluginHost::eSpecialType_Flash) {
+        quirks |= QUIRK_FLASH_AVOID_CGMODE_CRASHES;
+        quirks |= QUIRK_ALLOW_OFFLINE_RENDERER;
+    } else if (FindInReadable(quicktime, aPluginFilename)) {
+        quirks |= QUIRK_ALLOW_OFFLINE_RENDERER;
+    }
+#endif
+
+#ifdef OS_WIN
+    if (specialType == nsPluginHost::eSpecialType_Unity) {
+        quirks |= QUIRK_UNITY_FIXUP_MOUSE_CAPTURE;
+    }
+#endif
+
+    return quirks;
+}
+
+} /* namespace plugins */
+} /* namespace mozilla */
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/PluginQuirks.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * 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 dom_plugins_PluginQuirks_h
+#define dom_plugins_PluginQuirks_h
+
+namespace mozilla {
+namespace plugins {
+
+// Quirks mode support for various plugin mime types
+enum PluginQuirks {
+  QUIRKS_NOT_INITIALIZED                          = 0,
+  // Silverlight assumes it is transparent in windowless mode. This quirk
+  // matches the logic in nsNPAPIPluginInstance::SetWindowless.
+  QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT           = 1 << 0,
+  // Win32: Hook TrackPopupMenu api so that we can swap out parent
+  // hwnds. The api will fail with parents not associated with our
+  // child ui thread. See WinlessHandleEvent for details.
+  QUIRK_WINLESS_TRACKPOPUP_HOOK                   = 1 << 1,
+  // Win32: Throttle flash WM_USER+1 heart beat messages to prevent
+  // flooding chromium's dispatch loop, which can cause ipc traffic
+  // processing lag.
+  QUIRK_FLASH_THROTTLE_WMUSER_EVENTS              = 1 << 2,
+  // Win32: Catch resets on our subclass by hooking SetWindowLong.
+  QUIRK_FLASH_HOOK_SETLONGPTR                     = 1 << 3,
+  // X11: Work around a bug in Flash up to 10.1 d51 at least, where
+  // expose event top left coordinates within the plugin-rect and
+  // not at the drawable origin are misinterpreted.
+  QUIRK_FLASH_EXPOSE_COORD_TRANSLATION            = 1 << 4,
+  // Win32: Catch get window info calls on the browser and tweak the
+  // results so mouse input works when flash is displaying it's settings
+  // window.
+  QUIRK_FLASH_HOOK_GETWINDOWINFO                  = 1 << 5,
+  // Win: Addresses a flash bug with mouse capture and full screen
+  // windows.
+  QUIRK_FLASH_FIXUP_MOUSE_CAPTURE                 = 1 << 6,
+  // Win: QuickTime steals focus on SetWindow calls even if it's hidden.
+  // Avoid calling SetWindow in that case.
+  QUIRK_QUICKTIME_AVOID_SETWINDOW                 = 1 << 7,
+  // Win: Check to make sure the parent window has focus before calling
+  // set focus on the child. Addresses a full screen dialog prompt
+  // problem in Silverlight.
+  QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT            = 1 << 8,
+  // Mac: Allow the plugin to use offline renderer mode.
+  // Use this only if the plugin is certified the support the offline renderer.
+  QUIRK_ALLOW_OFFLINE_RENDERER                    = 1 << 9,
+  // Mac: Work around a Flash bug that can cause plugin process crashes
+  // in CoreGraphics mode:  The Flash plugin sometimes accesses the
+  // CGContextRef we pass to it in NPP_HandleEvent(NPCocoaEventDrawRect)
+  // outside of that call.  See bug 804606.
+  QUIRK_FLASH_AVOID_CGMODE_CRASHES                = 1 << 10,
+  // Work around a Flash bug where it fails to check the error code of a
+  // NPN_GetValue(NPNVdocumentOrigin) call before trying to dereference
+  // its char* output.
+  QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN        = 1 << 11,
+  // Win: Addresses a Unity bug with mouse capture.
+  QUIRK_UNITY_FIXUP_MOUSE_CAPTURE                 = 1 << 12,
+};
+
+int GetQuirksFromMimeTypeAndFilename(const nsCString& aMimeType,
+                                     const nsCString& aPluginFilename);
+
+} /* namespace plugins */
+} /* namespace mozilla */
+
+#endif  // ifndef dom_plugins_PluginQuirks_h
--- a/dom/plugins/ipc/moz.build
+++ b/dom/plugins/ipc/moz.build
@@ -26,16 +26,17 @@ EXPORTS.mozilla.plugins += [
     'PluginDataResolver.h',
     'PluginInstanceChild.h',
     'PluginInstanceParent.h',
     'PluginMessageUtils.h',
     'PluginModuleChild.h',
     'PluginModuleParent.h',
     'PluginProcessChild.h',
     'PluginProcessParent.h',
+    'PluginQuirks.h',
     'PluginScriptableObjectChild.h',
     'PluginScriptableObjectParent.h',
     'PluginScriptableObjectUtils-inl.h',
     'PluginScriptableObjectUtils.h',
     'PluginStreamChild.h',
     'PluginStreamParent.h',
     'PluginUtilsOSX.h',
     'PluginWidgetChild.h',
@@ -81,16 +82,17 @@ UNIFIED_SOURCES += [
     'ChildTimer.cpp',
     'PluginAsyncSurrogate.cpp',
     'PluginBackgroundDestroyer.cpp',
     'PluginInstanceParent.cpp',
     'PluginMessageUtils.cpp',
     'PluginModuleParent.cpp',
     'PluginProcessChild.cpp',
     'PluginProcessParent.cpp',
+    'PluginQuirks.cpp',
     'PluginScriptableObjectChild.cpp',
     'PluginScriptableObjectParent.cpp',
     'PluginStreamChild.cpp',
     'PluginStreamParent.cpp',
 ]
 
 SOURCES += [
     'PluginInstanceChild.cpp', # 'PluginThreadCallback' : ambiguous symbol
--- a/dom/presentation/PresentationSession.cpp
+++ b/dom/presentation/PresentationSession.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/AsyncEventDispatcher.h"
+#include "mozilla/dom/MessageEvent.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsIDOMMessageEvent.h"
 #include "nsIPresentationService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStringStream.h"
 #include "PresentationSession.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -255,30 +255,26 @@ PresentationSession::DispatchMessageEven
 
   // Get the origin.
   nsAutoString origin;
   nsresult rv = nsContentUtils::GetUTFOrigin(global->PrincipalOrNull(), origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  rv = NS_NewDOMMessageEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
+  nsRefPtr<MessageEvent> messageEvent =
+    NS_NewDOMMessageEvent(this, nullptr, nullptr);
 
-  nsCOMPtr<nsIDOMMessageEvent> messageEvent = do_QueryInterface(event);
   rv = messageEvent->InitMessageEvent(NS_LITERAL_STRING("message"),
                                       false, false,
                                       aData,
                                       origin,
                                       EmptyString(), nullptr);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  event->SetTrusted(true);
+  messageEvent->SetTrusted(true);
 
   nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-    new AsyncEventDispatcher(this, event);
+    new AsyncEventDispatcher(this, static_cast<Event*>(messageEvent));
   return asyncDispatcher->PostDOMEvent();
 }
--- a/dom/smil/TimeEvent.cpp
+++ b/dom/smil/TimeEvent.cpp
@@ -75,19 +75,16 @@ TimeEvent::InitTimeEvent(const nsAString
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-nsresult
-NS_NewDOMTimeEvent(nsIDOMEvent** aInstancePtrResult,
-                   EventTarget* aOwner,
+already_AddRefed<TimeEvent>
+NS_NewDOMTimeEvent(EventTarget* aOwner,
                    nsPresContext* aPresContext,
                    InternalSMILTimeEvent* aEvent)
 {
-  TimeEvent* it = new TimeEvent(aOwner, aPresContext, aEvent);
-  NS_ADDREF(it);
-  *aInstancePtrResult = static_cast<Event*>(it);
-  return NS_OK;
+  nsRefPtr<TimeEvent> it = new TimeEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/smil/TimeEvent.h
+++ b/dom/smil/TimeEvent.h
@@ -58,9 +58,14 @@ private:
 
   nsCOMPtr<nsIDOMWindow> mView;
   int32_t mDetail;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::TimeEvent>
+NS_NewDOMTimeEvent(mozilla::dom::EventTarget* aOwner,
+                   nsPresContext* aPresContext,
+                   mozilla::InternalSMILTimeEvent* aEvent);
+
 #endif // mozilla_dom_TimeEvent_h_
--- a/dom/speakermanager/SpeakerManager.cpp
+++ b/dom/speakermanager/SpeakerManager.cpp
@@ -1,24 +1,27 @@
 /* -*- 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 "SpeakerManager.h"
+
+#include "mozilla/Services.h"
+
+#include "mozilla/dom/Event.h"
+
+#include "AudioChannelService.h"
+#include "nsIDocShell.h"
 #include "nsIDOMClassInfo.h"
-#include "nsIDOMEvent.h"
 #include "nsIDOMEventListener.h"
-#include "SpeakerManagerService.h"
+#include "nsIInterfaceRequestorUtils.h"
 #include "nsIPermissionManager.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "nsIDocShell.h"
-#include "AudioChannelService.h"
-#include "mozilla/Services.h"
+#include "SpeakerManagerService.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_QUERY_INTERFACE_INHERITED(SpeakerManager, DOMEventTargetHelper,
                                   nsIDOMEventListener)
 NS_IMPL_ADDREF_INHERITED(SpeakerManager, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(SpeakerManager, DOMEventTargetHelper)
@@ -81,22 +84,17 @@ void
 SpeakerManager::DispatchSimpleEvent(const nsAString& aStr)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to create the error event!!!");
-    return;
-  }
+  nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
   rv = event->InitEvent(aStr, false, false);
 
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to init the error event!!!");
     return;
   }
 
   event->SetTrusted(true);
--- a/dom/svg/SVGZoomEvent.cpp
+++ b/dom/svg/SVGZoomEvent.cpp
@@ -85,18 +85,19 @@ SVGZoomEvent::~SVGZoomEvent()
 
 } // namespace dom
 } // namespace mozilla
 
 
 ////////////////////////////////////////////////////////////////////////
 // Exported creation functions:
 
-nsresult
-NS_NewDOMSVGZoomEvent(nsIDOMEvent** aInstancePtrResult,
-                      mozilla::dom::EventTarget* aOwner,
+using namespace mozilla;
+using namespace mozilla::dom;
+
+already_AddRefed<SVGZoomEvent>
+NS_NewDOMSVGZoomEvent(EventTarget* aOwner,
                       nsPresContext* aPresContext,
                       mozilla::InternalSVGZoomEvent* aEvent)
 {
-  mozilla::dom::SVGZoomEvent* it =
-    new mozilla::dom::SVGZoomEvent(aOwner, aPresContext, aEvent);
-  return CallQueryInterface(it, aInstancePtrResult);
+  nsRefPtr<SVGZoomEvent> it = new SVGZoomEvent(aOwner, aPresContext, aEvent);
+  return it.forget();
 }
--- a/dom/svg/SVGZoomEvent.h
+++ b/dom/svg/SVGZoomEvent.h
@@ -66,9 +66,14 @@ private:
   float mNewScale;
   nsRefPtr<DOMSVGPoint> mPreviousTranslate;
   nsRefPtr<DOMSVGPoint> mNewTranslate;
 };
 
 } // namespace dom
 } // namespace mozilla
 
+already_AddRefed<mozilla::dom::SVGZoomEvent>
+NS_NewDOMSVGZoomEvent(mozilla::dom::EventTarget* aOwner,
+                      nsPresContext* aPresContext,
+                      mozilla::InternalSVGZoomEvent* aEvent);
+
 #endif // mozilla_dom_SVGZoomEvent_h
--- a/dom/tests/mochitest/pointerlock/mochitest.ini
+++ b/dom/tests/mochitest/pointerlock/mochitest.ini
@@ -16,9 +16,9 @@ support-files =
   file_targetOutOfFocus.html
   file_screenClientXYConst.html
   file_suppressSomeMouseEvents.html
   file_locksvgelement.html
   file_allowPointerLockSandboxFlag.html
   iframe_differentDOM.html
 
 [test_pointerlock-api.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || buildapp == 'mulet' || e10s # B2G - window.open focus issues using fullscreen
+skip-if = buildapp == 'b2g' || toolkit == 'android' || buildapp == 'mulet' || e10s || os == 'linux' || os == 'win' # B2G - window.open focus issues using fullscreen. (For Linux & Win) Bug1180351
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -1452,36 +1452,35 @@ RuntimeService::RegisterWorker(JSContext
   nsCString sharedWorkerScriptSpec;
 
   const bool isServiceWorker = aWorkerPrivate->IsServiceWorker();
   if (isServiceWorker) {
     AssertIsOnMainThread();
     Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_ATTEMPTS, 1);
   }
 
-  bool isSharedOrServiceWorker = aWorkerPrivate->IsSharedWorker() ||
-                                 aWorkerPrivate->IsServiceWorker();
-  if (isSharedOrServiceWorker) {
+  const bool isSharedWorker = aWorkerPrivate->IsSharedWorker();
+  if (isSharedWorker || isServiceWorker) {
     AssertIsOnMainThread();
 
     nsCOMPtr<nsIURI> scriptURI = aWorkerPrivate->GetResolvedScriptURI();
     NS_ASSERTION(scriptURI, "Null script URI!");
 
     nsresult rv = scriptURI->GetSpec(sharedWorkerScriptSpec);
     if (NS_FAILED(rv)) {
       NS_WARNING("GetSpec failed?!");
       xpc::Throw(aCx, rv);
       return false;
     }
 
     NS_ASSERTION(!sharedWorkerScriptSpec.IsEmpty(), "Empty spec!");
   }
 
   bool exemptFromPerDomainMax = false;
-  if (aWorkerPrivate->IsServiceWorker()) {
+  if (isServiceWorker) {
     AssertIsOnMainThread();
     exemptFromPerDomainMax = Preferences::GetBool("dom.serviceWorkers.exemptFromPerDomainMax",
                                                   false);
   }
 
   const nsCString& domain = aWorkerPrivate->Domain();
 
   WorkerDomainInfo* domainInfo;
@@ -1499,41 +1498,42 @@ RuntimeService::RegisterWorker(JSContext
 
     queued = gMaxWorkersPerDomain &&
              domainInfo->ActiveWorkerCount() >= gMaxWorkersPerDomain &&
              !domain.IsEmpty() &&
              !exemptFromPerDomainMax;
 
     if (queued) {
       domainInfo->mQueuedWorkers.AppendElement(aWorkerPrivate);
-      if (isServiceWorker) {
+      if (isServiceWorker || isSharedWorker) {
         AssertIsOnMainThread();
         // ServiceWorker spawn gets queued due to hitting max workers per domain
         // limit so let's log a warning.
         // Note: aWorkerPrivate->GetDocument() call might result nullptr due to
         // no window so the message warning will show up in the browser console.
         nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                         NS_LITERAL_CSTRING("DOM"),
                                         aWorkerPrivate->GetDocument(),
                                         nsContentUtils::eDOM_PROPERTIES,
                                         "HittingMaxWorkersPerDomain");
-        Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_GETS_QUEUED, 1);
+        Telemetry::Accumulate(isSharedWorker ? Telemetry::SHARED_WORKER_SPAWN_GETS_QUEUED
+                                             : Telemetry::SERVICE_WORKER_SPAWN_GETS_QUEUED, 1);
       }
     }
     else if (parent) {
       domainInfo->mChildWorkerCount++;
     }
     else if (isServiceWorker) {
       domainInfo->mActiveServiceWorkers.AppendElement(aWorkerPrivate);
     }
     else {
       domainInfo->mActiveWorkers.AppendElement(aWorkerPrivate);
     }
 
-    if (isSharedOrServiceWorker) {
+    if (isSharedWorker || isServiceWorker) {
       const nsCString& sharedWorkerName = aWorkerPrivate->SharedWorkerName();
       const nsCString& cacheName =
         aWorkerPrivate->IsServiceWorker() ?
           NS_ConvertUTF16toUTF8(aWorkerPrivate->ServiceWorkerCacheName()) :
           EmptyCString();
 
       nsAutoCString key;
       GenerateSharedWorkerKey(sharedWorkerScriptSpec, sharedWorkerName,
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -2369,24 +2369,20 @@ public:
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     MOZ_ASSERT(aWorkerPrivate);
 
     WorkerGlobalScope* globalScope = aWorkerPrivate->GlobalScope();
 
-    nsCOMPtr<nsIDOMEvent> event;
-    nsresult rv =
-      NS_NewDOMEvent(getter_AddRefs(event), globalScope, nullptr, nullptr);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return false;
-    }
-
-    rv = event->InitEvent(NS_LITERAL_STRING("pushsubscriptionchange"), false, false);
+    nsRefPtr<Event> event = NS_NewDOMEvent(globalScope, nullptr, nullptr);
+
+    nsresult rv = event->InitEvent(NS_LITERAL_STRING("pushsubscriptionchange"),
+                                   false, false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return false;
     }
 
     event->SetTrusted(true);
 
     globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
     return true;
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1043,25 +1043,19 @@ private:
   {
     JS::Rooted<JSObject*> target(aCx, JS::CurrentGlobalOrNull(aCx));
     NS_ASSERTION(target, "This must never be null!");
 
     aWorkerPrivate->CloseHandlerStarted();
 
     WorkerGlobalScope* globalScope = aWorkerPrivate->GlobalScope();
 
-    nsCOMPtr<nsIDOMEvent> event;
-    nsresult rv =
-      NS_NewDOMEvent(getter_AddRefs(event), globalScope, nullptr, nullptr);
-    if (NS_FAILED(rv)) {
-      Throw(aCx, rv);
-      return false;
-    }
-
-    rv = event->InitEvent(NS_LITERAL_STRING("close"), false, false);
+    nsRefPtr<Event> event = NS_NewDOMEvent(globalScope, nullptr, nullptr);
+
+    nsresult rv = event->InitEvent(NS_LITERAL_STRING("close"), false, false);
     if (NS_FAILED(rv)) {
       Throw(aCx, rv);
       return false;
     }
 
     event->SetTrusted(true);
 
     globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
@@ -3614,22 +3608,19 @@ WorkerPrivate::OfflineStatusChangeEventI
 
   nsString eventType;
   if (aIsOffline) {
     eventType.AssignLiteral("offline");
   } else {
     eventType.AssignLiteral("online");
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
-  nsresult rv =
-    NS_NewDOMEvent(getter_AddRefs(event), globalScope, nullptr, nullptr);
-  NS_ENSURE_SUCCESS_VOID(rv);
-
-  rv = event->InitEvent(eventType, false, false);
+  nsRefPtr<Event> event = NS_NewDOMEvent(globalScope, nullptr, nullptr);
+
+  nsresult rv = event->InitEvent(eventType, false, false);
   NS_ENSURE_SUCCESS_VOID(rv);
 
   event->SetTrusted(true);
 
   globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
 template <class Derived>
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -1390,29 +1390,29 @@ EventRunnable::WorkerRun(JSContext* aCx,
     target = xhr->GetUploadObjectNoCreate();
   }
   else {
     target = xhr;
   }
 
   MOZ_ASSERT(target);
 
-  nsCOMPtr<nsIDOMEvent> event;
+  nsRefPtr<Event> event;
   if (mProgressEvent) {
     ProgressEventInit init;
     init.mBubbles = false;
     init.mCancelable = false;
     init.mLengthComputable = mLengthComputable;
     init.mLoaded = mLoaded;
     init.mTotal = mTotal;
 
     event = ProgressEvent::Constructor(target, mType, init);
   }
   else {
-    NS_NewDOMEvent(getter_AddRefs(event), target, nullptr, nullptr);
+    event = NS_NewDOMEvent(target, nullptr, nullptr);
 
     if (event) {
       event->InitEvent(mType, false, false);
     }
   }
 
   if (!event) {
     return false;
@@ -1791,23 +1791,20 @@ XMLHttpRequest::DispatchPrematureAbortEv
   mWorkerPrivate->AssertIsOnWorkerThread();
   MOZ_ASSERT(aTarget);
 
   if (!mProxy) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  nsCOMPtr<nsIDOMEvent> event;
+  nsRefPtr<Event> event;
   if (aEventType.EqualsLiteral("readystatechange")) {
-    NS_NewDOMEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
-
-    if (event) {
-      event->InitEvent(aEventType, false, false);
-    }
+    event = NS_NewDOMEvent(aTarget, nullptr, nullptr);
+    event->InitEvent(aEventType, false, false);
   }
   else {
     ProgressEventInit init;
     init.mBubbles = false;
     init.mCancelable = false;
     if (aUploadTarget) {
       init.mLengthComputable = mProxy->mLastUploadLengthComputable;
       init.mLoaded = mProxy->mLastUploadLoaded;
--- a/dom/workers/test/serviceworkers/fetch/index.html
+++ b/dom/workers/test/serviceworkers/fetch/index.html
@@ -113,16 +113,43 @@
     elem.id = 'intercepted-iframe';
     elem.src = "nonexistent_page.html";
     return elem;
   }, function() {
     my_ok(this.test_result, "iframe load should be intercepted");
   });
 
   gExpected++;
+  var xmlDoc = document.implementation.createDocument(null, null, null);
+  xmlDoc.load('load_cross_origin_xml_document_synthetic.xml');
+  xmlDoc.onload = function(evt) {
+    var content = new XMLSerializer().serializeToString(evt.target);
+    my_ok(!content.includes('parsererror'), "Load synthetic cross origin XML Document should be allowed");
+    finish();
+  };
+
+  gExpected++;
+  var xmlDoc = document.implementation.createDocument(null, null, null);
+  xmlDoc.load('load_cross_origin_xml_document_cors.xml');
+  xmlDoc.onload = function(evt) {
+    var content = new XMLSerializer().serializeToString(evt.target);
+    my_ok(!content.includes('parsererror'), "Load CORS cross origin XML Document should be allowed");
+    finish();
+  };
+
+  gExpected++;
+  var xmlDoc = document.implementation.createDocument(null, null, null);
+  xmlDoc.load('load_cross_origin_xml_document_opaque.xml');
+  xmlDoc.onload = function(evt) {
+    var content = new XMLSerializer().serializeToString(evt.target);
+    my_ok(content.includes('parsererror'), "Load opaque cross origin XML Document should not be allowed");
+    finish();
+  };
+
+  gExpected++;
   var worker = new Worker('nonexistent_worker_script.js');
   worker.onmessage = function(e) {
     my_ok(e.data == "worker-intercept-success", "worker load intercepted");
     finish();
   };
   worker.onerror = function() {
     my_ok(false, "worker load should be intercepted");
   };
--- a/dom/workers/test/serviceworkers/fetch_event_worker.js
+++ b/dom/workers/test/serviceworkers/fetch_event_worker.js
@@ -230,9 +230,42 @@ onfetch = function(ev) {
 
   else if (ev.request.url.includes('redirect_serviceworker.sjs')) {
     // The redirect_serviceworker.sjs server-side JavaScript file redirects to
     // 'http://mochi.test:8888/tests/dom/workers/test/serviceworkers/worker.js'
     // The redirected fetch should not go through the SW since the original
     // fetch was initiated from a SW.
     ev.respondWith(fetch('redirect_serviceworker.sjs'));
   }
+
+  else if (ev.request.url.includes('load_cross_origin_xml_document_synthetic.xml')) {
+    if (ev.request.mode != 'same-origin') {
+      ev.respondWith(Promise.reject());
+      return;
+    }
+
+    ev.respondWith(Promise.resolve(
+      new Response("<response>body</response>", { headers: {'Content-Type': 'text/xtml'}})
+    ));
+  }
+
+  else if (ev.request.url.includes('load_cross_origin_xml_document_cors.xml')) {
+    if (ev.request.mode != 'same-origin') {
+      ev.respondWith(Promise.reject());
+      return;
+    }
+
+    var url = 'http://example.com/tests/dom/security/test/cors/file_CrossSiteXHR_server.sjs?status=200&allowOrigin=*';
+    ev.respondWith(fetch(url, { mode: 'cors' }));
+  }
+
+  else if (ev.request.url.includes('load_cross_origin_xml_document_opaque.xml')) {
+    if (ev.request.mode != 'same-origin') {
+      Promise.resolve(
+        new Response("<error>Invalid Request mode</error>", { headers: {'Content-Type': 'text/xtml'}})
+      );
+      return;
+    }
+
+    var url = 'http://example.com/tests/dom/security/test/cors/file_CrossSiteXHR_server.sjs?status=200';
+    ev.respondWith(fetch(url, { mode: 'no-cors' }));
+  }
 };
--- a/dom/xml/XMLDocument.cpp
+++ b/dom/xml/XMLDocument.cpp
@@ -17,17 +17,17 @@
 #include "nsHTMLParts.h"
 #include "nsIComponentManager.h"
 #include "nsIDOMElement.h"
 #include "nsIBaseWindow.h"
 #include "nsIDOMWindow.h"
 #include "nsIDOMDocumentType.h"
 #include "nsCOMPtr.h"
 #include "nsXPIDLString.h"
-#include "nsIHttpChannel.h"
+#include "nsIHttpChannelInternal.h"
 #include "nsIURI.h"
 #include "nsIServiceManager.h"
 #include "nsNetUtil.h"
 #include "nsError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsLayoutCID.h"
 #include "mozilla/dom/Attr.h"
@@ -416,16 +416,24 @@ XMLDocument::Load(const nsAString& aUrl,
                      req,
                      nsIRequest::LOAD_BACKGROUND);
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return false;
   }
 
+  // TODO Bug 1189945: Remove nsIChannel CorsMode flag and set Request.mode
+  // based on nsILoadInfo securityFlags instead. This block will be removed
+  // when Request.mode set correctly.
+  nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(channel);
+  if (httpChannel) {
+    httpChannel->SetCorsMode(nsIHttpChannelInternal::CORS_MODE_SAME_ORIGIN);
+  }
+
   // StartDocumentLoad asserts that readyState is uninitialized, so
   // uninitialize it. SetReadyStateInternal make this transition invisible to
   // Web content. But before doing that, assert that the current readyState
   // is complete as it should be after the call to ResetToURI() above.
   MOZ_ASSERT(GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE,
              "Bad readyState");
   SetReadyStateInternal(nsIDocument::READYSTATE_UNINITIALIZED);
 
--- a/dom/xml/nsXMLPrettyPrinter.cpp
+++ b/dom/xml/nsXMLPrettyPrinter.cpp
@@ -18,17 +18,17 @@
 #include "mozilla/dom/Element.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsBindingManager.h"
 #include "nsXBLService.h"
 #include "nsIScriptSecurityManager.h"
 #include "mozilla/Preferences.h"
 #include "nsIDocument.h"
 #include "nsVariant.h"
-#include "nsIDOMCustomEvent.h"
+#include "mozilla/dom/CustomEvent.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS(nsXMLPrettyPrinter,
                   nsIDocumentObserver,
                   nsIMutationObserver)
 
@@ -151,32 +151,29 @@ nsXMLPrettyPrinter::PrettyPrint(nsIDocum
     // Load the bindings.
     nsRefPtr<nsXBLBinding> unused;
     bool ignored;
     rv = xblService->LoadBindings(rootCont, bindingUri, sysPrincipal,
                                   getter_AddRefs(unused), &ignored);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Fire an event at the bound element to pass it |resultFragment|.
-    nsCOMPtr<nsIDOMEvent> domEvent;
-    rv = NS_NewDOMCustomEvent(getter_AddRefs(domEvent), rootCont,
-                              nullptr, nullptr);
-    NS_ENSURE_SUCCESS(rv, rv);
-    nsCOMPtr<nsIDOMCustomEvent> customEvent = do_QueryInterface(domEvent);
-    MOZ_ASSERT(customEvent);
+    nsRefPtr<CustomEvent> event =
+      NS_NewDOMCustomEvent(rootCont, nullptr, nullptr);
+    MOZ_ASSERT(event);
     nsCOMPtr<nsIWritableVariant> resultFragmentVariant = new nsVariant();
     rv = resultFragmentVariant->SetAsISupports(resultFragment);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
-    rv = customEvent->InitCustomEvent(NS_LITERAL_STRING("prettyprint-dom-created"),
-                                      /* bubbles = */ false, /* cancelable = */ false,
-                                      /* detail = */ resultFragmentVariant);
+    rv = event->InitCustomEvent(NS_LITERAL_STRING("prettyprint-dom-created"),
+                                /* bubbles = */ false, /* cancelable = */ false,
+                                /* detail = */ resultFragmentVariant);
     NS_ENSURE_SUCCESS(rv, rv);
-    customEvent->SetTrusted(true);
+    event->SetTrusted(true);
     bool dummy;
-    rv = rootCont->DispatchEvent(domEvent, &dummy);
+    rv = rootCont->DispatchEvent(static_cast<Event*>(event), &dummy);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Observe the document so we know when to switch to "normal" view
     aDocument->AddObserver(this);
     mDocument = aDocument;
 
     NS_ADDREF_THIS();
 
--- a/js/public/TraceKind.h
+++ b/js/public/TraceKind.h
@@ -93,17 +93,19 @@ JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
 // Downcast the |void *thing| to the specific type designated by |traceKind|,
 // and pass it to the functor |f| along with |... args|, forwarded. Pass the
 // type designated by |traceKind| as the functor's template argument. The
 // |thing| parameter is optional; without it, we simply pass through |... args|.
 
 // GCC and Clang require an explicit template declaration in front of the
 // specialization of operator() because it is a dependent template. MSVC, on
 // the other hand, gets very confused if we have a |template| token there.
-#ifdef _MSC_VER
+// The clang-cl front end defines _MSC_VER, but still requires the explicit
+// template declaration, so we must test for __clang__ here as well.
+#if defined(_MSC_VER) && !defined(__clang__)
 # define JS_DEPENDENT_TEMPLATE_HINT
 #else
 # define JS_DEPENDENT_TEMPLATE_HINT template
 #endif
 template <typename F, typename... Args>
 auto
 DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args)
   -> decltype(f. JS_DEPENDENT_TEMPLATE_HINT operator()<JSObject>(mozilla::Forward<Args>(args)...))
--- a/js/src/asmjs/AsmJSFrameIterator.cpp
+++ b/js/src/asmjs/AsmJSFrameIterator.cpp
@@ -131,17 +131,17 @@ static const unsigned PushedRetAddr = 4;
 static const unsigned PushedFP = 16;
 static const unsigned StoredFP = 20;
 static const unsigned PostStorePrePopFP = 4;
 #elif defined(JS_CODEGEN_ARM64)
 static const unsigned PushedRetAddr = 0;
 static const unsigned PushedFP = 0;
 static const unsigned StoredFP = 0;
 static const unsigned PostStorePrePopFP = 0;
-#elif defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS32)
 static const unsigned PushedRetAddr = 8;
 static const unsigned PushedFP = 24;
 static const unsigned StoredFP = 28;
 static const unsigned PostStorePrePopFP = 4;
 #elif defined(JS_CODEGEN_NONE)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
 static const unsigned PostStorePrePopFP = 0;
@@ -152,17 +152,17 @@ static const unsigned StoredFP = 1;
 # error "Unknown architecture!"
 #endif
 
 static void
 PushRetAddr(MacroAssembler& masm)
 {
 #if defined(JS_CODEGEN_ARM)
     masm.push(lr);
-#elif defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS32)
     masm.push(ra);
 #else
     // The x86/x64 call instruction pushes the return address.
 #endif
 }
 
 // Generate a prologue that maintains AsmJSActivation::fp as the virtual frame
 // pointer so that AsmJSProfilingFrameIterator can walk the stack at any pc in
@@ -216,17 +216,17 @@ GenerateProfilingPrologue(MacroAssembler
 }
 
 // Generate the inverse of GenerateProfilingPrologue.
 static void
 GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, AsmJSExit::Reason reason,
                           Label* profilingReturn)
 {
     Register scratch = ABIArgGenerator::NonReturn_VolatileReg0;
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32)
     Register scratch2 = ABIArgGenerator::NonReturn_VolatileReg1;
 #endif
 
     if (framePushed)
         masm.addToStackPtr(Imm32(framePushed));
 
     masm.loadAsmJSActivation(scratch);
 
@@ -240,17 +240,17 @@ GenerateProfilingEpilogue(MacroAssembler
 #if defined(JS_CODEGEN_ARM)
         AutoForbidPools afp(&masm, /* number of instructions in scope = */ 4);
 #endif
 
         // sp protects the stack from clobber via asynchronous signal handlers
         // and the async interrupt exit. Since activation.fp can be read at any
         // time and still points to the current frame, be careful to only update
         // sp after activation.fp has been repointed to the caller's frame.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32)
         masm.loadPtr(Address(masm.getStackPointer(), 0), scratch2);
         masm.storePtr(scratch2, Address(scratch, AsmJSActivation::offsetOfFP()));
         DebugOnly<uint32_t> prePop = masm.currentOffset();
         masm.addToStackPtr(Imm32(sizeof(void *)));
         MOZ_ASSERT(PostStorePrePopFP == masm.currentOffset() - prePop);
 #else
         masm.pop(Address(scratch, AsmJSActivation::offsetOfFP()));
         MOZ_ASSERT(PostStorePrePopFP == 0);
@@ -334,17 +334,17 @@ js::GenerateAsmJSFunctionEpilogue(MacroA
 
         // The exact form of this instruction must be kept consistent with the
         // patching in AsmJSModule::setProfilingEnabled.
         masm.bind(&labels->profilingJump);
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
         masm.twoByteNop();
 #elif defined(JS_CODEGEN_ARM)
         masm.nop();
-#elif defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS32)
         masm.nop();
         masm.nop();
         masm.nop();
         masm.nop();
 #endif
     }
 
     // Normal epilogue:
@@ -561,17 +561,17 @@ AsmJSProfilingFrameIterator::AsmJSProfil
         // innermost call. To avoid this problem, we use the static structure of
         // the code in the prologue and epilogue to do the Right Thing.
         uint32_t offsetInModule = (uint8_t*)state.pc - module_->codeBase();
         MOZ_ASSERT(offsetInModule < module_->codeBytes());
         MOZ_ASSERT(offsetInModule >= codeRange->begin());
         MOZ_ASSERT(offsetInModule < codeRange->end());
         uint32_t offsetInCodeRange = offsetInModule - codeRange->begin();
         void** sp = (void**)state.sp;
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
         if (offsetInCodeRange < PushedRetAddr) {
             // First instruction of the ARM/MIPS function; the return address is
             // still in lr and fp still holds the caller's fp.
             callerPC_ = state.lr;
             callerFP_ = fp;
             AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, sp - 2);
         } else if (offsetInModule == codeRange->profilingReturn() - PostStorePrePopFP) {
             // Second-to-last instruction of the ARM/MIPS function; fp points to
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -284,17 +284,17 @@ AsmJSModule::lookupHeapAccess(void* pc) 
 bool
 AsmJSModule::finish(ExclusiveContext* cx, TokenStream& tokenStream, MacroAssembler& masm,
                     const Label& interruptLabel, const Label& outOfBoundsLabel)
 {
     MOZ_ASSERT(isFinishedWithFunctionBodies() && !isFinished());
 
     uint32_t endBeforeCurly = tokenStream.currentToken().pos.end;
     TokenPos pos;
-    if (!tokenStream.peekTokenPos(&pos))
+    if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
         return false;
     uint32_t endAfterCurly = pos.end;
     MOZ_ASSERT(endBeforeCurly >= srcBodyStart_);
     MOZ_ASSERT(endAfterCurly >= srcBodyStart_);
     pod.srcLength_ = endBeforeCurly - srcStart_;
     pod.srcLengthWithRightBrace_ = endAfterCurly - srcStart_;
 
     // Start global data on a new page so JIT code may be given independent
@@ -400,17 +400,17 @@ AsmJSModule::finish(ExclusiveContext* cx
         RelativeLink link(RelativeLink::InstructionImmediate);
         link.patchAtOffset = masm.labelOffsetToPatchOffset(a.patchAt.offset());
         link.targetOffset = offsetOfGlobalData() + a.globalDataOffset;
         if (!staticLinkData_.relativeLinks.append(link))
             return false;
     }
 #endif
 
-#if defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_MIPS32)
     // On MIPS we need to update all the long jumps because they contain an
     // absolute adress.
     for (size_t i = 0; i < masm.numLongJumps(); i++) {
         RelativeLink link(RelativeLink::InstructionImmediate);
         link.patchAtOffset = masm.longJump(i);
         InstImm* inst = (InstImm*)(code_ + masm.longJump(i));
         link.targetOffset = Assembler::ExtractLuiOriValue(inst, inst->next()) - (uint32_t)code_;
         if (!staticLinkData_.relativeLinks.append(link))
@@ -867,17 +867,17 @@ AsmJSModule::initHeap(Handle<ArrayBuffer
     // CodeGeneratorX64::visitAsmJS{Load,Store,CompareExchange,Exchange,AtomicBinop}Heap)
     uint32_t heapLength = heap->byteLength();
     for (size_t i = 0; i < heapAccesses_.length(); i++) {
         const jit::AsmJSHeapAccess& access = heapAccesses_[i];
         // See comment above for x86 codegen.
         if (access.hasLengthCheck())
             X86Encoding::AddInt32(access.patchLengthAt(code_), heapLength);
     }
-#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
     uint32_t heapLength = heap->byteLength();
     for (unsigned i = 0; i < heapAccesses_.length(); i++) {
         jit::Assembler::UpdateBoundsCheck(heapLength,
                                           (jit::Instruction*)(heapAccesses_[i].insnOffset() + code_));
     }
 #endif
 }
 
@@ -1798,17 +1798,17 @@ AsmJSModule::setProfilingEnabled(bool en
         uint8_t* caller = callerRetAddr - 4;
         Instruction* callerInsn = reinterpret_cast<Instruction*>(caller);
         BOffImm calleeOffset;
         callerInsn->as<InstBLImm>()->extractImm(&calleeOffset);
         void* callee = calleeOffset.getDest(callerInsn);
 #elif defined(JS_CODEGEN_ARM64)
         MOZ_CRASH();
         void* callee = nullptr;
-#elif defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS32)
         Instruction* instr = (Instruction*)(callerRetAddr - 4 * sizeof(uint32_t));
         void* callee = (void*)Assembler::ExtractLuiOriValue(instr, instr->next());
 #elif defined(JS_CODEGEN_NONE)
         MOZ_CRASH();
         void* callee = nullptr;
 #else
 # error "Missing architecture"
 #endif
@@ -1824,17 +1824,17 @@ AsmJSModule::setProfilingEnabled(bool en
         uint8_t* newCallee = enabled ? profilingEntry : entry;
 
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
         X86Encoding::SetRel32(callerRetAddr, newCallee);
 #elif defined(JS_CODEGEN_ARM)
         new (caller) InstBLImm(BOffImm(newCallee - caller), Assembler::Always);
 #elif defined(JS_CODEGEN_ARM64)
         MOZ_CRASH();
-#elif defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS32)
         Assembler::WriteLuiOriInstructions(instr, instr->next(),
                                            ScratchRegister, (uint32_t)newCallee);
         instr[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
 #elif defined(JS_CODEGEN_NONE)
         MOZ_CRASH();
 #else
 # error "Missing architecture"
 #endif
@@ -1889,17 +1889,17 @@ AsmJSModule::setProfilingEnabled(bool en
             MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstNOP>());
             new (jump) InstBImm(BOffImm(profilingEpilogue - jump), Assembler::Always);
         } else {
             MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstBImm>());
             new (jump) InstNOP();
         }
 #elif defined(JS_CODEGEN_ARM64)
         MOZ_CRASH();
-#elif defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS32)
         Instruction* instr = (Instruction*)jump;
         if (enabled) {
             Assembler::WriteLuiOriInstructions(instr, instr->next(),
                                                ScratchRegister, (uint32_t)profilingEpilogue);
             instr[2] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr);
         } else {
             instr[0].makeNop();
             instr[1].makeNop();
@@ -1955,17 +1955,17 @@ GetCPUID(uint32_t* cpuId)
 #elif defined(JS_CODEGEN_X64)
     MOZ_ASSERT(uint32_t(CPUInfo::GetSSEVersion()) <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = X64 | (uint32_t(CPUInfo::GetSSEVersion()) << ARCH_BITS);
     return true;
 #elif defined(JS_CODEGEN_ARM)
     MOZ_ASSERT(GetARMFlags() <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = ARM | (GetARMFlags() << ARCH_BITS);
     return true;
-#elif defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS32)
     MOZ_ASSERT(GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = MIPS | (GetMIPSFlags() << ARCH_BITS);
     return true;
 #else
     return false;
 #endif
 }
 
@@ -2041,17 +2041,17 @@ class ModuleChars
 
   public:
     static uint32_t beginOffset(AsmJSParser& parser) {
         return parser.pc->maybeFunction->pn_pos.begin;
     }
 
     static uint32_t endOffset(AsmJSParser& parser) {
         TokenPos pos(0, 0);  // initialize to silence GCC warning
-        MOZ_ALWAYS_TRUE(parser.tokenStream.peekTokenPos(&pos));
+        MOZ_ALWAYS_TRUE(parser.tokenStream.peekTokenPos(&pos, TokenStream::Operand));
         return pos.end;
     }
 };
 
 class ModuleCharsForStore : ModuleChars
 {
     uint32_t uncompressedSize_;
     uint32_t compressedSize_;
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -725,35 +725,35 @@ class AsmJSModule
             InstructionImmediate
         };
 
         RelativeLink()
         { }
 
         explicit RelativeLink(Kind kind)
         {
-#if defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_MIPS32)
             kind_ = kind;
 #elif defined(JS_CODEGEN_ARM)
             // On ARM, CodeLabels are only used to label raw pointers, so in
             // all cases on ARM, a RelativePatch means patching a raw pointer.
             MOZ_ASSERT(kind == CodeLabel || kind == RawPointer);
 #endif
             // On X64 and X86, all RelativePatch-es are patched as raw pointers.
         }
 
         bool isRawPointerPatch() {
-#if defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_MIPS32)
             return kind_ == RawPointer;
 #else
             return true;
 #endif
         }
 
-#ifdef JS_CODEGEN_MIPS
+#ifdef JS_CODEGEN_MIPS32
         Kind kind_;
 #endif
         uint32_t patchAtOffset;
         uint32_t targetOffset;
     };
 
     typedef Vector<RelativeLink, 0, SystemAllocPolicy> RelativeLinkVector;
 
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -480,17 +480,17 @@ PeekToken(AsmJSParser& parser, TokenKind
 {
     TokenStream& ts = parser.tokenStream;
     TokenKind tk;
     while (true) {
         if (!ts.peekToken(&tk, TokenStream::Operand))
             return false;
         if (tk != TOK_SEMI)
             break;
-        ts.consumeKnownToken(TOK_SEMI);
+        ts.consumeKnownToken(TOK_SEMI, TokenStream::Operand);
     }
     *tkp = tk;
     return true;
 }
 
 static bool
 ParseVarOrConstStatement(AsmJSParser& parser, ParseNode** var)
 {
@@ -1600,17 +1600,18 @@ class MOZ_STACK_CLASS ModuleCompiler
             return failOffset(pn->pn_pos.begin, str);
 
         // The exact rooting static analysis does not perform dataflow analysis, so it believes
         // that unrooted things on the stack during compilation may still be accessed after this.
         // Since pn is typically only null under OOM, this suppression simply forces any GC to be
         // delayed until the compilation is off the stack and more memory can be freed.
         gc::AutoSuppressGC nogc(cx_);
         TokenPos pos;
-        if (!tokenStream().peekTokenPos(&pos))
+        TokenStream::Modifier modifier = tokenStream().hasLookahead() ? tokenStream().getLookaheadModifier() : TokenStream::None;
+        if (!tokenStream().peekTokenPos(&pos, modifier))
             return false;
         return failOffset(pos.begin, str);
     }
 
     bool failfVA(ParseNode* pn, const char* fmt, va_list ap) {
         MOZ_ASSERT(!errorString_);
         MOZ_ASSERT(errorOffset_ == UINT32_MAX);
         MOZ_ASSERT(fmt);
@@ -4906,17 +4907,17 @@ CheckModuleGlobal(ModuleCompiler& m, Par
 }
 
 static bool
 CheckModuleProcessingDirectives(ModuleCompiler& m)
 {
     TokenStream& ts = m.parser().tokenStream;
     while (true) {
         bool matched;
-        if (!ts.matchToken(&matched, TOK_STRING))
+        if (!ts.matchToken(&matched, TOK_STRING, TokenStream::Operand))
             return false;
         if (!matched)
             return true;
 
         if (!IsIgnoredDirectiveName(m.cx(), ts.currentToken().atom()))
             return m.fail(nullptr, "unsupported processing directive");
 
         if (!ts.matchToken(&matched, TOK_SEMI))
@@ -9772,22 +9773,22 @@ CheckChangeHeap(ModuleCompiler& m, Parse
     return m.addChangeHeap(changeHeapName, fn, mask, min, max);
 }
 
 static bool
 ParseFunction(ModuleCompiler& m, ParseNode** fnOut)
 {
     TokenStream& tokenStream = m.tokenStream();
 
-    tokenStream.consumeKnownToken(TOK_FUNCTION);
+    tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand);
 
     RootedPropertyName name(m.cx());
 
     TokenKind tk;
-    if (!tokenStream.getToken(&tk))
+    if (!tokenStream.getToken(&tk, TokenStream::Operand))
         return false;
     if (tk == TOK_NAME) {
         name = tokenStream.currentName();
     } else if (tk == TOK_YIELD) {
         if (!m.parser().checkYieldNameValidity())
             return false;
         name = m.cx()->names().yield;
     } else {
@@ -10889,17 +10890,17 @@ static const LiveRegisterSet NonVolatile
                                      | (1ULL << FloatRegisters::d15)
                                      | (1ULL << FloatRegisters::s31)));
 #else
 static const LiveRegisterSet NonVolatileRegs =
     LiveRegisterSet(GeneralRegisterSet(Registers::NonVolatileMask),
                     FloatRegisterSet(FloatRegisters::NonVolatileMask));
 #endif
 
-#if defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_MIPS32)
 // Mips is using one more double slot due to stack alignment for double values.
 // Look at MacroAssembler::PushRegsInMask(RegisterSet set)
 static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
                                              NonVolatileRegs.fpus().getPushSizeInBytes() +
                                              sizeof(double);
 #elif defined(JS_CODEGEN_NONE)
 static const unsigned FramePushedAfterSave = 0;
 #else
@@ -10915,32 +10916,32 @@ GenerateEntry(ModuleCompiler& m, unsigne
 
     Label begin;
     masm.haltingAlign(CodeAlignment);
     masm.bind(&begin);
 
     // Save the return address if it wasn't already saved by the call insn.
 #if defined(JS_CODEGEN_ARM)
     masm.push(lr);
-#elif defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS32)
     masm.push(ra);
 #elif defined(JS_CODEGEN_X86)
     static const unsigned EntryFrameSize = sizeof(void*);
 #endif
 
     // Save all caller non-volatile registers before we clobber them here and in
     // the asm.js callee (which does not preserve non-volatile registers).
     masm.setFramePushed(0);
     masm.PushRegsInMask(NonVolatileRegs);
     MOZ_ASSERT(masm.framePushed() == FramePushedAfterSave);
 
     // ARM and MIPS have a globally-pinned GlobalReg (x64 uses RIP-relative
     // addressing, x86 uses immediates in effective addresses). For the
     // AsmJSGlobalRegBias addition, see Assembler-(mips,arm).h.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
     masm.movePtr(IntArgReg1, GlobalReg);
     masm.addPtr(Imm32(AsmJSGlobalRegBias), GlobalReg);
 #endif
 
     // ARM, MIPS and x64 have a globally-pinned HeapReg (x86 uses immediates in
     // effective addresses). Loading the heap register depends on the global
     // register already having been loaded.
     masm.loadAsmJSHeapRegisterFromGlobalData();
@@ -11234,17 +11235,17 @@ GenerateFFIInterpExit(ModuleCompiler& m,
     masm.loadAsmJSHeapRegisterFromGlobalData();
     GenerateCheckForHeapDetachment(m, ABIArgGenerator::NonReturn_VolatileReg0);
 
     Label profilingReturn;
     GenerateAsmJSExitEpilogue(masm, framePushed, AsmJSExit::SlowFFI, &profilingReturn);
     return !masm.oom() && m.finishGeneratingInterpExit(exitIndex, &begin, &profilingReturn);
 }
 
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
 static const unsigned MaybeSavedGlobalReg = sizeof(void*);
 #else
 static const unsigned MaybeSavedGlobalReg = 0;
 #endif
 
 static bool
 GenerateFFIIonExit(ModuleCompiler& m, const ModuleCompiler::ExitDescriptor& exit,
                    unsigned exitIndex, Label* throwLabel)
@@ -11278,17 +11279,17 @@ GenerateFFIIonExit(ModuleCompiler& m, co
     Register scratch = ABIArgGenerator::NonArgReturnReg1;  // repeatedly clobbered
 
     // 2.1. Get ExitDatum
     unsigned globalDataOffset = m.module().exitIndexToGlobalDataOffset(exitIndex);
 #if defined(JS_CODEGEN_X64)
     m.masm().append(AsmJSGlobalAccess(masm.leaRipRelative(callee), globalDataOffset));
 #elif defined(JS_CODEGEN_X86)
     m.masm().append(AsmJSGlobalAccess(masm.movlWithPatch(Imm32(0), callee), globalDataOffset));
-#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
     masm.computeEffectiveAddress(Address(GlobalReg, globalDataOffset - AsmJSGlobalRegBias), callee);
 #endif
 
     // 2.2. Get callee
     masm.loadPtr(Address(callee, offsetof(AsmJSModule::ExitDatum, fun)), callee);
 
     // 2.3. Save callee
     masm.storePtr(callee, Address(masm.getStackPointer(), argOffset));
@@ -11314,17 +11315,17 @@ GenerateFFIIonExit(ModuleCompiler& m, co
     MOZ_ASSERT(argOffset == ionFrameBytes);
 
     // 6. Jit code will clobber all registers, even non-volatiles. GlobalReg and
     //    HeapReg are removed from the general register set for asm.js code, so
     //    these will not have been saved by the caller like all other registers,
     //    so they must be explicitly preserved. Only save GlobalReg since
     //    HeapReg must be reloaded (from global data) after the call since the
     //    heap may change during the FFI call.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
     static_assert(MaybeSavedGlobalReg == sizeof(void*), "stack frame accounting");
     masm.storePtr(GlobalReg, Address(masm.getStackPointer(), ionFrameBytes));
 #endif
 
     {
         // Enable Activation.
         //
         // This sequence requires four registers, and needs to preserve the 'callee'
@@ -11430,17 +11431,17 @@ GenerateFFIIonExit(ModuleCompiler& m, co
         masm.storePtr(reg2, Address(reg0, offsetOfJitJSContext));
 
         //   rt->jitActivation = prevJitActivation_;
         masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitActivation()), reg2);
         masm.storePtr(reg2, Address(reg0, offsetOfJitActivation));
     }
 
     // Reload the global register since Ion code can clobber any register.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
     static_assert(MaybeSavedGlobalReg == sizeof(void*), "stack frame accounting");
     masm.loadPtr(Address(masm.getStackPointer(), ionFrameBytes), GlobalReg);
 #endif
 
     // As explained above, the frame was aligned for Ion such that
     //   (sp + sizeof(void*)) % JitStackAlignment == 0
     // But now we possibly want to call one of several different C++ functions,
     // so subtract the sizeof(void*) so that sp is aligned for an ABI call.
@@ -11745,17 +11746,17 @@ GenerateAsyncInterruptExit(ModuleCompile
 
     // Restore the StackPointer to its position before the call.
     masm.moveToStackPtr(ABIArgGenerator::NonVolatileReg);
 
     // Restore the machine state to before the interrupt.
     masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP)
     masm.popFlags();              // after this, nothing that sets conditions
     masm.ret();                   // pop resumePC into PC
-#elif defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS32)
     // Reserve space to store resumePC.
     masm.subFromStackPtr(Imm32(sizeof(intptr_t)));
     // set to zero so we can use masm.framePushed() below.
     masm.setFramePushed(0);
     // When this platform supports SIMD extensions, we'll need to push high lanes
     // of SIMD registers as well.
     JS_STATIC_ASSERT(!SupportsSimd);
     // save all registers,except sp. After this stack is alligned.
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -478,50 +478,50 @@ SIMDObject::initClass(JSContext* cx, Han
                                                   SingletonObject));
     if (!SIMD)
         return nullptr;
 
     RootedObject i8x16(cx);
     i8x16 = CreateAndBindSimdClass<Int8x16Defn>(cx, global, SIMD, cx->names().int8x16);
     if (!i8x16)
         return nullptr;
-    global->setInt8x16TypeDescr(*i8x16);
 
     RootedObject i16x8(cx);
     i16x8 = CreateAndBindSimdClass<Int16x8Defn>(cx, global, SIMD, cx->names().int16x8);
     if (!i16x8)
         return nullptr;
-    global->setInt16x8TypeDescr(*i16x8);
 
     RootedObject f32x4(cx);
     f32x4 = CreateAndBindSimdClass<Float32x4Defn>(cx, global, SIMD, cx->names().float32x4);
     if (!f32x4)
         return nullptr;
-    global->setFloat32x4TypeDescr(*f32x4);
 
     RootedObject i32x4(cx);
     i32x4 = CreateAndBindSimdClass<Int32x4Defn>(cx, global, SIMD, cx->names().int32x4);
     if (!i32x4)
         return nullptr;
-    global->setInt32x4TypeDescr(*i32x4);
 
     RootedObject f64x2(cx);
     f64x2 = CreateAndBindSimdClass<Float64x2Defn>(cx, global, SIMD, cx->names().float64x2);
     if (!f64x2)
         return nullptr;
-    global->setFloat64x2TypeDescr(*f64x2);
 
     // Everything is set up, install SIMD on the global object.
     RootedValue SIMDValue(cx, ObjectValue(*SIMD));
     if (!DefineProperty(cx, global, cx->names().SIMD, SIMDValue, nullptr, nullptr,
                         JSPROP_RESOLVING))
     {
         return nullptr;
     }
 
+    global->setInt8x16TypeDescr(*i8x16);
+    global->setInt16x8TypeDescr(*i16x8);
+    global->setFloat32x4TypeDescr(*f32x4);
+    global->setInt32x4TypeDescr(*i32x4);
+    global->setFloat64x2TypeDescr(*f64x2);
     global->setConstructor(JSProto_SIMD, SIMDValue);
     return SIMD;
 }
 
 JSObject*
 js::InitSIMDClass(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(obj->is<GlobalObject>());
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1372,22 +1372,21 @@ ShellObjectMetadataCallback(JSContext* c
             stackIndex++;
         }
     }
 
     return obj;
 }
 
 static bool
-SetObjectMetadataCallback(JSContext* cx, unsigned argc, Value* vp)
+EnableShellObjectMetadataCallback(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    bool enabled = args.length() ? ToBoolean(args[0]) : false;
-    SetObjectMetadataCallback(cx, enabled ? ShellObjectMetadataCallback : nullptr);
+    SetObjectMetadataCallback(cx, ShellObjectMetadataCallback);
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 GetObjectMetadata(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -2000,16 +1999,19 @@ GetBacktrace(JSContext* cx, unsigned arg
         showLocals = ToBoolean(v);
 
         if (!JS_GetProperty(cx, cfg, "thisprops", &v))
             return false;
         showThisProps = ToBoolean(v);
     }
 
     char* buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
+    if (!buf)
+        return false;
+
     RootedString str(cx);
     if (!(str = JS_NewStringCopyZ(cx, buf)))
         return false;
     JS_smprintf_free(buf);
 
     args.rval().setString(str);
     return true;
 }
@@ -2926,19 +2928,19 @@ gc::ZealModeHelpText),
     JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0,
 "isLazyFunction(fun)",
 "  True if fun is a lazy JSFunction."),
 
     JS_FN_HELP("isRelazifiableFunction", IsRelazifiableFunction, 1, 0,
 "isRelazifiableFunction(fun)",
 "  Ture if fun is a JSFunction with a relazifiable JSScript."),
 
-    JS_FN_HELP("setObjectMetadataCallback", SetObjectMetadataCallback, 1, 0,
-"setObjectMetadataCallback(fn)",
-"  Specify function to supply metadata for all newly created objects."),
+    JS_FN_HELP("enableShellObjectMetadataCallback", EnableShellObjectMetadataCallback, 0, 0,
+"enableShellObjectMetadataCallback()",
+"  Use ShellObjectMetadataCallback to supply metadata for all newly created objects."),
 
     JS_FN_HELP("getObjectMetadata", GetObjectMetadata, 1, 0,
 "getObjectMetadata(obj)",
 "  Get the metadata for an object."),
 
     JS_FN_HELP("bailout", testingFunc_bailout, 0, 0,
 "bailout()",
 "  Force a bailout out of ionmonkey (if running in ionmonkey)."),
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -969,17 +969,17 @@ x86_64 | ia64)
     CPU_ARCH="$OS_TEST"
     ;;
 
 arm*)
     CPU_ARCH=arm
     ;;
 
 mips|mipsel)
-    CPU_ARCH="mips"
+    CPU_ARCH="mips32"
     ;;
 
 aarch64*)
     CPU_ARCH=aarch64
     ;;
 
 esac
 
@@ -3053,26 +3053,26 @@ fi
 AC_SUBST(MOZ_VALGRIND)
 
 dnl ========================================================
 dnl = Use a JIT code simulator for a foreign architecture.
 dnl ========================================================
 MOZ_ARG_ENABLE_STRING(simulator,
 [  --enable-simulator=ARCH
                           Enable a JIT code simulator for the specified arch.
-                          (arm, arm64, mips).],
+                          (arm, arm64, mips32).],
     JS_SIMULATOR="$enableval")
 
 if test -n "$JS_SIMULATOR"; then
     case "$JS_SIMULATOR" in
-        arm|arm64|mips) ;;
+        arm|arm64|mips32) ;;
         no)
             JS_SIMULATOR=
             ;;
-        *) AC_MSG_ERROR([Invalid simulator. Valid simulators are: arm, arm64, mips.]) ;;
+        *) AC_MSG_ERROR([Invalid simulator. Valid simulators are: arm, arm64, mips32.]) ;;
     esac
 fi
 
 if test -z "$ENABLE_ION"; then
     AC_DEFINE(JS_CODEGEN_NONE)
     JS_CODEGEN_NONE=1
 elif test "$JS_SIMULATOR" = arm; then
     if test "$CPU_ARCH" != "x86"; then
@@ -3087,51 +3087,51 @@ elif test "$JS_SIMULATOR" = arm64; then
     if test "$CPU_ARCH" != "x86_64"; then
         AC_MSG_ERROR([The ARM64 simulator only works on x86_64.])
     fi
     AC_DEFINE(JS_SIMULATOR)
     AC_DEFINE(JS_SIMULATOR_ARM64)
     AC_DEFINE(JS_CODEGEN_ARM64)
     JS_SIMULATOR_ARM64=1
     JS_CODEGEN_ARM64=1
-elif test "$JS_SIMULATOR" = mips; then
+elif test "$JS_SIMULATOR" = mips32; then
     if test "$CPU_ARCH" != "x86"; then
-        AC_MSG_ERROR([The MIPS simulator only works on x86.])
+        AC_MSG_ERROR([The MIPS32 simulator only works on x86.])
     fi
     AC_DEFINE(JS_SIMULATOR)
-    AC_DEFINE(JS_SIMULATOR_MIPS)
-    AC_DEFINE(JS_CODEGEN_MIPS)
-    JS_SIMULATOR_MIPS=1
-    JS_CODEGEN_MIPS=1
+    AC_DEFINE(JS_SIMULATOR_MIPS32)
+    AC_DEFINE(JS_CODEGEN_MIPS32)
+    JS_SIMULATOR_MIPS32=1
+    JS_CODEGEN_MIPS32=1
 elif test "$CPU_ARCH" = "x86"; then
     AC_DEFINE(JS_CODEGEN_X86)
     JS_CODEGEN_X86=1
 elif test "$CPU_ARCH" = "x86_64"; then
     AC_DEFINE(JS_CODEGEN_X64)
     JS_CODEGEN_X64=1
 
     dnl Signal-handler OOM checking requires large mprotected guard regions, so
     dnl currently it is only implemented on x64.
     AC_DEFINE(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
     ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB=1
 elif test "$CPU_ARCH" = "arm"; then
     AC_DEFINE(JS_CODEGEN_ARM)
     JS_CODEGEN_ARM=1
-elif test "$CPU_ARCH" = "mips"; then
-    AC_DEFINE(JS_CODEGEN_MIPS)
-    JS_CODEGEN_MIPS=1
+elif test "$CPU_ARCH" = "mips32"; then
+    AC_DEFINE(JS_CODEGEN_MIPS32)
+    JS_CODEGEN_MIPS32=1
 fi
 
 AC_SUBST(JS_SIMULATOR)
 AC_SUBST(JS_SIMULATOR_ARM)
 AC_SUBST(JS_SIMULATOR_ARM64)
-AC_SUBST(JS_SIMULATOR_MIPS)
+AC_SUBST(JS_SIMULATOR_MIPS32)
 AC_SUBST(JS_CODEGEN_ARM)
 AC_SUBST(JS_CODEGEN_ARM64)
-AC_SUBST(JS_CODEGEN_MIPS)
+AC_SUBST(JS_CODEGEN_MIPS32)
 AC_SUBST(JS_CODEGEN_X86)
 AC_SUBST(JS_CODEGEN_X64)
 AC_SUBST(JS_CODEGEN_NONE)
 AC_SUBST(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 
 dnl ========================================================
 dnl jprof
 dnl ========================================================
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -52,27 +52,28 @@ namespace js {
 namespace frontend {
 
 typedef Rooted<StaticBlockObject*> RootedStaticBlockObject;
 typedef Handle<StaticBlockObject*> HandleStaticBlockObject;
 typedef Rooted<NestedScopeObject*> RootedNestedScopeObject;
 typedef Handle<NestedScopeObject*> HandleNestedScopeObject;
 
 /* Read a token. Report an error and return null() if that token isn't of type tt. */
-#define MUST_MATCH_TOKEN(tt, errno)                                                         \
+#define MUST_MATCH_TOKEN_MOD(tt, modifier, errno)                                           \
     JS_BEGIN_MACRO                                                                          \
         TokenKind token;                                                                    \
-        if (!tokenStream.getToken(&token))                                                  \
+        if (!tokenStream.getToken(&token, modifier))                                        \
             return null();                                                                  \
         if (token != tt) {                                                                  \
             report(ParseError, false, null(), errno);                                       \
             return null();                                                                  \
         }                                                                                   \
     JS_END_MACRO
 
+#define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errno)
 
 template <>
 bool
 ParseContext<FullParseHandler>::checkLocalsOverflow(TokenStream& ts)
 {
     if (vars_.length() + bodyLevelLexicals_.length() >= LOCALNO_LIMIT) {
         ts.reportError(JSMSG_TOO_MANY_LOCALS);
         return false;
@@ -737,17 +738,17 @@ Parser<ParseHandler>::parse()
                                         &globalsc, /* newDirectives = */ nullptr,
                                         /* blockScopeDepth = */ 0);
     if (!globalpc.init(*this))
         return null();
 
     Node pn = statements(YieldIsName);
     if (pn) {
         TokenKind tt;
-        if (!tokenStream.getToken(&tt))
+        if (!tokenStream.getToken(&tt, TokenStream::Operand))
             return null();
         if (tt != TOK_EOF) {
             report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
                    "script", TokenKindToDesc(tt));
             return null();
         }
         if (foldConstants) {
             if (!FoldConstants(context, &pn, this))
@@ -835,17 +836,17 @@ Parser<FullParseHandler>::standaloneFunc
     }
 
     YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
     ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
     if (!pn)
         return null();
 
     TokenKind tt;
-    if (!tokenStream.getToken(&tt))
+    if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return null();
     if (tt != TOK_EOF) {
         report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
                "function body", TokenKindToDesc(tt));
         return null();
     }
 
     if (!FoldConstants(context, &pn, this))
@@ -1342,29 +1343,33 @@ Parser<ParseHandler>::newFunction(Handle
     if (!fun)
         return nullptr;
     if (options().selfHostingMode)
         fun->setIsSelfHostedBuiltin();
     return fun;
 }
 
 static bool
-MatchOrInsertSemicolon(TokenStream& ts)
+MatchOrInsertSemicolon(TokenStream& ts, TokenStream::Modifier modifier = TokenStream::None)
 {
     TokenKind tt;
-    if (!ts.peekTokenSameLine(&tt, TokenStream::Operand))
+    if (!ts.peekTokenSameLine(&tt, modifier))
         return false;
     if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
         /* Advance the scanner for proper error location reporting. */
-        ts.consumeKnownToken(tt);
+        ts.consumeKnownToken(tt, modifier);
         ts.reportError(JSMSG_SEMI_BEFORE_STMNT);
         return false;
     }
-    bool ignored;
-    return ts.matchToken(&ignored, TOK_SEMI);
+    bool matched;
+    if (!ts.matchToken(&matched, TOK_SEMI, modifier))
+        return false;
+    if (!matched && modifier == TokenStream::None)
+        ts.addModifierException(TokenStream::OperandIsNone);
+    return true;
 }
 
 /*
  * The function LexicalLookup searches a static binding for the given name in
  * the stack of statements enclosing the statement currently being parsed. Each
  * statement that introduces a new scope has a corresponding scope object, on
  * which the bindings for that scope are stored. LexicalLookup either returns
  * the innermost statement which has a scope object containing a binding with
@@ -1699,26 +1704,29 @@ bool
 Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
                                         Node funcpn, bool* hasRest)
 {
     FunctionBox* funbox = pc->sc->asFunctionBox();
 
     *hasRest = false;
 
     bool parenFreeArrow = false;
+    TokenStream::Modifier modifier = TokenStream::None;
     if (kind == Arrow) {
         TokenKind tt;
-        if (!tokenStream.peekToken(&tt))
+        if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return false;
         if (tt == TOK_NAME)
             parenFreeArrow = true;
+        else
+            modifier = TokenStream::Operand;
     }
     if (!parenFreeArrow) {
         TokenKind tt;
-        if (!tokenStream.getToken(&tt))
+        if (!tokenStream.getToken(&tt, modifier))
             return false;
         if (tt != TOK_LP) {
             report(ParseError, false, null(),
                    kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL);
             return false;
         }
 
         // Record the start of function source (for FunctionToString). If we
@@ -1731,17 +1739,17 @@ Parser<ParseHandler>::functionArguments(
         return false;
     handler.setFunctionBody(funcpn, argsbody);
 
     bool hasArguments = false;
     if (parenFreeArrow) {
         hasArguments = true;
     } else {
         bool matched;
-        if (!tokenStream.matchToken(&matched, TOK_RP))
+        if (!tokenStream.matchToken(&matched, TOK_RP, TokenStream::Operand))
             return false;
         if (!matched)
             hasArguments = true;
     }
     if (hasArguments) {
         bool hasDefaults = false;
         Node duplicatedArg = null();
         bool disallowDuplicateArgs = kind == Arrow || kind == Method || kind == ClassConstructor;
@@ -1753,17 +1761,17 @@ Parser<ParseHandler>::functionArguments(
 
         while (true) {
             if (*hasRest) {
                 report(ParseError, false, null(), JSMSG_PARAMETER_AFTER_REST);
                 return false;
             }
 
             TokenKind tt;
-            if (!tokenStream.getToken(&tt))
+            if (!tokenStream.getToken(&tt, TokenStream::Operand))
                 return false;
             MOZ_ASSERT_IF(parenFreeArrow, tt == TOK_NAME);
             switch (tt) {
               case TOK_LB:
               case TOK_LC:
               {
                 /* See comment below in the TOK_NAME case. */
                 disallowDuplicateArgs = true;
@@ -2690,17 +2698,17 @@ Parser<ParseHandler>::functionArgsAndBod
     if ((kind != Method && !IsConstructorKind(kind)) && fun->name() &&
         !checkStrictBinding(fun->name(), pn))
     {
         return false;
     }
 
     if (bodyType == StatementListBody) {
         bool matched;
-        if (!tokenStream.matchToken(&matched, TOK_RC))
+        if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand))
             return false;
         if (!matched) {
             report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY);
             return false;
         }
         funbox->bufEnd = pos().begin + 1;
     } else {
 #if !JS_HAS_EXPR_CLOSURES
@@ -3042,25 +3050,25 @@ template <typename ParseHandler>
 bool
 Parser<ParseHandler>::matchLabel(YieldHandling yieldHandling, MutableHandle<PropertyName*> label)
 {
     TokenKind tt;
     if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
         return false;
 
     if (tt == TOK_NAME) {
-        tokenStream.consumeKnownToken(TOK_NAME);
+        tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand);
         MOZ_ASSERT_IF(tokenStream.currentName() == context->names().yield,
                       yieldHandling == YieldIsName);
         label.set(tokenStream.currentName());
     } else if (tt == TOK_YIELD) {
         // We might still consider |yield| to be valid here, contrary to ES6.
         // Fix bug 1104014, then stop shipping legacy generators in chrome
         // code, then remove this check!
-        tokenStream.consumeKnownToken(TOK_YIELD);
+        tokenStream.consumeKnownToken(TOK_YIELD, TokenStream::Operand);
         if (!checkYieldNameValidity())
             return false;
         label.set(tokenStream.currentName());
     } else {
         label.set(nullptr);
     }
     return true;
 }
@@ -3854,17 +3862,17 @@ Parser<ParseHandler>::deprecatedLetBlock
     if (!block)
         return null();
 
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_LET);
 
     Node expr = statements(yieldHandling);
     if (!expr)
         return null();
-    MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
+    MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_LET);
 
     addTelemetry(JSCompartment::DeprecatedLetBlock);
     if (!report(ParseWarning, pc->sc->strict(), expr, JSMSG_DEPRECATED_LET_BLOCK))
         return null();
 
     handler.setLexicalScopeBody(block, expr);
 
     TokenPos letPos(begin, pos().end);
@@ -3881,17 +3889,17 @@ Parser<ParseHandler>::blockStatement(Yie
     AutoPushStmtInfoPC stmtInfo(*this, StmtType::BLOCK);
     if (!stmtInfo.generateBlockId())
         return null();
 
     Node list = statements(yieldHandling);
     if (!list)
         return null();
 
-    MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND);
+    MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_IN_COMPOUND);
     return list;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::newBindingNode(PropertyName* name, bool functionScope, VarContext varContext)
 {
     /*
@@ -4338,30 +4346,31 @@ Parser<SyntaxParseHandler>::letDeclarati
     return SyntaxParseHandler::NodeFailure;
 }
 
 template<>
 bool
 Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet)
 {
     if (tt == TOK_LC) {
+        TokenStream::Modifier modifier = TokenStream::KeywordIsName;
         while (true) {
             // Handle the forms |import {} from 'a'| and
             // |import { ..., } from 'a'| (where ... is non empty), by
             // escaping the loop early if the next token is }.
             if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName))
                 return false;
 
             if (tt == TOK_RC)
                 break;
 
             // If the next token is a keyword, the previous call to
             // peekToken matched it as a TOK_NAME, and put it in the
             // lookahead buffer, so this call will match keywords as well.
-            MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME);
+            MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_IMPORT_NAME);
             Node importName = newName(tokenStream.currentName());
             if (!importName)
                 return false;
 
             if (!tokenStream.getToken(&tt))
                 return false;
 
             if (tt == TOK_NAME && tokenStream.currentName() == context->names().as) {
@@ -4389,21 +4398,23 @@ Parser<FullParseHandler>::namedImportsOr
                 return false;
 
             handler.addList(importSpecSet, importSpec);
 
             bool matched;
             if (!tokenStream.matchToken(&matched, TOK_COMMA))
                 return false;
 
-            if (!matched)
+            if (!matched) {
+                modifier = TokenStream::None;
                 break;
-        }
-
-        MUST_MATCH_TOKEN(TOK_RC, JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
+            }
+        }
+
+        MUST_MATCH_TOKEN_MOD(TOK_RC, modifier, JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
     } else {
         MOZ_ASSERT(tt == TOK_MUL);
         if (!tokenStream.getToken(&tt))
             return false;
 
         if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) {
             report(ParseError, false, null(), JSMSG_AS_AFTER_IMPORT_STAR);
             return false;
@@ -4514,17 +4525,17 @@ Parser<ParseHandler>::importDeclaration(
         report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_IMPORT);
         return null();
     }
 
     Node moduleSpec = stringLiteral();
     if (!moduleSpec)
         return null();
 
-    if (!MatchOrInsertSemicolon(tokenStream))
+    if (!MatchOrInsertSemicolon(tokenStream, TokenStream::Operand))
         return null();
 
     return handler.newImportDeclaration(importSpecSet, moduleSpec, TokenPos(begin, pos().end));
 }
 
 template<>
 SyntaxParseHandler::Node
 Parser<SyntaxParseHandler>::importDeclaration()
@@ -4661,17 +4672,17 @@ Parser<FullParseHandler>::exportDeclarat
         kid->pn_xflags = PNX_POPVAR;
 
         kid = MatchOrInsertSemicolon(tokenStream) ? kid : nullptr;
         if (!kid)
             return null();
         break;
 
       case TOK_DEFAULT: {
-        if (!tokenStream.getToken(&tt))
+        if (!tokenStream.getToken(&tt, TokenStream::Operand))
             return null();
 
         switch (tt) {
           case TOK_FUNCTION:
             kid = functionStmt(YieldIsKeyword, AllowDefaultName);
             break;
           case TOK_CLASS:
             kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName);
@@ -4790,29 +4801,31 @@ template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::doWhileStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
     AutoPushStmtInfoPC stmtInfo(*this, StmtType::DO_LOOP);
     Node body = statement(yieldHandling);
     if (!body)
         return null();
-    MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO);
+    MUST_MATCH_TOKEN_MOD(TOK_WHILE, TokenStream::Operand, JSMSG_WHILE_AFTER_DO);
     Node cond = condition(InAllowed, yieldHandling);
     if (!cond)
         return null();
 
     // The semicolon after do-while is even more optional than most
     // semicolons in JS.  Web compat required this by 2004:
     //   http://bugzilla.mozilla.org/show_bug.cgi?id=238945
     // ES3 and ES5 disagreed, but ES6 conforms to Web reality:
     //   https://bugs.ecmascript.org/show_bug.cgi?id=157
-    bool ignored;
-    if (!tokenStream.matchToken(&ignored, TOK_SEMI))
-        return null();
+    bool matched;
+    if (!tokenStream.matchToken(&matched, TOK_SEMI))
+        return null();
+    if (!matched)
+        tokenStream.addModifierException(TokenStream::OperandIsNone);
     return handler.newDoWhileStatement(body, cond, TokenPos(begin, pos().end));
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::whileStatement(YieldHandling yieldHandling)
 {
     uint32_t begin = pos().begin;
@@ -4916,16 +4929,17 @@ Parser<FullParseHandler>::forStatement(Y
     bool isForDecl = false;
 
     /* Non-null when isForDecl is true for a 'for (let ...)' statement. */
     RootedStaticBlockObject blockObj(context);
 
     /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
     ParseNode* pn1;
 
+    TokenStream::Modifier modifier = TokenStream::Operand;
     {
         TokenKind tt;
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
         if (tt == TOK_SEMI) {
             pn1 = nullptr;
         } else {
             // Set pn1 to a variable list or an initializing expression.
@@ -4934,37 +4948,38 @@ Parser<FullParseHandler>::forStatement(Y
             // to trigger |for|-specific parsing for that one position.  In a
             // normal variable declaration, any initializer may be an |in|
             // expression.  But for declarations at the start of a for-loop
             // head, initializers can't contain |in|.  (Such syntax conflicts
             // with ES5's |for (var i = 0 in foo)| syntax, removed in ES6, that
             // we "support" by ignoring the |= 0|.)
             if (tt == TOK_VAR) {
                 isForDecl = true;
-                tokenStream.consumeKnownToken(tt);
+                tokenStream.consumeKnownToken(tt, TokenStream::Operand);
                 pn1 = variables(yieldHandling, PNK_VAR, InForInit);
             } else if (tt == TOK_LET || tt == TOK_CONST) {
                 handler.disableSyntaxParser();
                 bool constDecl = tt == TOK_CONST;
-                tokenStream.consumeKnownToken(tt);
+                tokenStream.consumeKnownToken(tt, TokenStream::Operand);
                 isForDecl = true;
                 blockObj = StaticBlockObject::create(context);
                 if (!blockObj)
                     return null();
                 pn1 = variables(yieldHandling, constDecl ? PNK_CONST : PNK_LET, InForInit,
                                 nullptr, blockObj, DontHoistVars);
             } else {
                 // Pass |InProhibited| when parsing an expression so that |in|
                 // isn't parsed in a RelationalExpression as a binary operator.
                 // In this context, |in| is part of a for-in loop -- *not* part
                 // of a binary expression.
                 pn1 = expr(InProhibited, yieldHandling);
             }
             if (!pn1)
                 return null();
+            modifier = TokenStream::None;
         }
     }
 
     MOZ_ASSERT_IF(isForDecl, pn1->isArity(PN_LIST));
     MOZ_ASSERT(!!blockObj == (isForDecl && pn1->isOp(JSOP_NOP)));
 
     // All forms of for-loop (for(;;), for-in, for-of) generate an implicit
     // block to store any lexical variables declared by the loop-head.  We
@@ -5087,16 +5102,17 @@ Parser<FullParseHandler>::forStatement(Y
                 return null();
         }
 
         pn3 = (headKind == PNK_FOROF)
               ? assignExpr(InAllowed, yieldHandling)
               : expr(InAllowed, yieldHandling);
         if (!pn3)
             return null();
+        modifier = TokenStream::None;
 
         if (blockObj) {
             /*
              * Now that the pn3 has been parsed, push the let scope. To hold
              * the blockObj for the emitter, wrap the PNK_LEXICALSCOPE node
              * created by pushLetScope around the for's initializer. This also
              * serves to indicate the let-decl to the emitter.
              */
@@ -5174,42 +5190,46 @@ Parser<FullParseHandler>::forStatement(Y
             } else {
                 pn1 = handler.newFreshenBlock(pn1->pn_pos);
                 if (!pn1)
                     return null();
             }
         }
 
         /* Parse the loop condition or null into pn2. */
-        MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
+        MUST_MATCH_TOKEN_MOD(TOK_SEMI, modifier, JSMSG_SEMI_AFTER_FOR_INIT);
         TokenKind tt;
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
         if (tt == TOK_SEMI) {
             pn2 = nullptr;
+            modifier = TokenStream::Operand;
         } else {
             pn2 = expr(InAllowed, yieldHandling);
             if (!pn2)
                 return null();
+            modifier = TokenStream::None;
         }
 
         /* Parse the update expression or null into pn3. */
-        MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
+        MUST_MATCH_TOKEN_MOD(TOK_SEMI, modifier, JSMSG_SEMI_AFTER_FOR_COND);
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
         if (tt == TOK_RP) {
             pn3 = nullptr;
+            modifier = TokenStream::Operand;
         } else {
             pn3 = expr(InAllowed, yieldHandling);
             if (!pn3)
                 return null();
-        }
-    }
-
-    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
+            modifier = TokenStream::None;
+        }
+    }
+
+    MUST_MATCH_TOKEN_MOD(TOK_RP, modifier, JSMSG_PAREN_AFTER_FOR_CTRL);
 
     TokenPos headPos(begin, pos().end);
     ParseNode* forHead = handler.newForHead(headKind, pn1, pn2, pn3, headPos);
     if (!forHead)
         return null();
 
     /* Parse the loop body. */
     ParseNode* body = statement(yieldHandling);
@@ -5259,38 +5279,40 @@ Parser<SyntaxParseHandler>::forStatement
 
     /* True if we have 'for (var ...)'. */
     bool isForDecl = false;
     bool simpleForDecl = true;
 
     /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
     Node lhsNode;
 
+    TokenStream::Modifier modifier = TokenStream::Operand;
     {
         TokenKind tt;
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
         if (tt == TOK_SEMI) {
             lhsNode = null();
         } else {
             /* Set lhsNode to a var list or an initializing expression. */
             if (tt == TOK_VAR) {
                 isForDecl = true;
-                tokenStream.consumeKnownToken(tt);
+                tokenStream.consumeKnownToken(tt, TokenStream::Operand);
                 lhsNode = variables(yieldHandling, PNK_VAR, InForInit, &simpleForDecl);
             }
             else if (tt == TOK_CONST || tt == TOK_LET) {
                 JS_ALWAYS_FALSE(abortIfSyntaxParser());
                 return null();
             }
             else {
                 lhsNode = expr(InProhibited, yieldHandling);
             }
             if (!lhsNode)
                 return null();
+            modifier = TokenStream::None;
         }
     }
 
     // If there's an |in| keyword here, it's a for-in loop, by dint of careful
     // parsing of |pn1|.
     bool isForIn = false, isForOf = false;
     if (lhsNode) {
         if (!matchInOrOf(&isForIn, &isForOf))
@@ -5314,38 +5336,43 @@ Parser<SyntaxParseHandler>::forStatement
             return null();
         }
 
         if (!isForDecl && !checkAndMarkAsAssignmentLhs(lhsNode, PlainAssignment))
             return null();
 
         if (!(isForIn ? expr(InAllowed, yieldHandling) : assignExpr(InAllowed, yieldHandling)))
             return null();
+        modifier = TokenStream::None;
     } else {
         /* Parse the loop condition or null. */
-        MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
+        MUST_MATCH_TOKEN_MOD(TOK_SEMI, modifier, JSMSG_SEMI_AFTER_FOR_INIT);
         TokenKind tt;
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
+        modifier = TokenStream::Operand;
         if (tt != TOK_SEMI) {
             if (!expr(InAllowed, yieldHandling))
                 return null();
+            modifier = TokenStream::None;
         }
 
         /* Parse the update expression or null. */
-        MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
+        MUST_MATCH_TOKEN_MOD(TOK_SEMI, modifier, JSMSG_SEMI_AFTER_FOR_COND);
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
+        modifier = TokenStream::Operand;
         if (tt != TOK_RP) {
             if (!expr(InAllowed, yieldHandling))
                 return null();
-        }
-    }
-
-    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
+            modifier = TokenStream::None;
+        }
+    }
+
+    MUST_MATCH_TOKEN_MOD(TOK_RP, modifier, JSMSG_PAREN_AFTER_FOR_CTRL);
 
     /* Parse the loop body. */
     if (!statement(yieldHandling))
         return null();
 
     return SyntaxParseHandler::NodeGeneric;
 }
 
@@ -5374,17 +5401,17 @@ Parser<ParseHandler>::switchStatement(Yi
         return null();
 
     Node saveBlock = pc->blockNode;
     pc->blockNode = caseList;
 
     bool seenDefault = false;
     TokenKind tt;
     while (true) {
-        if (!tokenStream.getToken(&tt))
+        if (!tokenStream.getToken(&tt, TokenStream::Operand))
             return null();
         if (tt == TOK_RC)
             break;
         uint32_t caseBegin = pos().begin;
 
         Node caseExpr;
         switch (tt) {
           case TOK_DEFAULT:
@@ -5517,17 +5544,17 @@ Parser<ParseHandler>::continueStatement(
                 report(ParseError, false, null(), JSMSG_BAD_CONTINUE);
                 return null();
             }
             if (stmt->isLoop())
                 break;
         }
     }
 
-    if (!MatchOrInsertSemicolon(tokenStream))
+    if (!MatchOrInsertSemicolon(tokenStream, TokenStream::Operand))
         return null();
 
     return handler.newContinueStatement(label, TokenPos(begin, pos().end));
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::breakStatement(YieldHandling yieldHandling)
@@ -5554,17 +5581,17 @@ Parser<ParseHandler>::breakStatement(Yie
                 report(ParseError, false, null(), JSMSG_TOUGH_BREAK);
                 return null();
             }
             if (stmt->isLoop() || stmt->type == StmtType::SWITCH)
                 break;
         }
     }
 
-    if (!MatchOrInsertSemicolon(tokenStream))
+    if (!MatchOrInsertSemicolon(tokenStream, TokenStream::Operand))
         return null();
 
     return handler.newBreakStatement(label, TokenPos(begin, pos().end));
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
@@ -5576,33 +5603,35 @@ Parser<ParseHandler>::returnStatement(Yi
 
     // Parse an optional operand.
     //
     // This is ugly, but we don't want to require a semicolon.
     Node exprNode;
     TokenKind tt;
     if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
         return null();
+    TokenStream::Modifier modifier = TokenStream::Operand;
     switch (tt) {
       case TOK_EOL:
       case TOK_EOF:
       case TOK_SEMI:
       case TOK_RC:
         exprNode = null();
         pc->funHasReturnVoid = true;
         break;
       default: {
         exprNode = expr(InAllowed, yieldHandling);
         if (!exprNode)
             return null();
+        modifier = TokenStream::None;
         pc->funHasReturnExpr = true;
       }
     }
 
-    if (!MatchOrInsertSemicolon(tokenStream))
+    if (!MatchOrInsertSemicolon(tokenStream, modifier))
         return null();
 
     Node genrval = null();
     if (pc->isStarGenerator()) {
         genrval = newName(context->names().dotGenRVal);
         if (!genrval)
             return null();
         if (!noteNameUse(context->names().dotGenRVal, genrval))
@@ -5671,20 +5700,21 @@ Parser<ParseHandler>::yieldExpression(In
           case TOK_SEMI:
           case TOK_RC:
           case TOK_RB:
           case TOK_RP:
           case TOK_COLON:
           case TOK_COMMA:
             // No value.
             exprNode = null();
+            tokenStream.addModifierException(TokenStream::NoneIsOperand);
             break;
           case TOK_MUL:
             kind = PNK_YIELD_STAR;
-            tokenStream.consumeKnownToken(TOK_MUL);
+            tokenStream.consumeKnownToken(TOK_MUL, TokenStream::Operand);
             // Fall through.
           default:
             exprNode = assignExpr(inHandling, YieldIsKeyword);
             if (!exprNode)
                 return null();
         }
         return newYieldExpression(begin, exprNode, kind == PNK_YIELD_STAR);
       }
@@ -5733,16 +5763,17 @@ Parser<ParseHandler>::yieldExpression(In
           case TOK_SEMI:
           case TOK_RC:
           case TOK_RB:
           case TOK_RP:
           case TOK_COLON:
           case TOK_COMMA:
             // No value.
             exprNode = null();
+            tokenStream.addModifierException(TokenStream::NoneIsOperand);
             break;
           default:
             exprNode = assignExpr(inHandling, YieldIsKeyword);
             if (!exprNode)
                 return null();
         }
 
         return newYieldExpression(begin, exprNode);
@@ -5905,17 +5936,17 @@ Parser<ParseHandler>::tryStatement(Yield
     {
         MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
         AutoPushStmtInfoPC stmtInfo(*this, StmtType::TRY);
         if (!stmtInfo.generateBlockId())
             return null();
         innerBlock = statements(yieldHandling);
         if (!innerBlock)
             return null();
-        MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY);
+        MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_TRY);
     }
 
     bool hasUnconditionalCatch = false;
     Node catchList = null();
     TokenKind tt;
     if (!tokenStream.getToken(&tt))
         return null();
     if (tt == TOK_CATCH) {
@@ -6017,17 +6048,17 @@ Parser<ParseHandler>::tryStatement(Yield
             }
 #endif
             MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
 
             MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
             Node catchBody = statements(yieldHandling);
             if (!catchBody)
                 return null();
-            MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH);
+            MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_CATCH);
 
             if (!catchGuard)
                 hasUnconditionalCatch = true;
 
             if (!handler.addCatchBlock(catchList, pnblock, catchName, catchGuard, catchBody))
                 return null();
             handler.setEndPosition(catchList, pos().end);
             handler.setEndPosition(pnblock, pos().end);
@@ -6042,17 +6073,17 @@ Parser<ParseHandler>::tryStatement(Yield
     if (tt == TOK_FINALLY) {
         MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
         AutoPushStmtInfoPC stmtInfo(*this, StmtType::TRY);
         if (!stmtInfo.generateBlockId())
             return null();
         finallyBlock = statements(yieldHandling);
         if (!finallyBlock)
             return null();
-        MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY);
+        MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_FINALLY);
     } else {
         tokenStream.ungetToken();
     }
     if (!catchList && !finallyBlock) {
         report(ParseError, false, null(), JSMSG_CATCH_OR_FINALLY);
         return null();
     }
 
@@ -6060,17 +6091,17 @@ Parser<ParseHandler>::tryStatement(Yield
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::debuggerStatement()
 {
     TokenPos p;
     p.begin = pos().begin;
-    if (!MatchOrInsertSemicolon(tokenStream))
+    if (!MatchOrInsertSemicolon(tokenStream, TokenStream::Operand))
         return null();
     p.end = pos().end;
 
     pc->sc->setBindingsAccessedDynamically();
     pc->sc->setHasDebuggerStatement();
 
     return handler.newDebuggerStatement(p);
 }
@@ -6705,17 +6736,17 @@ Parser<ParseHandler>::assignExpr(InHandl
             return null();
         }
 
         tokenStream.seek(start);
         if (!abortIfSyntaxParser())
             return null();
 
         TokenKind ignored;
-        if (!tokenStream.peekToken(&ignored))
+        if (!tokenStream.peekToken(&ignored, TokenStream::Operand))
             return null();
 
         if (pc->sc->isFunctionBox() && pc->sc->asFunctionBox()->isDerivedClassConstructor()) {
             report(ParseError, false, null(), JSMSG_DISABLED_DERIVED_CLASS, "arrow functions");
             return null();
         }
 
         return functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator);
@@ -6948,17 +6979,17 @@ Parser<ParseHandler>::unaryExpr(YieldHan
       }
 
       default: {
         Node pn = memberExpr(yieldHandling, tt, /* allowCallSyntax = */ true, invoked);
         if (!pn)
             return null();
 
         /* Don't look across a newline boundary for a postfix incop. */
-        if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
+        if (!tokenStream.peekTokenSameLine(&tt))
             return null();
         if (tt == TOK_INC || tt == TOK_DEC) {
             tokenStream.consumeKnownToken(tt);
             AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment;
             if (!checkAndMarkAsIncOperand(pn, flavor))
                 return null();
             return handler.newUnary((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT,
                                     JSOP_NOP,
@@ -8267,35 +8298,36 @@ Parser<ParseHandler>::arrayInitializer(Y
          * determine their type.
          */
         handler.setListFlag(literal, PNX_NONCONST);
     } else {
         tokenStream.ungetToken();
 
         bool spread = false, missingTrailingComma = false;
         uint32_t index = 0;
+        TokenStream::Modifier modifier = TokenStream::Operand;
         for (; ; index++) {
             if (index == NativeObject::NELEMENTS_LIMIT) {
                 report(ParseError, false, null(), JSMSG_ARRAY_INIT_TOO_BIG);
                 return null();
             }
 
             TokenKind tt;
             if (!tokenStream.peekToken(&tt, TokenStream::Operand))
                 return null();
             if (tt == TOK_RB)
                 break;
 
             if (tt == TOK_COMMA) {
-                tokenStream.consumeKnownToken(TOK_COMMA);
+                tokenStream.consumeKnownToken(TOK_COMMA, TokenStream::Operand);
                 if (!handler.addElision(literal, pos()))
                     return null();
             } else if (tt == TOK_TRIPLEDOT) {
                 spread = true;
-                tokenStream.consumeKnownToken(TOK_TRIPLEDOT);
+                tokenStream.consumeKnownToken(TOK_TRIPLEDOT, TokenStream::Operand);
                 uint32_t begin = pos().begin;
                 Node inner = assignExpr(InAllowed, yieldHandling);
                 if (!inner)
                     return null();
                 if (!handler.addSpreadElement(literal, begin, inner))
                     return null();
             } else {
                 Node element = assignExpr(InAllowed, yieldHandling);
@@ -8308,16 +8340,17 @@ Parser<ParseHandler>::arrayInitializer(Y
 
             if (tt != TOK_COMMA) {
                 /* If we didn't already match TOK_COMMA in above case. */
                 bool matched;
                 if (!tokenStream.matchToken(&matched, TOK_COMMA))
                     return null();
                 if (!matched) {
                     missingTrailingComma = true;
+                    modifier = TokenStream::None;
                     break;
                 }
             }
         }
 
         /*
          * At this point, (index == 0 && missingTrailingComma) implies one
          * element initialiser was parsed.
@@ -8362,23 +8395,24 @@ Parser<ParseHandler>::arrayInitializer(Y
          * slot's stack index from fp->spbase.
          *
          * The legacy array comprehension iteration step, array.push(i * j) in
          * the example above, is done by <i * j>; JSOP_ARRAYPUSH <array>, where
          * <array> is the index of array's stack slot.
          */
         if (index == 0 && !spread) {
             bool matched;
-            if (!tokenStream.matchToken(&matched, TOK_FOR))
+            if (!tokenStream.matchToken(&matched, TOK_FOR, modifier))
                 return null();
             if (matched && missingTrailingComma)
                 return legacyArrayComprehension(literal);
-        }
-
-        MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST);
+            if (matched)
+                modifier = TokenStream::None;
+        }
+        MUST_MATCH_TOKEN_MOD(TOK_RB, modifier, JSMSG_BRACKET_AFTER_LIST);
     }
     handler.setEndPosition(literal, pos().end);
     return literal;
 }
 
 static JSAtom*
 DoubleToAtom(ExclusiveContext* cx, double value)
 {
@@ -8540,16 +8574,17 @@ Parser<ParseHandler>::propertyList(Yield
                 if (!propname)
                     return null();
             } else {
                 // Not an accessor property after all.
                 tokenStream.ungetToken();
                 propname = handler.newObjectLiteralPropertyName(atom, pos());
                 if (!propname)
                     return null();
+                tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName);
                 op = JSOP_INITPROP;
                 break;
             }
 
             MOZ_ASSERT(op == JSOP_INITPROP_GETTER || op == JSOP_INITPROP_SETTER);
             break;
           }
 
@@ -8567,18 +8602,20 @@ Parser<ParseHandler>::propertyList(Yield
             }
             break;
           }
 
           default:
             // There is never a case in which |static *(| can make a meaningful method definition.
             if (isStatic && !isGenerator) {
                 // Turns out it wasn't static. Put it back and pretend it was a name all along.
+                tokenStream.ungetToken();
+                if (isStatic)
+                    tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName);
                 isStatic = false;
-                tokenStream.ungetToken();
                 atom = tokenStream.currentName();
                 propname = handler.newObjectLiteralPropertyName(atom->asPropertyName(), pos());
                 if (!propname)
                     return null();
             } else {
                 report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
                 return null();
             }
@@ -8803,17 +8840,17 @@ Parser<ParseHandler>::primaryExpr(YieldH
         TokenKind next;
         if (!tokenStream.peekToken(&next, TokenStream::Operand))
             return null();
         if (next != TOK_RP)
             return parenExprOrGeneratorComprehension(yieldHandling);
 
         // Not valid expression syntax, but this is valid in an arrow function
         // with no params: `() => body`.
-        tokenStream.consumeKnownToken(next);
+        tokenStream.consumeKnownToken(next, TokenStream::Operand);
 
         if (!tokenStream.peekToken(&next))
             return null();
         if (next != TOK_ARROW) {
             report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
                    "expression", TokenKindToDesc(TOK_RP));
             return null();
         }
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -1640,16 +1640,23 @@ TokenStream::getTokenInternal(TokenKind*
     MOZ_CRASH("should have jumped to |out| or |error|");
 
   out:
     if (flags.hitOOM)
         return reportError(JSMSG_OUT_OF_MEMORY);
 
     flags.isDirtyLine = true;
     tp->pos.end = userbuf.offset();
+#ifdef DEBUG
+    // Save the modifier used to get this token, so that if an ungetToken()
+    // occurs and then the token is re-gotten (or peeked, etc.), we can assert
+    // that both gets have used the same modifiers.
+    tp->modifier = modifier;
+    tp->modifierExceptions = NoException;
+#endif
     MOZ_ASSERT(IsTokenSane(tp));
     *ttp = tp->type;
     return true;
 
   error:
     if (flags.hitOOM)
         return reportError(JSMSG_OUT_OF_MEMORY);
 
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef frontend_TokenStream_h
 #define frontend_TokenStream_h
 
 // JS lexical scanner interface.
 
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/UniquePtr.h"
 
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
 
@@ -71,32 +73,76 @@ struct TokenPos {
 
     bool encloses(const TokenPos& pos) const {
         return begin <= pos.begin && pos.end <= end;
     }
 };
 
 enum DecimalPoint { NoDecimal = false, HasDecimal = true };
 
+class TokenStream;
+
 struct Token
 {
+  private:
+    // Sometimes the parser needs to inform the tokenizer to interpret
+    // subsequent text in a particular manner: for example, to tokenize a
+    // keyword as an identifier, not as the actual keyword, on the right-hand
+    // side of a dotted property access.  Such information is communicated to
+    // the tokenizer as a Modifier when getting the next token.
+    //
+    // Ideally this definition would reside in TokenStream as that's the real
+    // user, but the debugging-use of it here causes a cyclic dependency (and
+    // C++ provides no way to forward-declare an enum inside a class).  So
+    // define it here, then typedef it into TokenStream with static consts to
+    // bring the initializers into scope.
+    enum Modifier
+    {
+        // Normal operation.
+        None,
+
+        // Looking for an operand, not an operator.  In practice, this means
+        // that when '/' is seen, we look for a regexp instead of just returning
+        // TOK_DIV.
+        Operand,
+
+        // Treat keywords as names by returning TOK_NAME.
+        KeywordIsName,
+
+        // Treat subsequent characters as the tail of a template literal, after
+        // a template substitution, beginning with a "}", continuing with zero
+        // or more template literal characters, and ending with either "${" or
+        // the end of the template literal.  For example:
+        //
+        //   var entity = "world";
+        //   var s = `Hello ${entity}!`;
+        //                          ^ TemplateTail context
+        TemplateTail,
+    };
+    friend class TokenStream;
+
+  public:
     TokenKind           type;           // char value or above enumerator
     TokenPos            pos;            // token position in file
     union {
       private:
         friend struct Token;
         PropertyName*   name;          // non-numeric atom
         JSAtom*         atom;          // potentially-numeric atom
         struct {
             double      value;          // floating point number
             DecimalPoint decimalPoint;  // literal contains '.'
         } number;
         RegExpFlag      reflags;        // regexp flags; use tokenbuf to access
                                         //   regexp chars
     } u;
+#ifdef DEBUG
+    Modifier modifier;                  // Modifier used to get this token
+    uint8_t modifierExceptions;         // Bitwise OR of modifier exceptions
+#endif
 
     // This constructor is necessary only for MSVC 2013 and how it compiles the
     // initialization of TokenStream::tokens.  That field is initialized as
     // tokens() in the constructor init-list.  This *should* zero the entire
     // array, then (because Token has a non-trivial constructor, because
     // TokenPos has a user-provided constructor) call the implicit Token
     // constructor on each element, which would call the TokenPos constructor
     // for Token::pos and do nothing.  (All of which is equivalent to just
@@ -354,38 +400,119 @@ class MOZ_STACK_CLASS TokenStream
         bool hitOOM:1;          // Hit OOM.
 
         Flags()
           : isEOF(), isDirtyLine(), sawOctalEscape(), hadError(), hitOOM()
         {}
     };
 
   public:
-    // Sometimes the parser needs to modify how tokens are created.
-    enum Modifier
+    typedef Token::Modifier Modifier;
+    static MOZ_CONSTEXPR_VAR Modifier None = Token::None;
+    static MOZ_CONSTEXPR_VAR Modifier Operand = Token::Operand;
+    static MOZ_CONSTEXPR_VAR Modifier KeywordIsName = Token::KeywordIsName;
+    static MOZ_CONSTEXPR_VAR Modifier TemplateTail = Token::TemplateTail;
+
+    enum ModifierException
     {
-        None,           // Normal operation.
-        Operand,        // Looking for an operand, not an operator.  In
-                        //   practice, this means that when '/' is seen,
-                        //   we look for a regexp instead of just returning
-                        //   TOK_DIV.
-        KeywordIsName,  // Treat keywords as names by returning TOK_NAME.
-        TemplateTail,   // Treat next characters as part of a template string
+        NoException = 0x00,
+
+        // If a semicolon is inserted automatically, the next token is already
+        // gotten with None, but we expect Operand.
+        NoneIsOperand = 0x01,
+
+        // If an yield expression operand is omitted, the next token is already
+        // gotten with Operand, but we expect operator (None).
+        OperandIsNone = 0x02,
+
+        // If name of method definition is `get` or `set`, the next token is
+        // already gotten with KeywordIsName, but we expect None.
+        NoneIsKeywordIsName = 0x04,
     };
 
+    void addModifierException(ModifierException modifierException) {
+#ifdef DEBUG
+        const Token& next = nextToken();
+        switch (modifierException) {
+          case NoneIsOperand:
+            MOZ_ASSERT(next.modifier == Operand);
+            MOZ_ASSERT(next.type != TOK_DIV && next.type != TOK_REGEXP,
+                       "next token requires contextual specifier to be parsed unambiguously");
+            break;
+          case OperandIsNone:
+            // Non-Operand token after yield/continue/break already has
+            // NoneIsOperand exception.
+            MOZ_ASSERT(next.modifier == None ||
+                       ((next.modifierExceptions & NoneIsOperand) && next.modifier == Operand));
+            MOZ_ASSERT(next.type != TOK_DIV && next.type != TOK_REGEXP,
+                       "next token requires contextual specifier to be parsed unambiguously");
+            break;
+          case NoneIsKeywordIsName:
+            MOZ_ASSERT(next.modifier == KeywordIsName);
+            MOZ_ASSERT(next.type != TOK_NAME);
+            break;
+          default:
+            MOZ_CRASH("unexpected modifier exception");
+        }
+        tokens[(cursor + 1) & ntokensMask].modifierExceptions |= modifierException;
+#endif
+    }
+
+    bool hasLookahead() { return lookahead > 0; }
+
+    Modifier getLookaheadModifier() {
+#ifdef DEBUG
+        return nextToken().modifier;
+#else
+        return None;
+#endif
+    }
+
+    void
+    verifyConsistentModifier(Modifier modifier, Token lookaheadToken) {
+#ifdef DEBUG
+        // Easy case: modifiers match.
+        if (modifier == lookaheadToken.modifier)
+            return;
+
+        if (lookaheadToken.modifierExceptions & OperandIsNone) {
+            // getToken(Operand) permissibly following getToken().
+            if (modifier == Operand && lookaheadToken.modifier == None)
+                return;
+        }
+
+        if (lookaheadToken.modifierExceptions & NoneIsOperand) {
+            // getToken() permissibly following getToken(Operand).
+            if (modifier == None && lookaheadToken.modifier == Operand)
+                return;
+        }
+
+        if (lookaheadToken.modifierExceptions & NoneIsKeywordIsName) {
+            // getToken() permissibly following getToken(KeywordIsName).
+            if (modifier == None && lookaheadToken.modifier == KeywordIsName)
+                return;
+        }
+
+        MOZ_ASSERT_UNREACHABLE("this token was previously looked up with a "
+                               "different modifier, potentially making "
+                               "tokenization non-deterministic");
+#endif
+    }
+
     // Advance to the next token.  If the token stream encountered an error,
     // return false.  Otherwise return true and store the token kind in |*ttp|.
     bool getToken(TokenKind* ttp, Modifier modifier = None) {
         // Check for a pushed-back token resulting from mismatching lookahead.
         if (lookahead != 0) {
             MOZ_ASSERT(!flags.hadError);
             lookahead--;
             cursor = (cursor + 1) & ntokensMask;
             TokenKind tt = currentToken().type;
             MOZ_ASSERT(tt != TOK_EOL);
+            verifyConsistentModifier(modifier, currentToken());
             *ttp = tt;
             return true;
         }
 
         return getTokenInternal(ttp, modifier);
     }
 
     // Push the last scanned token back into the stream.
@@ -393,36 +520,38 @@ class MOZ_STACK_CLASS TokenStream
         MOZ_ASSERT(lookahead < maxLookahead);
         lookahead++;
         cursor = (cursor - 1) & ntokensMask;
     }
 
     bool peekToken(TokenKind* ttp, Modifier modifier = None) {
         if (lookahead > 0) {
             MOZ_ASSERT(!flags.hadError);
-            *ttp = tokens[(cursor + 1) & ntokensMask].type;
+            verifyConsistentModifier(modifier, nextToken());
+            *ttp = nextToken().type;
             return true;
         }
         if (!getTokenInternal(ttp, modifier))
             return false;
         ungetToken();
         return true;
     }
 
     bool peekTokenPos(TokenPos* posp, Modifier modifier = None) {
         if (lookahead == 0) {
             TokenKind tt;
             if (!getTokenInternal(&tt, modifier))
                 return false;
             ungetToken();
-            MOZ_ASSERT(lookahead != 0);
+            MOZ_ASSERT(hasLookahead());
         } else {
             MOZ_ASSERT(!flags.hadError);
+            verifyConsistentModifier(modifier, nextToken());
         }
-        *posp = tokens[(cursor + 1) & ntokensMask].pos;
+        *posp = nextToken().pos;
         return true;
     }
 
     // This is like peekToken(), with one exception:  if there is an EOL
     // between the end of the current token and the start of the next token, it
     // return true and store TOK_EOL in |*ttp|.  In that case, no token with
     // TOK_EOL is actually created, just a TOK_EOL TokenKind is returned, and
     // currentToken() shouldn't be consulted.  (This is the only place TOK_EOL
@@ -437,17 +566,18 @@ class MOZ_STACK_CLASS TokenStream
         // stronger condition than what we are looking for, and we don't need
         // to return TOK_EOL.
         if (lookahead != 0) {
             bool onThisLine;
             if (!srcCoords.isOnThisLine(curr.pos.end, lineno, &onThisLine))
                 return reportError(JSMSG_OUT_OF_MEMORY);
             if (onThisLine) {
                 MOZ_ASSERT(!flags.hadError);
-                *ttp = tokens[(cursor + 1) & ntokensMask].type;
+                verifyConsistentModifier(modifier, nextToken());
+                *ttp = nextToken().type;
                 return true;
             }
         }
 
         // The above check misses two cases where we don't have to return
         // TOK_EOL.
         // - The next token starts on the same line, but is a multi-line token.
         // - The next token starts on the same line, but lookahead==2 and there
@@ -475,20 +605,20 @@ class MOZ_STACK_CLASS TokenStream
             *matchedp = true;
         } else {
             ungetToken();
             *matchedp = false;
         }
         return true;
     }
 
-    void consumeKnownToken(TokenKind tt) {
+    void consumeKnownToken(TokenKind tt, Modifier modifier = None) {
         bool matched;
-        MOZ_ASSERT(lookahead != 0);
-        MOZ_ALWAYS_TRUE(matchToken(&matched, tt));
+        MOZ_ASSERT(hasLookahead());
+        MOZ_ALWAYS_TRUE(matchToken(&matched, tt, modifier));
         MOZ_ALWAYS_TRUE(matched);
     }
 
     bool matchContextualKeyword(bool* matchedp, Handle<PropertyName*> keyword) {
         TokenKind token;
         if (!getToken(&token))
             return false;
         if (token == TOK_NAME && currentToken().name() == keyword) {
@@ -816,16 +946,21 @@ class MOZ_STACK_CLASS TokenStream
     void skipChars(int n) {
         while (--n >= 0)
             getChar();
     }
 
     void updateLineInfoForEOL();
     void updateFlagsForEOL();
 
+    const Token& nextToken() {
+        MOZ_ASSERT(hasLookahead());
+        return tokens[(cursor + 1) & ntokensMask];
+    }
+
     // Options used for parsing/tokenizing.
     const ReadOnlyCompileOptions& options_;
 
     Token               tokens[ntokens];    // circular token buffer
     unsigned            cursor;             // index of last parsed token
     unsigned            lookahead;          // count of lookahead tokens
     unsigned            lineno;             // current line number
     Flags               flags;              // flags -- see above
--- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
@@ -390,17 +390,17 @@ NativeRegExpMacroAssembler::GenerateCode
         Label grow_failed;
 
         masm.movePtr(ImmPtr(runtime), temp1);
 
         // Save registers before calling C function
         LiveGeneralRegisterSet volatileRegs(GeneralRegisterSet::Volatile());
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
         volatileRegs.add(Register::FromCode(Registers::lr));
-#elif defined(JS_CODEGEN_MIPS)
+#elif defined(JS_CODEGEN_MIPS32)
         volatileRegs.add(Register::FromCode(Registers::ra));
 #endif
         volatileRegs.takeUnchecked(temp0);
         volatileRegs.takeUnchecked(temp1);
         masm.PushRegsInMask(volatileRegs);
 
         masm.setupUnalignedABICall(1, temp0);
         masm.passABIArg(temp1);
@@ -1319,17 +1319,17 @@ NativeRegExpMacroAssembler::CheckSpecial
     }
 }