merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 21 Nov 2014 12:57:00 +0100
changeset 241137 23ca43337c3f5db036d1cbb72b291460c37ba055
parent 241110 5ba06e4f49e8af5d49a1752a32afccfd1a170a4b (current diff)
parent 241136 794b5fca57b02ec6d0e9275431b90262c6d962a1 (diff)
child 241148 3366c0fcf9c2dd4fd447079f9ba7b42d21a2d171
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
dom/bindings/parser/tests/test_scalarvaluestring.py
dom/bindings/test/test_scalarvaluestring.html
layout/base/nsDocumentViewer.cpp
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -50,17 +50,17 @@
 @RESPATH@/browser/defaults/profile/chrome/*
 @RESPATH@/browser/defaults/profile/localstore.rdf
 @RESPATH@/browser/defaults/profile/mimeTypes.rdf
 @RESPATH@/dictionaries/*
 @RESPATH@/hyphenation/*
 @RESPATH@/browser/@PREF_DIR@/firefox-l10n.js
 @RESPATH@/browser/searchplugins/*
 #ifdef XP_WIN32
-@RESPATH@/uninstall/helper.exe
+@BINPATH@/uninstall/helper.exe
 #endif
 #ifdef MOZ_UPDATER
 @RESPATH@/update.locale
 @RESPATH@/updater.ini
 #endif
 
 [xpcom]
 @RESPATH@/dependentlibs.list
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2061,17 +2061,17 @@ nsDOMWindowUtils::GetFullZoom(float* aFu
 
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   nsPresContext* presContext = GetPresContext();
   if (!presContext) {
     return NS_OK;
   }
 
-  *aFullZoom = presContext->DeviceContext()->GetPixelScale();
+  *aFullZoom = presContext->DeviceContext()->GetFullZoom();
 
   return NS_OK;
 }
  
 NS_IMETHODIMP
 nsDOMWindowUtils::DispatchDOMEventViaPresShell(nsIDOMNode* aTarget,
                                                nsIDOMEvent* aEvent,
                                                bool aTrusted,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -6365,17 +6365,17 @@ nsGlobalWindow::Confirm(const nsAString&
 {
   ErrorResult rv;
   *aReturn = Confirm(aString, rv);
 
   return rv.ErrorCode();
 }
 
 already_AddRefed<Promise>
-nsGlobalWindow::Fetch(const RequestOrScalarValueString& aInput,
+nsGlobalWindow::Fetch(const RequestOrUSVString& aInput,
                       const RequestInit& aInit, ErrorResult& aRv)
 {
   return FetchRequest(this, aInput, aInit, aRv);
 }
 
 void
 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
                        nsAString& aReturn, ErrorResult& aError)
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -105,17 +105,17 @@ class External;
 class Function;
 class Gamepad;
 class MediaQueryList;
 class MozSelfSupport;
 class Navigator;
 class OwningExternalOrWindowProxy;
 class Promise;
 struct RequestInit;
-class RequestOrScalarValueString;
+class RequestOrUSVString;
 class Selection;
 class SpeechSynthesis;
 class WakeLock;
 namespace indexedDB {
 class IDBFactory;
 } // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
@@ -852,17 +852,17 @@ public:
 protected:
   bool AlertOrConfirm(bool aAlert, const nsAString& aMessage,
                       mozilla::ErrorResult& aError);
 
 public:
   void Alert(mozilla::ErrorResult& aError);
   void Alert(const nsAString& aMessage, mozilla::ErrorResult& aError);
   bool Confirm(const nsAString& aMessage, mozilla::ErrorResult& aError);
-  already_AddRefed<mozilla::dom::Promise> Fetch(const mozilla::dom::RequestOrScalarValueString& aInput,
+  already_AddRefed<mozilla::dom::Promise> Fetch(const mozilla::dom::RequestOrUSVString& aInput,
                                                 const mozilla::dom::RequestInit& aInit,
                                                 mozilla::ErrorResult& aRv);
   void Prompt(const nsAString& aMessage, const nsAString& aInitial,
               nsAString& aReturn, mozilla::ErrorResult& aError);
   void Print(mozilla::ErrorResult& aError);
   void ShowModalDialog(JSContext* aCx, const nsAString& aUrl,
                        JS::Handle<JS::Value> aArgument,
                        const nsAString& aOptions,
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2137,42 +2137,42 @@ NonVoidByteStringToJsval(JSContext *cx, 
         return false;
 
     rval.setString(jsStr);
     return true;
 }
 
 
 template<typename T> static void
-NormalizeScalarValueStringInternal(JSContext* aCx, T& aString)
+NormalizeUSVStringInternal(JSContext* aCx, T& aString)
 {
   char16_t* start = aString.BeginWriting();
   // Must use const here because we can't pass char** to UTF16CharEnumerator as
   // it expects const char**.  Unclear why this is illegal...
   const char16_t* nextChar = start;
   const char16_t* end = aString.Data() + aString.Length();
   while (nextChar < end) {
     uint32_t enumerated = UTF16CharEnumerator::NextChar(&nextChar, end);
     if (enumerated == UCS2_REPLACEMENT_CHAR) {
       int32_t lastCharIndex = (nextChar - start) - 1;
       start[lastCharIndex] = static_cast<char16_t>(enumerated);
     }
   }
 }
 
 void
-NormalizeScalarValueString(JSContext* aCx, nsAString& aString)
+NormalizeUSVString(JSContext* aCx, nsAString& aString)
 {
-  NormalizeScalarValueStringInternal(aCx, aString);
+  NormalizeUSVStringInternal(aCx, aString);
 }
 
 void
-NormalizeScalarValueString(JSContext* aCx, binding_detail::FakeString& aString)
+NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString)
 {
-  NormalizeScalarValueStringInternal(aCx, aString);
+  NormalizeUSVStringInternal(aCx, aString);
 }
 
 bool
 ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
                            bool nullable, nsACString& result)
 {
   JS::Rooted<JSString*> s(cx);
   if (v.isString()) {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1918,20 +1918,20 @@ ConvertJSValueToString(JSContext* cx, JS
       return false;
     }
   }
 
   return AssignJSString(cx, result, s);
 }
 
 void
-NormalizeScalarValueString(JSContext* aCx, nsAString& aString);
+NormalizeUSVString(JSContext* aCx, nsAString& aString);
 
 void
-NormalizeScalarValueString(JSContext* aCx, binding_detail::FakeString& aString);
+NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString);
 
 template<typename T>
 inline bool
 ConvertIdToString(JSContext* cx, JS::HandleId id, T& result, bool& isSymbol)
 {
   if (MOZ_LIKELY(JSID_IS_STRING(id))) {
     if (!AssignJSString(cx, result, JSID_TO_STRING(id))) {
       return false;
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4832,17 +4832,17 @@ def getJSToNativeConversionInfo(type, de
             declArgs = None
         return JSToNativeConversionInfo(template,
                                         declType=declType,
                                         holderType=holderType,
                                         dealWithOptional=isOptional,
                                         declArgs=declArgs,
                                         holderArgs=holderArgs)
 
-    if type.isDOMString() or type.isScalarValueString():
+    if type.isDOMString() or type.isUSVString():
         assert not isEnforceRange and not isClamp
 
         treatAs = {
             "Default": "eStringify",
             "EmptyString": "eEmpty",
             "Null": "eNull",
         }
         if type.nullable():
@@ -4851,18 +4851,18 @@ def getJSToNativeConversionInfo(type, de
             # For nullable strings undefined also becomes a null string.
             undefinedBehavior = "eNull"
         else:
             undefinedBehavior = "eStringify"
         nullBehavior = treatAs[treatNullAs]
 
         def getConversionCode(varName):
             normalizeCode = ""
-            if type.isScalarValueString():
-                normalizeCode = "NormalizeScalarValueString(cx, %s);\n" % varName
+            if type.isUSVString():
+                normalizeCode = "NormalizeUSVString(cx, %s);\n" % varName
 
             conversionCode = (
                 "if (!ConvertJSValueToString(cx, ${val}, %s, %s, %s)) {\n"
                 "%s"
                 "}\n"
                 "%s" % (nullBehavior, undefinedBehavior, varName,
                         exceptionCodeIndented.define(), normalizeCode))
 
@@ -5792,17 +5792,17 @@ def getWrapTemplateForType(type, descrip
             else:
                 getIID = ""
             wrap = "WrapObject(cx, %s, %s${jsvalHandle})" % (result, getIID)
             failed = None
 
         wrappingCode += wrapAndSetPtr(wrap, failed)
         return (wrappingCode, False)
 
-    if type.isDOMString() or type.isScalarValueString():
+    if type.isDOMString() or type.isUSVString():
         if type.nullable():
             return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result), False)
         else:
             return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
 
     if type.isByteString():
         if type.nullable():
             return (wrapAndSetPtr("ByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
@@ -6072,17 +6072,17 @@ def getRetvalDeclarationForType(returnTy
     if returnType is None or returnType.isVoid():
         # Nothing to declare
         return None, None, None, None, None
     if returnType.isPrimitive() and returnType.tag() in builtinNames:
         result = CGGeneric(builtinNames[returnType.tag()])
         if returnType.nullable():
             result = CGTemplatedType("Nullable", result)
         return result, None, None, None, None
-    if returnType.isDOMString() or returnType.isScalarValueString():
+    if returnType.isDOMString() or returnType.isUSVString():
         if isMember:
             return CGGeneric("nsString"), "ref", None, None, None
         return CGGeneric("DOMString"), "ref", None, None, None
     if returnType.isByteString():
         return CGGeneric("nsCString"), "ref", None, None, None
     if returnType.isEnum():
         result = CGGeneric(returnType.unroll().inner.identifier.name)
         if returnType.nullable():
@@ -8483,17 +8483,17 @@ def getUnionAccessorSignatureType(type, 
         else:
             typeName = CGWrapper(typeName, post="&")
         return typeName
 
     if type.isSpiderMonkeyInterface():
         typeName = CGGeneric(type.name)
         return CGWrapper(typeName, post=" const &")
 
-    if type.isDOMString() or type.isScalarValueString():
+    if type.isDOMString() or type.isUSVString():
         return CGGeneric("const nsAString&")
 
     if type.isByteString():
         return CGGeneric("const nsCString&")
 
     if type.isEnum():
         return CGGeneric(type.inner.identifier.name)
 
@@ -12462,17 +12462,17 @@ class CGNativeMember(ClassMethod):
             result = CGGeneric(builtinNames[type.tag()])
             defaultReturnArg = "0"
             if type.nullable():
                 result = CGTemplatedType("Nullable", result)
                 defaultReturnArg = ""
             return (result.define(),
                     "%s(%s)" % (result.define(), defaultReturnArg),
                     "return ${declName};\n")
-        if type.isDOMString() or type.isScalarValueString():
+        if type.isDOMString() or type.isUSVString():
             if isMember:
                 # No need for a third element in the isMember case
                 return "nsString", None, None
             # Outparam
             return "void", "", "aRetVal = ${declName};\n"
         if type.isByteString():
             if isMember:
                 # No need for a third element in the isMember case
@@ -12582,17 +12582,17 @@ class CGNativeMember(ClassMethod):
             return "void", "", ""
 
         raise TypeError("Don't know how to declare return value for %s" %
                         type)
 
     def getArgs(self, returnType, argList):
         args = [self.getArg(arg) for arg in argList]
         # Now the outparams
-        if returnType.isDOMString() or returnType.isScalarValueString():
+        if returnType.isDOMString() or returnType.isUSVString():
             args.append(Argument("nsString&", "aRetVal"))
         elif returnType.isByteString():
             args.append(Argument("nsCString&", "aRetVal"))
         elif returnType.isSequence():
             nullable = returnType.nullable()
             if nullable:
                 returnType = returnType.inner
             # And now the actual underlying type
@@ -12709,17 +12709,17 @@ class CGNativeMember(ClassMethod):
 
         if type.isSpiderMonkeyInterface():
             if not self.typedArraysAreStructs:
                 return "JS::Handle<JSObject*>", False, False
 
             # Unroll for the name, in case we're nullable.
             return type.unroll().name, True, True
 
-        if type.isDOMString() or type.isScalarValueString():
+        if type.isDOMString() or type.isUSVString():
             if isMember:
                 declType = "nsString"
             else:
                 declType = "nsAString"
             return declType, True, False
 
         if type.isByteString():
             declType = "nsCString"
@@ -14582,17 +14582,17 @@ class CGEventGetter(CGNativeMember):
             raise TypeError("Event code generators does not support static attributes")
         return CGNativeMember.getArgs(self, returnType, argList)
 
     def getMethodBody(self):
         type = self.member.type
         memberName = CGDictionary.makeMemberName(self.member.identifier.name)
         if (type.isPrimitive() and type.tag() in builtinNames) or type.isEnum() or type.isGeckoInterface():
             return "return " + memberName + ";\n"
-        if type.isDOMString() or type.isByteString() or type.isScalarValueString():
+        if type.isDOMString() or type.isByteString() or type.isUSVString():
             return "aRetVal = " + memberName + ";\n"
         if type.isSpiderMonkeyInterface() or type.isObject():
             return fill(
                 """
                 if (${memberName}) {
                   JS::ExposeObjectToActiveJS(${memberName});
                 }
                 aRetVal.set(${memberName});
@@ -14975,17 +14975,17 @@ class CGEventClass(CGBindingImplClass):
         if type.isPrimitive() and type.tag() in builtinNames:
             nativeType = CGGeneric(builtinNames[type.tag()])
             if type.nullable():
                 nativeType = CGTemplatedType("Nullable", nativeType)
         elif type.isEnum():
             nativeType = CGGeneric(type.unroll().inner.identifier.name)
             if type.nullable():
                 nativeType = CGTemplatedType("Nullable", nativeType)
-        elif type.isDOMString() or type.isScalarValueString():
+        elif type.isDOMString() or type.isUSVString():
             nativeType = CGGeneric("nsString")
         elif type.isByteString():
             nativeType = CGGeneric("nsCString")
         elif type.isGeckoInterface():
             iface = type.unroll().inner
             nativeType = self.descriptor.getDescriptor(
                 iface.identifier.name).nativeType
             # Now trim off unnecessary namespaces
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1567,17 +1567,17 @@ class IDLType(IDLObject):
         'float',
         'unrestricted_double',
         # "double" last primitive type to match IDLBuiltinType
         'double',
         # Other types
         'any',
         'domstring',
         'bytestring',
-        'scalarvaluestring',
+        'usvstring',
         'object',
         'date',
         'void',
         # Funny stuff
         'interface',
         'dictionary',
         'enum',
         'callback',
@@ -1620,17 +1620,17 @@ class IDLType(IDLObject):
         return False
 
     def isByteString(self):
         return False
 
     def isDOMString(self):
         return False
 
-    def isScalarValueString(self):
+    def isUSVString(self):
         return False
 
     def isVoid(self):
         return self.name == "Void"
 
     def isSequence(self):
         return False
 
@@ -1806,18 +1806,18 @@ class IDLNullableType(IDLType):
         return self.inner.isString()
 
     def isByteString(self):
         return self.inner.isByteString()
 
     def isDOMString(self):
         return self.inner.isDOMString()
 
-    def isScalarValueString(self):
-        return self.inner.isScalarValueString()
+    def isUSVString(self):
+        return self.inner.isUSVString()
 
     def isFloat(self):
         return self.inner.isFloat()
 
     def isUnrestricted(self):
         return self.inner.isUnrestricted()
 
     def includesRestrictedFloat(self):
@@ -1934,17 +1934,17 @@ class IDLSequenceType(IDLType):
         return False;
 
     def isByteString(self):
         return False
 
     def isDOMString(self):
         return False
 
-    def isScalarValueString(self):
+    def isUSVString(self):
         return False
 
     def isVoid(self):
         return False
 
     def isSequence(self):
         return True
 
@@ -2208,17 +2208,17 @@ class IDLArrayType(IDLType):
         return False
 
     def isByteString(self):
         return False
 
     def isDOMString(self):
         return False
 
-    def isScalarValueString(self):
+    def isUSVString(self):
         return False
 
     def isVoid(self):
         return False
 
     def isSequence(self):
         assert not self.inner.isSequence()
         return False
@@ -2306,18 +2306,18 @@ class IDLTypedefType(IDLType, IDLObjectW
         return self.inner.isString()
 
     def isByteString(self):
         return self.inner.isByteString()
 
     def isDOMString(self):
         return self.inner.isDOMString()
 
-    def isScalarValueString(self):
-        return self.inner.isScalarValueString()
+    def isUSVString(self):
+        return self.inner.isUSVString()
 
     def isVoid(self):
         return self.inner.isVoid()
 
     def isSequence(self):
         return self.inner.isSequence()
 
     def isMozMap(self):
@@ -2407,17 +2407,17 @@ class IDLWrapperType(IDLType):
         return False
 
     def isByteString(self):
         return False
 
     def isDOMString(self):
         return False
 
-    def isScalarValueString(self):
+    def isUSVString(self):
         return False
 
     def isVoid(self):
         return False
 
     def isSequence(self):
         return False
 
@@ -2561,17 +2561,17 @@ class IDLBuiltinType(IDLType):
         'float',
         'unrestricted_double',
         # IMPORTANT: "double" must be the last primitive type listed
         'double',
         # Other types
         'any',
         'domstring',
         'bytestring',
-        'scalarvaluestring',
+        'usvstring',
         'object',
         'date',
         'void',
         # Funny stuff
         'ArrayBuffer',
         'ArrayBufferView',
         'Int8Array',
         'Uint8Array',
@@ -2596,17 +2596,17 @@ class IDLBuiltinType(IDLType):
             Types.boolean: IDLType.Tags.bool,
             Types.unrestricted_float: IDLType.Tags.unrestricted_float,
             Types.float: IDLType.Tags.float,
             Types.unrestricted_double: IDLType.Tags.unrestricted_double,
             Types.double: IDLType.Tags.double,
             Types.any: IDLType.Tags.any,
             Types.domstring: IDLType.Tags.domstring,
             Types.bytestring: IDLType.Tags.bytestring,
-            Types.scalarvaluestring: IDLType.Tags.scalarvaluestring,
+            Types.usvstring: IDLType.Tags.usvstring,
             Types.object: IDLType.Tags.object,
             Types.date: IDLType.Tags.date,
             Types.void: IDLType.Tags.void,
             Types.ArrayBuffer: IDLType.Tags.interface,
             Types.ArrayBufferView: IDLType.Tags.interface,
             Types.Int8Array: IDLType.Tags.interface,
             Types.Uint8Array: IDLType.Tags.interface,
             Types.Uint8ClampedArray: IDLType.Tags.interface,
@@ -2630,26 +2630,26 @@ class IDLBuiltinType(IDLType):
         return self._typeTag == IDLBuiltinType.Types.boolean
 
     def isNumeric(self):
         return self.isPrimitive() and not self.isBoolean()
 
     def isString(self):
         return self._typeTag == IDLBuiltinType.Types.domstring or \
                self._typeTag == IDLBuiltinType.Types.bytestring or \
-               self._typeTag == IDLBuiltinType.Types.scalarvaluestring
+               self._typeTag == IDLBuiltinType.Types.usvstring
 
     def isByteString(self):
         return self._typeTag == IDLBuiltinType.Types.bytestring
 
     def isDOMString(self):
         return self._typeTag == IDLBuiltinType.Types.domstring
 
-    def isScalarValueString(self):
-        return self._typeTag == IDLBuiltinType.Types.scalarvaluestring
+    def isUSVString(self):
+        return self._typeTag == IDLBuiltinType.Types.usvstring
 
     def isInteger(self):
         return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long
 
     def isArrayBuffer(self):
         return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
 
     def isArrayBufferView(self):
@@ -2793,19 +2793,19 @@ BuiltinTypes = {
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Any",
                          IDLBuiltinType.Types.any),
       IDLBuiltinType.Types.domstring:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "String",
                          IDLBuiltinType.Types.domstring),
       IDLBuiltinType.Types.bytestring:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "ByteString",
                          IDLBuiltinType.Types.bytestring),
-      IDLBuiltinType.Types.scalarvaluestring:
-          IDLBuiltinType(BuiltinLocation("<builtin type>"), "ScalarValueString",
-                         IDLBuiltinType.Types.scalarvaluestring),
+      IDLBuiltinType.Types.usvstring:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "USVString",
+                         IDLBuiltinType.Types.usvstring),
       IDLBuiltinType.Types.object:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Object",
                          IDLBuiltinType.Types.object),
       IDLBuiltinType.Types.date:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Date",
                          IDLBuiltinType.Types.date),
       IDLBuiltinType.Types.void:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Void",
@@ -2930,20 +2930,20 @@ class IDLValue(IDLObject):
             return self
         elif self.type.isFloat() and type.isFloat():
             if (not type.isUnrestricted() and
                 (self.value == float("inf") or self.value == float("-inf") or
                  math.isnan(self.value))):
                 raise WebIDLError("Trying to convert unrestricted value %s to non-unrestricted"
                                   % self.value, [location]);
             return self
-        elif self.type.isString() and type.isScalarValueString():
-            # Allow ScalarValueStrings to use default value just like
+        elif self.type.isString() and type.isUSVString():
+            # Allow USVStrings to use default value just like
             # DOMString.  No coercion is required in this case as Codegen.py
-            # treats ScalarValueString just like DOMString, but with an
+            # treats USVString just like DOMString, but with an
             # extra normalization step.
             assert self.type.isDOMString()
             return self
         raise WebIDLError("Cannot coerce type %s to type %s." %
                           (self.type, type), [location])
 
     def _getDependentObjects(self):
         return set()
@@ -4163,17 +4163,17 @@ class Tokenizer(object):
         "deleter": "DELETER",
         "legacycaller": "LEGACYCALLER",
         "optional": "OPTIONAL",
         "...": "ELLIPSIS",
         "::": "SCOPE",
         "Date": "DATE",
         "DOMString": "DOMSTRING",
         "ByteString": "BYTESTRING",
-        "ScalarValueString": "SCALARVALUESTRING",
+        "USVString": "USVSTRING",
         "any": "ANY",
         "boolean": "BOOLEAN",
         "byte": "BYTE",
         "double": "DOUBLE",
         "float": "FLOAT",
         "long": "LONG",
         "object": "OBJECT",
         "octet": "OCTET",
@@ -5127,17 +5127,17 @@ class Parser(Tokenizer):
                   | SEMICOLON
                   | LT
                   | EQUALS
                   | GT
                   | QUESTIONMARK
                   | DATE
                   | DOMSTRING
                   | BYTESTRING
-                  | SCALARVALUESTRING
+                  | USVSTRING
                   | ANY
                   | ATTRIBUTE
                   | BOOLEAN
                   | BYTE
                   | LEGACYCALLER
                   | CONST
                   | CREATOR
                   | DELETER
@@ -5400,21 +5400,21 @@ class Parser(Tokenizer):
         p[0] = IDLBuiltinType.Types.domstring
 
     def p_PrimitiveOrStringTypeBytestring(self, p):
         """
             PrimitiveOrStringType : BYTESTRING
         """
         p[0] = IDLBuiltinType.Types.bytestring
 
-    def p_PrimitiveOrStringTypeScalarValueString(self, p):
-        """
-            PrimitiveOrStringType : SCALARVALUESTRING
-        """
-        p[0] = IDLBuiltinType.Types.scalarvaluestring
+    def p_PrimitiveOrStringTypeUSVString(self, p):
+        """
+            PrimitiveOrStringType : USVSTRING
+        """
+        p[0] = IDLBuiltinType.Types.usvstring
 
     def p_UnsignedIntegerTypeUnsigned(self, p):
         """
             UnsignedIntegerType : UNSIGNED IntegerType
         """
         p[0] = p[2] + 1 # Adding one to a given signed integer type
                         # gets you the unsigned type.
 
--- a/dom/bindings/parser/tests/test_distinguishability.py
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -155,28 +155,28 @@ def WebIDLTest(parser, harness):
                  "Interface", "Interface?",
                  "AncestorInterface", "UnrelatedInterface",
                  "ImplementedInterface", "CallbackInterface",
                  "CallbackInterface?", "CallbackInterface2",
                  "object", "Callback", "Callback2", "optional Dict",
                  "optional Dict2", "sequence<long>", "sequence<short>",
                  "MozMap<object>", "MozMap<Dict>", "MozMap<long>",
                  "long[]", "short[]", "Date", "Date?", "any",
-                 "ScalarValueString" ]
+                 "USVString" ]
     # When we can parse Date and RegExp, we need to add them here.
 
     # Try to categorize things a bit to keep list lengths down
     def allBut(list1, list2):
         return [a for a in list1 if a not in list2 and a != "any"]
     numerics = [ "long", "short", "long?", "short?" ]
     booleans = [ "boolean", "boolean?" ]
     primitives = numerics + booleans
     nonNumerics = allBut(argTypes, numerics)
     nonBooleans = allBut(argTypes, booleans)
-    strings = [ "DOMString", "ByteString", "Enum", "Enum2", "ScalarValueString" ]
+    strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString" ]
     nonStrings = allBut(argTypes, strings)
     nonObjects = primitives + strings
     objects = allBut(argTypes, nonObjects )
     interfaces = [ "Interface", "Interface?", "AncestorInterface",
                    "UnrelatedInterface", "ImplementedInterface" ]
     nullables = ["long?", "short?", "boolean?", "Interface?",
                  "CallbackInterface?", "optional Dict", "optional Dict2",
                  "Date?", "any"]
@@ -201,17 +201,17 @@ def WebIDLTest(parser, harness):
     setDistinguishable("long", nonNumerics)
     setDistinguishable("short", nonNumerics)
     setDistinguishable("long?", allBut(nonNumerics, nullables))
     setDistinguishable("short?", allBut(nonNumerics, nullables))
     setDistinguishable("boolean", nonBooleans)
     setDistinguishable("boolean?", allBut(nonBooleans, nullables))
     setDistinguishable("DOMString", nonStrings)
     setDistinguishable("ByteString", nonStrings)
-    setDistinguishable("ScalarValueString", nonStrings)
+    setDistinguishable("USVString", nonStrings)
     setDistinguishable("Enum", nonStrings)
     setDistinguishable("Enum2", nonStrings)
     setDistinguishable("Interface", notRelatedInterfaces)
     setDistinguishable("Interface?", allBut(notRelatedInterfaces, nullables))
     setDistinguishable("AncestorInterface", notRelatedInterfaces)
     setDistinguishable("UnrelatedInterface",
                        allBut(argTypes, ["object", "UnrelatedInterface"]))
     setDistinguishable("ImplementedInterface", notRelatedInterfaces)
--- a/dom/bindings/parser/tests/test_union.py
+++ b/dom/bindings/parser/tests/test_union.py
@@ -58,17 +58,17 @@ def WebIDLTest(parser, harness):
              "unsigned long",
              "long long",
              "unsigned long long",
              "boolean",
              "byte",
              "octet",
              "DOMString",
              "ByteString",
-             "ScalarValueString",
+             "USVString",
              #"sequence<float>",
              "object",
              "ArrayBuffer",
              #"Date",
              "TestInterface1",
              "TestInterface2"]
 
     testPre = """
rename from dom/bindings/parser/tests/test_scalarvaluestring.py
rename to dom/bindings/parser/tests/test_usvstring.py
--- a/dom/bindings/parser/tests/test_scalarvaluestring.py
+++ b/dom/bindings/parser/tests/test_usvstring.py
@@ -1,36 +1,36 @@
 # -*- coding: UTF-8 -*-
 
 import WebIDL
 
 def WebIDLTest(parser, harness):
     parser.parse("""
-        interface TestScalarValueString {
-          attribute ScalarValueString svs;
+        interface TestUSVString {
+          attribute USVString svs;
         };
     """)
 
     results = parser.finish();
 
     harness.check(len(results), 1, "Should be one production")
     harness.ok(isinstance(results[0], WebIDL.IDLInterface),
                "Should be an IDLInterface")
     iface = results[0]
-    harness.check(iface.identifier.QName(), "::TestScalarValueString",
+    harness.check(iface.identifier.QName(), "::TestUSVString",
                   "Interface has the right QName")
-    harness.check(iface.identifier.name, "TestScalarValueString",
+    harness.check(iface.identifier.name, "TestUSVString",
                   "Interface has the right name")
     harness.check(iface.parent, None, "Interface has no parent")
 
     members = iface.members
     harness.check(len(members), 1, "Should be one member")
 
     attr = members[0]
     harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Should be an IDLAttribute")
-    harness.check(attr.identifier.QName(), "::TestScalarValueString::svs",
+    harness.check(attr.identifier.QName(), "::TestUSVString::svs",
                   "Attr has correct QName")
     harness.check(attr.identifier.name, "svs", "Attr has correct name")
-    harness.check(str(attr.type), "ScalarValueString",
+    harness.check(str(attr.type), "USVString",
                   "Attr type is the correct name")
-    harness.ok(attr.type.isScalarValueString(), "Should be ScalarValueString type")
+    harness.ok(attr.type.isUSVString(), "Should be USVString type")
     harness.ok(attr.type.isString(), "Should be String collective type")
     harness.ok(not attr.type.isDOMString(), "Should be not be DOMString type")
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -475,25 +475,25 @@ public:
 
   // ByteString types
   void PassByteString(const nsCString&);
   void PassNullableByteString(const nsCString&);
   void PassOptionalByteString(const Optional<nsCString>&);
   void PassOptionalNullableByteString(const Optional<nsCString>&);
   void PassVariadicByteString(const Sequence<nsCString>&);
 
-  // ScalarValueString types
-  void PassSVS(const nsAString&);
-  void PassNullableSVS(const nsAString&);
-  void PassOptionalSVS(const Optional<nsAString>&);
-  void PassOptionalSVSWithDefaultValue(const nsAString&);
-  void PassOptionalNullableSVS(const Optional<nsAString>&);
-  void PassOptionalNullableSVSWithDefaultValue(const nsAString&);
-  void PassVariadicSVS(const Sequence<nsString>&);
-  void ReceiveSVS(DOMString&);
+  // USVString types
+  void PassUSVS(const nsAString&);
+  void PassNullableUSVS(const nsAString&);
+  void PassOptionalUSVS(const Optional<nsAString>&);
+  void PassOptionalUSVSWithDefaultValue(const nsAString&);
+  void PassOptionalNullableUSVS(const Optional<nsAString>&);
+  void PassOptionalNullableUSVSWithDefaultValue(const nsAString&);
+  void PassVariadicUSVS(const Sequence<nsString>&);
+  void ReceiveUSVS(DOMString&);
 
   // Enumerated types
   void PassEnum(TestEnum);
   void PassNullableEnum(const Nullable<TestEnum>&);
   void PassOptionalEnum(const Optional<TestEnum>&);
   void PassEnumWithDefault(TestEnum);
   void PassOptionalNullableEnum(const Optional<Nullable<TestEnum> >&);
   void PassOptionalNullableEnumWithDefaultValue(const Nullable<TestEnum>&);
@@ -608,17 +608,17 @@ public:
   void PassUnion26(const ImageDataOrNullSequenceSequenceOrLong&);
   void PassUnion27(const StringSequenceOrEventInit&);
   void PassUnion28(const EventInitOrStringSequence&);
   void PassUnionWithCallback(const EventHandlerNonNullOrNullOrLong& arg);
   void PassUnionWithByteString(const ByteStringOrLong&);
   void PassUnionWithMozMap(const StringMozMapOrString&);
   void PassUnionWithMozMapAndSequence(const StringMozMapOrStringSequence&);
   void PassUnionWithSequenceAndMozMap(const StringSequenceOrStringMozMap&);
-  void PassUnionWithSVS(const ScalarValueStringOrLong&);
+  void PassUnionWithUSVS(const USVStringOrLong&);
 #endif
   void PassNullableUnion(JSContext*, const Nullable<ObjectOrLong>&);
   void PassOptionalUnion(JSContext*, const Optional<ObjectOrLong>&);
   void PassOptionalNullableUnion(JSContext*, const Optional<Nullable<ObjectOrLong> >&);
   void PassOptionalNullableUnionWithDefaultValue(JSContext*, const Nullable<ObjectOrLong>&);
   //void PassUnionWithInterfaces(const TestInterfaceOrTestExternalInterface& arg);
   //void PassUnionWithInterfacesAndNullable(const TestInterfaceOrNullOrTestExternalInterface& arg);
   void PassUnionWithArrayBuffer(const ArrayBufferOrLong&);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -455,25 +455,25 @@ interface TestInterface {
 
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
   void passOptionalNullableByteString(optional ByteString? arg);
   void passVariadicByteString(ByteString... arg);
 
-  // ScalarValueString types
-  void passSVS(ScalarValueString arg);
-  void passNullableSVS(ScalarValueString? arg);
-  void passOptionalSVS(optional ScalarValueString arg);
-  void passOptionalSVSWithDefaultValue(optional ScalarValueString arg = "abc");
-  void passOptionalNullableSVS(optional ScalarValueString? arg);
-  void passOptionalNullableSVSWithDefaultValue(optional ScalarValueString? arg = null);
-  void passVariadicSVS(ScalarValueString... arg);
-  ScalarValueString receiveSVS();
+  // USVString types
+  void passUSVS(USVString arg);
+  void passNullableUSVS(USVString? arg);
+  void passOptionalUSVS(optional USVString arg);
+  void passOptionalUSVSWithDefaultValue(optional USVString arg = "abc");
+  void passOptionalNullableUSVS(optional USVString? arg);
+  void passOptionalNullableUSVSWithDefaultValue(optional USVString? arg = null);
+  void passVariadicUSVS(USVString... arg);
+  USVString receiveUSVS();
 
   // Enumerated types
   void passEnum(TestEnum arg);
   void passNullableEnum(TestEnum? arg);
   void passOptionalEnum(optional TestEnum arg);
   void passEnumWithDefault(optional TestEnum arg = "a");
   void passOptionalNullableEnum(optional TestEnum? arg);
   void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
@@ -573,17 +573,17 @@ interface TestInterface {
   void passUnion26((sequence<sequence<ImageData?>> or long) arg);
   void passUnion27(optional (sequence<DOMString> or EventInit) arg);
   void passUnion28(optional (EventInit or sequence<DOMString>) arg);
   void passUnionWithCallback((EventHandler or long) arg);
   void passUnionWithByteString((ByteString or long) arg);
   void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
   void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
   void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
-  void passUnionWithSVS((ScalarValueString or long) arg);
+  void passUnionWithUSVS((USVString or long) arg);
 #endif
   void passUnionWithNullable((object? or long) arg);
   void passNullableUnion((object or long)? arg);
   void passOptionalUnion(optional (object or long) arg);
   void passOptionalNullableUnion(optional (object or long)? arg);
   void passOptionalNullableUnionWithDefaultValue(optional (object or long)? arg = null);
   //void passUnionWithInterfaces((TestInterface or TestExternalInterface) arg);
   //void passUnionWithInterfacesAndNullable((TestInterface? or TestExternalInterface) arg);
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -322,25 +322,25 @@ interface TestExampleInterface {
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
   void passOptionalNullableByteString(optional ByteString? arg);
   void passVariadicByteString(ByteString... arg);
   void passUnionByteString((ByteString or long) arg);
 
-  // ScalarValueString types
-  void passSVS(ScalarValueString arg);
-  void passNullableSVS(ScalarValueString? arg);
-  void passOptionalSVS(optional ScalarValueString arg);
-  void passOptionalSVSWithDefaultValue(optional ScalarValueString arg = "abc");
-  void passOptionalNullableSVS(optional ScalarValueString? arg);
-  void passOptionalNullableSVSWithDefaultValue(optional ScalarValueString? arg = null);
-  void passVariadicSVS(ScalarValueString... arg);
-  ScalarValueString receiveSVS();
+  // USVString types
+  void passSVS(USVString arg);
+  void passNullableSVS(USVString? arg);
+  void passOptionalSVS(optional USVString arg);
+  void passOptionalSVSWithDefaultValue(optional USVString arg = "abc");
+  void passOptionalNullableSVS(optional USVString? arg);
+  void passOptionalNullableSVSWithDefaultValue(optional USVString? arg = null);
+  void passVariadicSVS(USVString... arg);
+  USVString receiveSVS();
 
   // Enumerated types
   void passEnum(TestEnum arg);
   void passNullableEnum(TestEnum? arg);
   void passOptionalEnum(optional TestEnum arg);
   void passEnumWithDefault(optional TestEnum arg = "a");
   void passOptionalNullableEnum(optional TestEnum? arg);
   void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
@@ -438,17 +438,17 @@ interface TestExampleInterface {
   void passUnion26((sequence<sequence<ImageData?>> or long) arg);
   void passUnion27(optional (sequence<DOMString> or EventInit) arg);
   void passUnion28(optional (EventInit or sequence<DOMString>) arg);
   void passUnionWithCallback((EventHandler or long) arg);
   void passUnionWithByteString((ByteString or long) arg);
   void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
   void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
   void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
-  void passUnionWithSVS((ScalarValueString or long) arg);
+  void passUnionWithSVS((USVString or long) arg);
 #endif
   void passUnionWithNullable((object? or long) arg);
   void passNullableUnion((object or long)? arg);
   void passOptionalUnion(optional (object or long) arg);
   void passOptionalNullableUnion(optional (object or long)? arg);
   void passOptionalNullableUnionWithDefaultValue(optional (object or long)? arg = null);
   //void passUnionWithInterfaces((TestInterface or TestExternalInterface) arg);
   //void passUnionWithInterfacesAndNullable((TestInterface? or TestExternalInterface) arg);
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -334,25 +334,25 @@ interface TestJSImplInterface {
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
   void passOptionalNullableByteString(optional ByteString? arg);
   void passVariadicByteString(ByteString... arg);
   void PassUnionByteString((ByteString or long) arg);
 
-  // ScalarValueString types
-  void passSVS(ScalarValueString arg);
-  void passNullableSVS(ScalarValueString? arg);
-  void passOptionalSVS(optional ScalarValueString arg);
-  void passOptionalSVSWithDefaultValue(optional ScalarValueString arg = "abc");
-  void passOptionalNullableSVS(optional ScalarValueString? arg);
-  void passOptionalNullableSVSWithDefaultValue(optional ScalarValueString? arg = null);
-  void passVariadicSVS(ScalarValueString... arg);
-  ScalarValueString receiveSVS();
+  // USVString types
+  void passSVS(USVString arg);
+  void passNullableSVS(USVString? arg);
+  void passOptionalSVS(optional USVString arg);
+  void passOptionalSVSWithDefaultValue(optional USVString arg = "abc");
+  void passOptionalNullableSVS(optional USVString? arg);
+  void passOptionalNullableSVSWithDefaultValue(optional USVString? arg = null);
+  void passVariadicSVS(USVString... arg);
+  USVString receiveSVS();
 
   // Enumerated types
   void passEnum(MyTestEnum arg);
   void passNullableEnum(MyTestEnum? arg);
   void passOptionalEnum(optional MyTestEnum arg);
   void passEnumWithDefault(optional MyTestEnum arg = "a");
   void passOptionalNullableEnum(optional MyTestEnum? arg);
   void passOptionalNullableEnumWithDefaultValue(optional MyTestEnum? arg = null);
@@ -451,17 +451,17 @@ interface TestJSImplInterface {
   void passUnion26((sequence<sequence<ImageData?>> or long) arg);
   void passUnion27(optional (sequence<DOMString> or EventInit) arg);
   void passUnion28(optional (EventInit or sequence<DOMString>) arg);
   void passUnionWithCallback((EventHandler or long) arg);
   void passUnionWithByteString((ByteString or long) arg);
   void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
   void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
   void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
-  void passUnionWithSVS((ScalarValueString or long) arg);
+  void passUnionWithSVS((USVString or long) arg);
 #endif
   void passUnionWithNullable((object? or long) arg);
   void passNullableUnion((object or long)? arg);
   void passOptionalUnion(optional (object or long) arg);
   void passOptionalNullableUnion(optional (object or long)? arg);
   void passOptionalNullableUnionWithDefaultValue(optional (object or long)? arg = null);
   //void passUnionWithInterfaces((TestJSImplInterface or TestExternalInterface) arg);
   //void passUnionWithInterfacesAndNullable((TestJSImplInterface? or TestExternalInterface) arg);
--- a/dom/bindings/test/mochitest.ini
+++ b/dom/bindings/test/mochitest.ini
@@ -39,17 +39,17 @@ skip-if = (toolkit == 'gonk' && debug) #
 [test_lenientThis.html]
 [test_lookupGetter.html]
 [test_namedNoIndexed.html]
 [test_named_getter_enumerability.html]
 [test_Object.prototype_props.html]
 [test_queryInterface.html]
 [test_returnUnion.html]
 skip-if = debug == false
-[test_scalarvaluestring.html]
+[test_usvstring.html]
 skip-if = debug == false
 [test_sequence_wrapping.html]
 [test_setWithNamedGetterNoNamedSetter.html]
 [test_throwing_method_noDCE.html]
 [test_treat_non_object_as_null.html]
 [test_traceProtos.html]
 [test_sequence_detection.html]
 skip-if = debug == false
rename from dom/bindings/test/test_scalarvaluestring.html
rename to dom/bindings/test/test_usvstring.html
--- a/dom/bindings/test/test_scalarvaluestring.html
+++ b/dom/bindings/test/test_usvstring.html
@@ -1,14 +1,14 @@
 <!-- Any copyright is dedicated to the Public Domain.
    - http://creativecommons.org/publicdomain/zero/1.0/ -->
 <!DOCTYPE HTML>
 <html>
 <head>
-  <title>Test ScalarValueString</title>
+  <title>Test USVString</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <script class="testbody" type="application/javascript">
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() {
   var testInterfaceJS = new TestInterfaceJS();
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -881,17 +881,18 @@ Event::GetScreenCoords(nsPresContext* aP
 
   WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
   if (!guiEvent->widget) {
     return LayoutDeviceIntPoint::ToUntyped(aPoint);
   }
 
   LayoutDeviceIntPoint offset = aPoint +
     LayoutDeviceIntPoint::FromUntyped(guiEvent->widget->WidgetToScreenOffset());
-  nscoord factor = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
+  nscoord factor =
+    aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
   return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
                     nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
 }
 
 // static
 CSSIntPoint
 Event::GetPageCoords(nsPresContext* aPresContext,
                      WidgetEvent* aEvent,
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -27,16 +27,22 @@
 #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"
 #include "mozilla/unused.h"
 
+#ifdef MOZ_TASK_TRACER
+#include "GeckoTaskTracer.h"
+#include "mozilla/dom/Element.h"
+using namespace mozilla::tasktracer;
+#endif
+
 namespace mozilla {
 
 using namespace dom;
 
 class ELMCreationDetector
 {
 public:
   ELMCreationDetector()
@@ -402,16 +408,37 @@ EventDispatcher::Dispatch(nsISupports* a
   NS_ASSERTION(!aTargets || !aEvent->message, "Wrong parameters!");
 
   // If we're dispatching an already created DOMEvent object, make
   // sure it is initialized!
   // If aTargets is non-null, the event isn't going to be dispatched.
   NS_ENSURE_TRUE(aEvent->message || !aDOMEvent || aTargets,
                  NS_ERROR_DOM_INVALID_STATE_ERR);
 
+#ifdef MOZ_TASK_TRACER
+  {
+    if (aDOMEvent) {
+      nsAutoString eventType;
+      aDOMEvent->GetType(eventType);
+
+      nsCOMPtr<Element> element = do_QueryInterface(aTarget);
+      nsAutoString elementId;
+      nsAutoString elementTagName;
+      if (element) {
+        element->GetId(elementId);
+        element->GetTagName(elementTagName);
+      }
+      AddLabel("Event [%s] dispatched at target [id:%s tag:%s]",
+               NS_ConvertUTF16toUTF8(eventType).get(),
+               NS_ConvertUTF16toUTF8(elementId).get(),
+               NS_ConvertUTF16toUTF8(elementTagName).get());
+    }
+  }
+#endif
+
   nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget);
 
   bool retargeted = false;
 
   if (aEvent->mFlags.mRetargetToNonNativeAnonymous) {
     nsCOMPtr<nsIContent> content = do_QueryInterface(target);
     if (content && content->IsInNativeAnonymousSubtree()) {
       nsCOMPtr<EventTarget> newTarget =
--- a/dom/events/UIEvent.h
+++ b/dom/events/UIEvent.h
@@ -55,17 +55,17 @@ public:
     WidgetGUIEvent* event = aEvent->AsGUIEvent();
     if (!event->widget) {
       return LayoutDeviceIntPoint::ToUntyped(aEvent->refPoint);
     }
 
     LayoutDeviceIntPoint offset = aEvent->refPoint +
       LayoutDeviceIntPoint::FromUntyped(event->widget->WidgetToScreenOffset());
     nscoord factor =
-      aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
+      aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
     return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
                       nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
   }
 
   static CSSIntPoint CalculateClientPoint(nsPresContext* aPresContext,
                                           WidgetEvent* aEvent,
                                           CSSIntPoint* aDefaultClientPoint)
   {
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -107,17 +107,17 @@ public:
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     return NS_OK;
   }
 };
 
 already_AddRefed<Promise>
-FetchRequest(nsIGlobalObject* aGlobal, const RequestOrScalarValueString& aInput,
+FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
              const RequestInit& aInit, ErrorResult& aRv)
 {
   nsRefPtr<Promise> p = Promise::Create(aGlobal, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   AutoJSAPI jsapi;
@@ -311,17 +311,17 @@ ExtractFromBlob(const File& aFile, nsIIn
 
   nsString type;
   impl->GetType(type);
   aContentType = NS_ConvertUTF16toUTF8(type);
   return NS_OK;
 }
 
 nsresult
-ExtractFromScalarValueString(const nsString& aStr,
+ExtractFromUSVString(const nsString& aStr,
                              nsIInputStream** aStream,
                              nsCString& aContentType)
 {
   nsCOMPtr<nsIUnicodeEncoder> encoder = EncodingUtils::EncoderForEncoding("UTF-8");
   if (!encoder) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
@@ -360,64 +360,64 @@ ExtractFromURLSearchParams(const URLSear
   nsAutoString serialized;
   aParams.Stringify(serialized);
   aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8");
   return NS_NewStringInputStream(aStream, serialized);
 }
 }
 
 nsresult
-ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType)
 {
   MOZ_ASSERT(aStream);
 
   if (aBodyInit.IsArrayBuffer()) {
     const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
     return ExtractFromArrayBuffer(buf, aStream);
   } else if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream);
   } else if (aBodyInit.IsBlob()) {
     const File& blob = aBodyInit.GetAsBlob();
     return ExtractFromBlob(blob, aStream, aContentType);
-  } else if (aBodyInit.IsScalarValueString()) {
+  } else if (aBodyInit.IsUSVString()) {
     nsAutoString str;
-    str.Assign(aBodyInit.GetAsScalarValueString());
-    return ExtractFromScalarValueString(str, aStream, aContentType);
+    str.Assign(aBodyInit.GetAsUSVString());
+    return ExtractFromUSVString(str, aStream, aContentType);
   } else if (aBodyInit.IsURLSearchParams()) {
     URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
     return ExtractFromURLSearchParams(params, aStream, aContentType);
   }
 
   NS_NOTREACHED("Should never reach here");
   return NS_ERROR_FAILURE;
 }
 
 nsresult
-ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType)
 {
   MOZ_ASSERT(aStream);
 
   if (aBodyInit.IsArrayBuffer()) {
     const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
     return ExtractFromArrayBuffer(buf, aStream);
   } else if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream);
   } else if (aBodyInit.IsBlob()) {
     const File& blob = aBodyInit.GetAsBlob();
     return ExtractFromBlob(blob, aStream, aContentType);
-  } else if (aBodyInit.IsScalarValueString()) {
+  } else if (aBodyInit.IsUSVString()) {
     nsAutoString str;
-    str.Assign(aBodyInit.GetAsScalarValueString());
-    return ExtractFromScalarValueString(str, aStream, aContentType);
+    str.Assign(aBodyInit.GetAsUSVString());
+    return ExtractFromUSVString(str, aStream, aContentType);
   } else if (aBodyInit.IsURLSearchParams()) {
     URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
     return ExtractFromURLSearchParams(params, aStream, aContentType);
   }
 
   NS_NOTREACHED("Should never reach here");
   return NS_ERROR_FAILURE;
 }
--- a/dom/fetch/Fetch.h
+++ b/dom/fetch/Fetch.h
@@ -13,48 +13,48 @@
 #include "mozilla/dom/RequestBinding.h"
 
 class nsIInputStream;
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
-class ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams;
+class ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams;
 class InternalRequest;
-class OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams;
+class OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams;
 class Promise;
-class RequestOrScalarValueString;
+class RequestOrUSVString;
 
 namespace workers {
 class WorkerPrivate;
 } // namespace workers
 
 already_AddRefed<Promise>
-FetchRequest(nsIGlobalObject* aGlobal, const RequestOrScalarValueString& aInput,
+FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
              const RequestInit& aInit, ErrorResult& aRv);
 
 nsresult
 GetRequestReferrer(nsIGlobalObject* aGlobal, const InternalRequest* aRequest, nsCString& aReferrer);
 
 /*
  * Creates an nsIInputStream based on the fetch specifications 'extract a byte
  * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
  * Stores content type in out param aContentType.
  */
 nsresult
-ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType);
 
 /*
  * Non-owning version.
  */
 nsresult
-ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
+ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentType);
 
 template <class Derived>
 class FetchBody {
 public:
   bool
   BodyUsed() { return mBodyUsed; }
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -44,17 +44,17 @@ already_AddRefed<InternalRequest>
 Request::GetInternalRequest()
 {
   nsRefPtr<InternalRequest> r = mRequest;
   return r.forget();
 }
 
 /*static*/ already_AddRefed<Request>
 Request::Constructor(const GlobalObject& aGlobal,
-                     const RequestOrScalarValueString& aInput,
+                     const RequestOrUSVString& aInput,
                      const RequestInit& aInit, ErrorResult& aRv)
 {
   nsRefPtr<InternalRequest> request;
 
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 
   if (aInput.IsRequest()) {
     nsRefPtr<Request> inputReq = &aInput.GetAsRequest();
@@ -71,19 +71,19 @@ Request::Constructor(const GlobalObject&
 
   request = request->GetRequestConstructorCopy(global, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   RequestMode fallbackMode = RequestMode::EndGuard_;
   RequestCredentials fallbackCredentials = RequestCredentials::EndGuard_;
-  if (aInput.IsScalarValueString()) {
+  if (aInput.IsUSVString()) {
     nsString input;
-    input.Assign(aInput.GetAsScalarValueString());
+    input.Assign(aInput.GetAsUSVString());
 
     nsString requestURL;
     if (NS_IsMainThread()) {
       nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
       MOZ_ASSERT(window);
       nsCOMPtr<nsIURI> docURI = window->GetDocumentURI();
       nsCString spec;
       aRv = docURI->GetSpec(spec);
@@ -186,17 +186,17 @@ Request::Constructor(const GlobalObject&
   }
 
   requestHeaders->Fill(*headers, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   if (aInit.mBody.WasPassed()) {
-    const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
+    const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
     nsCOMPtr<nsIInputStream> stream;
     nsCString contentType;
     aRv = ExtractByteStreamFromBody(bodyInit,
                                     getter_AddRefs(stream), contentType);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
     request->SetBody(stream);
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -18,17 +18,17 @@
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class Headers;
 class InternalHeaders;
 class Promise;
-class RequestOrScalarValueString;
+class RequestOrUSVString;
 
 class Request MOZ_FINAL : public nsISupports
                         , public nsWrapperCache
                         , public FetchBody<Request>
 {
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Request)
 
@@ -84,17 +84,17 @@ public:
   }
 
   Headers* Headers_();
 
   void
   GetBody(nsIInputStream** aStream) { return mRequest->GetBody(aStream); }
 
   static already_AddRefed<Request>
-  Constructor(const GlobalObject& aGlobal, const RequestOrScalarValueString& aInput,
+  Constructor(const GlobalObject& aGlobal, const RequestOrUSVString& aInput,
               const RequestInit& aInit, ErrorResult& rv);
 
   nsIGlobalObject* GetParentObject() const
   {
     return mOwner;
   }
 
   already_AddRefed<Request>
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -51,24 +51,24 @@ Response::Error(const GlobalObject& aGlo
 }
 
 /* static */ already_AddRefed<Response>
 Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
                    uint16_t aStatus)
 {
   ErrorResult result;
   ResponseInit init;
-  Optional<ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams> body;
+  Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams> body;
   nsRefPtr<Response> r = Response::Constructor(aGlobal, body, init, result);
   return r.forget();
 }
 
 /*static*/ already_AddRefed<Response>
 Response::Constructor(const GlobalObject& aGlobal,
-                      const Optional<ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams>& aBody,
+                      const Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams>& aBody,
                       const ResponseInit& aInit, ErrorResult& aRv)
 {
   if (aInit.mStatus < 200 || aInit.mStatus > 599) {
     aRv.Throw(NS_ERROR_RANGE_ERR);
     return nullptr;
   }
 
   nsCString statusText;
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -14,17 +14,17 @@
 
 #include "InternalResponse.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
-class ArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams;
+class ArrayBufferOrArrayBufferViewOrUSVStringOrURLSearchParams;
 class Headers;
 class InternalHeaders;
 class Promise;
 
 class Response MOZ_FINAL : public nsISupports
                          , public nsWrapperCache
                          , public FetchBody<Response>
 {
@@ -82,17 +82,17 @@ public:
   static already_AddRefed<Response>
   Error(const GlobalObject& aGlobal);
 
   static already_AddRefed<Response>
   Redirect(const GlobalObject& aGlobal, const nsAString& aUrl, uint16_t aStatus);
 
   static already_AddRefed<Response>
   Constructor(const GlobalObject& aGlobal,
-              const Optional<ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams>& aBody,
+              const Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams>& aBody,
               const ResponseInit& aInit, ErrorResult& rv);
 
   nsIGlobalObject* GetParentObject() const
   {
     return mOwner;
   }
 
   already_AddRefed<Response>
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -273,17 +273,18 @@ private:
 // BreakCycles() during shutdown.
 class RequestSampleCallback {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RequestSampleCallback)
 
   enum NotDecodedReason {
     END_OF_STREAM,
     DECODE_ERROR,
-    WAITING_FOR_DATA
+    WAITING_FOR_DATA,
+    CANCELED
   };
 
   // Receives the result of a RequestAudioData() call.
   virtual void OnAudioDecoded(AudioData* aSample) = 0;
 
   // Receives the result of a RequestVideoData() call.
   virtual void OnVideoDecoded(VideoData* aSample) = 0;
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -627,16 +627,21 @@ MediaDecoderStateMachine::DecodeVideo()
 
   mReader->RequestVideoData(skipToNextKeyFrame, currentTime);
 }
 
 bool
 MediaDecoderStateMachine::NeedToDecodeAudio()
 {
   AssertCurrentThreadInMonitor();
+  SAMPLE_LOG("NeedToDecodeAudio() isDec=%d decToTar=%d minPrl=%d seek=%d enufAud=%d",
+             IsAudioDecoding(), mDecodeToSeekTarget, mMinimizePreroll,
+             mState == DECODER_STATE_SEEKING,
+             HaveEnoughDecodedAudio(mAmpleAudioThresholdUsecs * mPlaybackRate));
+
   return IsAudioDecoding() &&
          ((mState == DECODER_STATE_SEEKING && mDecodeToSeekTarget) ||
           (!mMinimizePreroll &&
           !HaveEnoughDecodedAudio(mAmpleAudioThresholdUsecs * mPlaybackRate) &&
           (mState != DECODER_STATE_SEEKING || mDecodeToSeekTarget)));
 }
 
 void
@@ -828,16 +833,21 @@ MediaDecoderStateMachine::OnNotDecoded(M
     bool outOfSamples = isAudio ? !AudioQueue().GetSize() : !VideoQueue().GetSize();
     if (outOfSamples) {
       StartBuffering();
     }
 
     return;
   }
 
+  if (aReason == RequestSampleCallback::CANCELED) {
+    DispatchDecodeTasksIfNeeded();
+    return;
+  }
+
   // This is an EOS. Finish off the queue, and then handle things based on our
   // state.
   MOZ_ASSERT(aReason == RequestSampleCallback::END_OF_STREAM);
   if (!isAudio && mState == DECODER_STATE_SEEKING &&
       mCurrentSeekTarget.IsValid() && mFirstVideoFrameAfterSeek) {
     // Null sample. Hit end of stream. If we have decoded a frame,
     // insert it into the queue so that we have something to display.
     // We make sure to do this before invoking VideoQueue().Finish()
@@ -1717,27 +1727,28 @@ MediaDecoderStateMachine::DispatchDecode
              (!needToDecodeAudio && !needToDecodeVideo));
 
   bool needIdle = !mDecoder->IsLogicallyPlaying() &&
                   mState != DECODER_STATE_SEEKING &&
                   !needToDecodeAudio &&
                   !needToDecodeVideo &&
                   !IsPlaying();
 
+  SAMPLE_LOG("DispatchDecodeTasksIfNeeded needAudio=%d dispAudio=%d needVideo=%d dispVid=%d needIdle=%d",
+             needToDecodeAudio, mAudioRequestPending,
+             needToDecodeVideo, mVideoRequestPending,
+             needIdle);
+
   if (needToDecodeAudio) {
     EnsureAudioDecodeTaskQueued();
   }
   if (needToDecodeVideo) {
     EnsureVideoDecodeTaskQueued();
   }
 
-  SAMPLE_LOG("DispatchDecodeTasksIfNeeded needAudio=%d dispAudio=%d needVideo=%d dispVid=%d needIdle=%d",
-             needToDecodeAudio, mAudioRequestPending,
-             needToDecodeVideo, mVideoRequestPending,
-             needIdle);
 
   if (needIdle) {
     RefPtr<nsIRunnable> event = NS_NewRunnableMethod(
         this, &MediaDecoderStateMachine::SetReaderIdle);
     nsresult rv = mDecodeTaskQueue->Dispatch(event.forget());
     if (NS_FAILED(rv) && mState != DECODER_STATE_SHUTDOWN) {
       DECODER_WARN("Failed to dispatch event to set decoder idle state");
     }
@@ -2246,19 +2257,20 @@ void MediaDecoderStateMachine::DecodeSee
       NS_NewRunnableMethod(mDecoder, &MediaDecoder::SeekingStarted);
     NS_DispatchToMainThread(startEvent, NS_DISPATCH_SYNC);
   }
   if (mState != DECODER_STATE_SEEKING) {
     // May have shutdown while we released the monitor.
     return;
   }
 
+  mDecodeToSeekTarget = false;
+
   if (!currentTimeChanged) {
     DECODER_LOG("Seek !currentTimeChanged...");
-    mDecodeToSeekTarget = false;
     nsresult rv = mDecodeTaskQueue->Dispatch(
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
     if (NS_FAILED(rv)) {
       DecodeError();
     }
   } else {
     // The seek target is different than the current playback position,
     // we'll need to seek the playback position, so shutdown our decode
@@ -2382,29 +2394,31 @@ MediaDecoderStateMachine::SeekCompleted(
   UpdatePlaybackPositionInternal(newCurrentTime);
   if (mDecoder->GetDecodedStream()) {
     SetSyncPointForMediaStream();
   }
 
   // Try to decode another frame to detect if we're at the end...
   DECODER_LOG("Seek completed, mCurrentFrameTime=%lld", mCurrentFrameTime);
 
+  mCurrentSeekTarget = SeekTarget();
+
+  // Reset quick buffering status. This ensures that if we began the
+  // seek while quick-buffering, we won't bypass quick buffering mode
+  // if we need to buffer after the seek.
+  mQuickBuffering = false;
+
   // Prevent changes in playback position before 'seeked' is fired for we
   // expect currentTime equals seek target in 'seeked' callback.
   mScheduler->FreezeScheduling();
   {
     ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
     NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC);
   }
 
-  // Reset quick buffering status. This ensures that if we began the
-  // seek while quick-buffering, we won't bypass quick buffering mode
-  // if we need to buffer after the seek.
-  mQuickBuffering = false;
-
   ScheduleStateMachine();
   mScheduler->ThawScheduling();
 }
 
 // Runnable to dispose of the decoder and state machine on the main thread.
 class nsDecoderDisposeEvent : public nsRunnable {
 public:
   nsDecoderDisposeEvent(already_AddRefed<MediaDecoder> aDecoder,
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -1297,18 +1297,17 @@ PeerConnectionObserver.prototype = {
   //
   handleIceGatheringStateChange: function(gatheringState) {
     this._dompc.changeIceGatheringState(gatheringState);
   },
 
   onStateChange: function(state) {
     switch (state) {
       case "SignalingState":
-        this._dompc.callCB(this._dompc.onsignalingstatechange,
-                           this._dompc.signalingState);
+        this.dispatchEvent(new this._win.Event("signalingstatechange"));
         break;
 
       case "IceConnectionState":
         this.handleIceConnectionStateChange(this._dompc._pc.iceConnectionState);
         break;
 
       case "IceGatheringState":
         this.handleIceGatheringStateChange(this._dompc._pc.iceGatheringState);
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -28,18 +28,20 @@ using mozilla::layers::LayersBackend;
 PRLogModuleInfo* GetDemuxerLog() {
   static PRLogModuleInfo* log = nullptr;
   if (!log) {
     log = PR_NewLogModule("MP4Demuxer");
   }
   return log;
 }
 #define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__))
+#define VLOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
 #else
 #define LOG(...)
+#define VLOG(...)
 #endif
 
 using namespace mp4_demuxer;
 
 namespace mozilla {
 
 // Uncomment to enable verbose per-sample logging.
 //#define LOG_SAMPLE_DECODE 1
@@ -129,24 +131,38 @@ MP4Reader::MP4Reader(AbstractMediaDecode
   , mIndexMonitor("MP4 index")
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   MOZ_COUNT_CTOR(MP4Reader);
 }
 
 MP4Reader::~MP4Reader()
 {
-  MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   MOZ_COUNT_DTOR(MP4Reader);
-  Shutdown();
 }
 
+class DestroyPDMTask : public nsRunnable {
+public:
+  DestroyPDMTask(nsAutoPtr<PlatformDecoderModule>& aPDM)
+    : mPDM(aPDM)
+  {}
+  NS_IMETHOD Run() MOZ_OVERRIDE {
+    MOZ_ASSERT(NS_IsMainThread());
+    mPDM = nullptr;
+    return NS_OK;
+  }
+private:
+  nsAutoPtr<PlatformDecoderModule> mPDM;
+};
+
 void
 MP4Reader::Shutdown()
 {
+  MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
+
   if (mAudio.mDecoder) {
     Flush(kAudio);
     mAudio.mDecoder->Shutdown();
     mAudio.mDecoder = nullptr;
   }
   if (mAudio.mTaskQueue) {
     mAudio.mTaskQueue->Shutdown();
     mAudio.mTaskQueue = nullptr;
@@ -159,18 +175,20 @@ MP4Reader::Shutdown()
   if (mVideo.mTaskQueue) {
     mVideo.mTaskQueue->Shutdown();
     mVideo.mTaskQueue = nullptr;
   }
   // Dispose of the queued sample before shutting down the demuxer
   mQueuedVideoSample = nullptr;
 
   if (mPlatform) {
-    mPlatform->Shutdown();
-    mPlatform = nullptr;
+    // PDMs are supposed to be destroyed on the main thread...
+    nsRefPtr<DestroyPDMTask> task(new DestroyPDMTask(mPlatform));
+    MOZ_ASSERT(!mPlatform);
+    NS_DispatchToMainThread(task);
   }
 }
 
 void
 MP4Reader::InitLayersBackendType()
 {
   if (!IsVideoContentType(mDecoder->GetResource()->GetContentType())) {
     // Not playing video, we don't care about the layers backend type.
@@ -201,22 +219,20 @@ nsresult
 MP4Reader::Init(MediaDecoderReader* aCloneDonor)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   PlatformDecoderModule::Init();
   mDemuxer = new MP4Demuxer(new MP4Stream(mDecoder->GetResource()));
 
   InitLayersBackendType();
 
-  mAudio.mTaskQueue = new MediaTaskQueue(
-    SharedThreadPool::Get(NS_LITERAL_CSTRING("MP4 Audio Decode")));
+  mAudio.mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
   NS_ENSURE_TRUE(mAudio.mTaskQueue, NS_ERROR_FAILURE);
 
-  mVideo.mTaskQueue = new MediaTaskQueue(
-    SharedThreadPool::Get(NS_LITERAL_CSTRING("MP4 Video Decode")));
+  mVideo.mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
   NS_ENSURE_TRUE(mVideo.mTaskQueue, NS_ERROR_FAILURE);
 
   static bool sSetupPrefCache = false;
   if (!sSetupPrefCache) {
     sSetupPrefCache = true;
     Preferences::AddBoolVarCache(&sIsEMEEnabled, "media.eme.enabled", false);
   }
 
@@ -478,16 +494,186 @@ MP4Reader::HasVideo()
 
 MP4Reader::DecoderData&
 MP4Reader::GetDecoderData(TrackType aTrack)
 {
   MOZ_ASSERT(aTrack == kAudio || aTrack == kVideo);
   return (aTrack == kAudio) ? mAudio : mVideo;
 }
 
+void
+MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
+                            int64_t aTimeThreshold)
+{
+  MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
+  VLOG("RequestVideoData skip=%d time=%lld", aSkipToNextKeyframe, aTimeThreshold);
+
+  // Record number of frames decoded and parsed. Automatically update the
+  // stats counters using the AutoNotifyDecoded stack-based class.
+  uint32_t parsed = 0, decoded = 0;
+  AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
+
+  MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder);
+
+  if (aSkipToNextKeyframe) {
+    if (!SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed) ||
+        NS_FAILED(mVideo.mDecoder->Flush())) {
+      NS_WARNING("Failed to skip/flush video when skipping-to-next-keyframe.");
+    }
+  }
+
+  auto& decoder = GetDecoderData(kVideo);
+  MonitorAutoLock lock(decoder.mMonitor);
+  decoder.mOutputRequested = true;
+  ScheduleUpdate(kVideo);
+
+  // Report the number of "decoded" frames as the difference in the
+  // mNumSamplesOutput field since the last time we were called.
+  uint64_t delta = mVideo.mNumSamplesOutput - mLastReportedNumDecodedFrames;
+  decoded = static_cast<uint32_t>(delta);
+  mLastReportedNumDecodedFrames = mVideo.mNumSamplesOutput;
+}
+
+void
+MP4Reader::RequestAudioData()
+{
+  MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
+  VLOG("RequestAudioData");
+  auto& decoder = GetDecoderData(kAudio);
+  MonitorAutoLock lock(decoder.mMonitor);
+  decoder.mOutputRequested = true;
+  ScheduleUpdate(kAudio);
+}
+
+void
+MP4Reader::ScheduleUpdate(TrackType aTrack)
+{
+  auto& decoder = GetDecoderData(aTrack);
+  decoder.mMonitor.AssertCurrentThreadOwns();
+  if (decoder.mUpdateScheduled) {
+    return;
+  }
+  VLOG("SchedulingUpdate(%s)", TrackTypeToStr(aTrack));
+  decoder.mUpdateScheduled = true;
+  RefPtr<nsIRunnable> task(
+    NS_NewRunnableMethodWithArg<TrackType>(this, &MP4Reader::Update, aTrack));
+  GetTaskQueue()->Dispatch(task.forget());
+}
+
+bool
+MP4Reader::NeedInput(DecoderData& aDecoder)
+{
+  aDecoder.mMonitor.AssertCurrentThreadOwns();
+  // We try to keep a few more compressed samples input than decoded samples
+  // have been output, provided the state machine has requested we send it a
+  // decoded sample. To account for H.264 streams which may require a longer
+  // run of input than we input, decoders fire an "input exhausted" callback,
+  // which overrides our "few more samples" threshold.
+  return
+    !aDecoder.mError &&
+    !aDecoder.mEOS &&
+    aDecoder.mOutputRequested &&
+    aDecoder.mOutput.IsEmpty() &&
+    (aDecoder.mInputExhausted ||
+     aDecoder.mNumSamplesInput - aDecoder.mNumSamplesOutput < aDecoder.mDecodeAhead);
+}
+
+void
+MP4Reader::Update(TrackType aTrack)
+{
+  MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
+
+  bool needInput = false;
+  bool needOutput = false;
+  bool eos = false;
+  auto& decoder = GetDecoderData(aTrack);
+  nsRefPtr<MediaData> output;
+  {
+    MonitorAutoLock lock(decoder.mMonitor);
+    decoder.mUpdateScheduled = false;
+    if (NeedInput(decoder)) {
+      needInput = true;
+      decoder.mInputExhausted = false;
+      decoder.mNumSamplesInput++;
+    }
+    needOutput = decoder.mOutputRequested;
+    if (needOutput && !decoder.mOutput.IsEmpty()) {
+      output = decoder.mOutput[0];
+      decoder.mOutput.RemoveElementAt(0);
+    }
+    eos = decoder.mEOS;
+  }
+  VLOG("Update(%s) ni=%d no=%d iex=%d or=%d fl=%d",
+       TrackTypeToStr(aTrack),
+       needInput,
+       needOutput,
+       decoder.mInputExhausted,
+       decoder.mOutputRequested,
+       decoder.mIsFlushing);
+
+  if (needInput) {
+    MP4Sample* sample = PopSample(aTrack);
+    if (sample) {
+      decoder.mDecoder->Input(sample);
+    } else {
+      {
+        MonitorAutoLock lock(decoder.mMonitor);
+        MOZ_ASSERT(!decoder.mEOS);
+        eos = decoder.mEOS = true;
+      }
+      decoder.mDecoder->Drain();
+    }
+  }
+  if (needOutput) {
+    if (output) {
+      ReturnOutput(output, aTrack);
+    } else if (eos) {
+      ReturnEOS(aTrack);
+    }
+  }
+}
+
+void
+MP4Reader::ReturnOutput(MediaData* aData, TrackType aTrack)
+{
+  auto& decoder = GetDecoderData(aTrack);
+  {
+    MonitorAutoLock lock(decoder.mMonitor);
+    MOZ_ASSERT(decoder.mOutputRequested);
+    decoder.mOutputRequested = false;
+    if (decoder.mDiscontinuity) {
+      decoder.mDiscontinuity = false;
+      aData->mDiscontinuity = true;
+    }
+  }
+
+  if (aTrack == kAudio) {
+    AudioData* audioData = static_cast<AudioData*>(aData);
+
+    if (audioData->mChannels != mInfo.mAudio.mChannels ||
+        audioData->mRate != mInfo.mAudio.mRate) {
+      LOG("MP4Reader::ReturnOutput change of sampling rate:%d->%d",
+          mInfo.mAudio.mRate, audioData->mRate);
+      mInfo.mAudio.mRate = audioData->mRate;
+      mInfo.mAudio.mChannels = audioData->mChannels;
+    }
+
+    GetCallback()->OnAudioDecoded(audioData);
+  } else if (aTrack == kVideo) {
+    GetCallback()->OnVideoDecoded(static_cast<VideoData*>(aData));
+  }
+}
+
+void
+MP4Reader::ReturnEOS(TrackType aTrack)
+{
+  GetCallback()->OnNotDecoded(aTrack == kAudio ? MediaData::AUDIO_DATA : MediaData::VIDEO_DATA,
+                              RequestSampleCallback::END_OF_STREAM);
+}
+
 MP4Sample*
 MP4Reader::PopSample(TrackType aTrack)
 {
   switch (aTrack) {
     case kAudio:
       return mDemuxer->DemuxAudioSample();
 
     case kVideo:
@@ -496,169 +682,53 @@ MP4Reader::PopSample(TrackType aTrack)
       }
       return mDemuxer->DemuxVideoSample();
 
     default:
       return nullptr;
   }
 }
 
-// How async decoding works:
-//
-// When MP4Reader::Decode() is called:
-// * Lock the DecoderData. We assume the state machine wants
-//   output from the decoder (in future, we'll assume decoder wants input
-//   when the output MediaQueue isn't "full").
-// * Cache the value of mNumSamplesOutput, as prevFramesOutput.
-// * While we've not output data (mNumSamplesOutput != prevNumFramesOutput)
-//   and while we still require input, we demux and input data in the reader.
-//   We assume we require input if
-//   ((mNumSamplesInput - mNumSamplesOutput) < sDecodeAheadMargin) or
-//   mInputExhausted is true. Before we send input, we reset mInputExhausted
-//   and increment mNumFrameInput, and drop the lock on DecoderData.
-// * Once we no longer require input, we wait on the DecoderData
-//   lock for output, or for the input exhausted callback. If we receive the
-//   input exhausted callback, we go back and input more data.
-// * When our output callback is called, we take the DecoderData lock and
-//   increment mNumSamplesOutput. We notify the DecoderData lock. This will
-//   awaken the Decode thread, and unblock it, and it will return.
-bool
-MP4Reader::Decode(TrackType aTrack)
-{
-  DecoderData& data = GetDecoderData(aTrack);
-  MOZ_ASSERT(data.mDecoder);
-
-  data.mMonitor.Lock();
-  uint64_t prevNumFramesOutput = data.mNumSamplesOutput;
-  while (prevNumFramesOutput == data.mNumSamplesOutput) {
-    data.mMonitor.AssertCurrentThreadOwns();
-    if (data.mError) {
-      // Decode error!
-      data.mMonitor.Unlock();
-      return false;
-    }
-    // Send input to the decoder, if we need to. We assume the decoder
-    // needs input if it's told us it's out of input, or we're beneath the
-    // "low water mark" for the amount of input we've sent it vs the amount
-    // out output we've received. We always try to keep the decoder busy if
-    // possible, so we try to maintain at least a few input samples ahead,
-    // if we need output.
-    while (prevNumFramesOutput == data.mNumSamplesOutput &&
-           (data.mInputExhausted ||
-           (data.mNumSamplesInput - data.mNumSamplesOutput) < data.mDecodeAhead) &&
-           !data.mEOS) {
-      data.mMonitor.AssertCurrentThreadOwns();
-      data.mMonitor.Unlock();
-      nsAutoPtr<MP4Sample> compressed(PopSample(aTrack));
-      if (!compressed) {
-        // EOS, or error. Send the decoder a signal to drain.
-        LOG("MP4Reader: EOS or error - no samples available");
-        LOG("Draining %s", TrackTypeToStr(aTrack));
-        data.mMonitor.Lock();
-        MOZ_ASSERT(!data.mEOS);
-        data.mEOS = true;
-        MOZ_ASSERT(!data.mDrainComplete);
-        data.mDrainComplete = false;
-        data.mMonitor.Unlock();
-        data.mDecoder->Drain();
-      } else {
-#ifdef LOG_SAMPLE_DECODE
-        LOG("PopSample %s time=%lld dur=%lld", TrackTypeToStr(aTrack),
-            compressed->composition_timestamp, compressed->duration);
-#endif
-        data.mMonitor.Lock();
-        data.mDrainComplete = false;
-        data.mInputExhausted = false;
-        data.mNumSamplesInput++;
-        data.mMonitor.Unlock();
-
-        if (NS_FAILED(data.mDecoder->Input(compressed))) {
-          return false;
-        }
-        // If Input() failed, we let the auto pointer delete |compressed|.
-        // Otherwise, we assume the decoder will delete it when it's finished
-        // with it.
-        compressed.forget();
-      }
-      data.mMonitor.Lock();
-    }
-    data.mMonitor.AssertCurrentThreadOwns();
-    while (!data.mError &&
-           prevNumFramesOutput == data.mNumSamplesOutput &&
-           (!data.mInputExhausted || data.mEOS) &&
-           !data.mDrainComplete) {
-      data.mMonitor.Wait();
-    }
-    if (data.mError ||
-        (data.mEOS && data.mDrainComplete)) {
-      break;
-    }
-  }
-  data.mMonitor.AssertCurrentThreadOwns();
-  bool rv = !(data.mDrainComplete || data.mError);
-  data.mMonitor.Unlock();
-  return rv;
-}
-
 nsresult
 MP4Reader::ResetDecode()
 {
+  MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
+  Flush(kVideo);
   Flush(kAudio);
-  Flush(kVideo);
   return MediaDecoderReader::ResetDecode();
 }
 
 void
 MP4Reader::Output(TrackType aTrack, MediaData* aSample)
 {
 #ifdef LOG_SAMPLE_DECODE
-  LOG("Decoded %s sample time=%lld dur=%lld",
+  VLOG("Decoded %s sample time=%lld dur=%lld",
       TrackTypeToStr(aTrack), aSample->mTime, aSample->mDuration);
 #endif
 
   if (!aSample) {
     NS_WARNING("MP4Reader::Output() passed a null sample");
     Error(aTrack);
     return;
   }
 
-  DecoderData& data = GetDecoderData(aTrack);
+  auto& decoder = GetDecoderData(aTrack);
   // Don't accept output while we're flushing.
-  MonitorAutoLock mon(data.mMonitor);
-  if (data.mIsFlushing) {
+  MonitorAutoLock mon(decoder.mMonitor);
+  if (decoder.mIsFlushing) {
     LOG("MP4Reader produced output while flushing, discarding.");
     mon.NotifyAll();
     return;
   }
 
-  switch (aTrack) {
-    case kAudio: {
-      MOZ_ASSERT(aSample->mType == MediaData::AUDIO_DATA);
-      AudioData* audioData = static_cast<AudioData*>(aSample);
-      AudioQueue().Push(audioData);
-      if (audioData->mChannels != mInfo.mAudio.mChannels ||
-          audioData->mRate != mInfo.mAudio.mRate) {
-        LOG("MP4Reader::Output change of sampling rate:%d->%d",
-            mInfo.mAudio.mRate, audioData->mRate);
-        mInfo.mAudio.mRate = audioData->mRate;
-        mInfo.mAudio.mChannels = audioData->mChannels;
-      }
-      break;
-    }
-    case kVideo: {
-      MOZ_ASSERT(aSample->mType == MediaData::VIDEO_DATA);
-      VideoQueue().Push(static_cast<VideoData*>(aSample));
-      break;
-    }
-    default:
-      break;
+  decoder.mOutput.AppendElement(aSample);
+  decoder.mNumSamplesOutput++;
+  if (NeedInput(decoder) || decoder.mOutputRequested) {
+    ScheduleUpdate(aTrack);
   }
-
-  data.mNumSamplesOutput++;
-  mon.NotifyAll();
 }
 
 void
 MP4Reader::DrainComplete(TrackType aTrack)
 {
   DecoderData& data = GetDecoderData(aTrack);
   MonitorAutoLock mon(data.mMonitor);
   data.mDrainComplete = true;
@@ -666,38 +736,36 @@ MP4Reader::DrainComplete(TrackType aTrac
 }
 
 void
 MP4Reader::InputExhausted(TrackType aTrack)
 {
   DecoderData& data = GetDecoderData(aTrack);
   MonitorAutoLock mon(data.mMonitor);
   data.mInputExhausted = true;
-  mon.NotifyAll();
+  ScheduleUpdate(aTrack);
 }
 
 void
 MP4Reader::Error(TrackType aTrack)
 {
   DecoderData& data = GetDecoderData(aTrack);
-  MonitorAutoLock mon(data.mMonitor);
-  data.mError = true;
-  mon.NotifyAll();
-}
-
-bool
-MP4Reader::DecodeAudioData()
-{
-  MOZ_ASSERT(HasAudio() && mPlatform && mAudio.mDecoder);
-  return Decode(kAudio);
+  {
+    MonitorAutoLock mon(data.mMonitor);
+    data.mError = true;
+  }
+  GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA,
+                              RequestSampleCallback::DECODE_ERROR);
 }
 
 void
 MP4Reader::Flush(TrackType aTrack)
 {
+  MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
+  VLOG("Flush(%s) BEGIN", TrackTypeToStr(aTrack));
   DecoderData& data = GetDecoderData(aTrack);
   if (!data.mDecoder) {
     return;
   }
   // Purge the current decoder's state.
   // Set a flag so that we ignore all output while we call
   // MediaDataDecoder::Flush().
   {
@@ -705,100 +773,91 @@ MP4Reader::Flush(TrackType aTrack)
     data.mIsFlushing = true;
     data.mDrainComplete = false;
     data.mEOS = false;
   }
   data.mDecoder->Flush();
   {
     MonitorAutoLock mon(data.mMonitor);
     data.mIsFlushing = false;
+    data.mOutput.Clear();
+    data.mNumSamplesInput = 0;
+    data.mNumSamplesOutput = 0;
+    data.mInputExhausted = false;
+    if (data.mOutputRequested) {
+      GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA,
+                                  RequestSampleCallback::CANCELED);
+    }
+    data.mOutputRequested = false;
+    data.mDiscontinuity = true;
   }
+  if (aTrack == kVideo) {
+    mQueuedVideoSample = nullptr;
+  }
+  VLOG("Flush(%s) END", TrackTypeToStr(aTrack));
 }
 
 bool
 MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed)
 {
+  MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
+
   MOZ_ASSERT(mVideo.mDecoder);
 
   Flush(kVideo);
 
   // Loop until we reach the next keyframe after the threshold.
   while (true) {
     nsAutoPtr<MP4Sample> compressed(PopSample(kVideo));
     if (!compressed) {
       // EOS, or error. Let the state machine know.
+      GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA,
+                                  RequestSampleCallback::END_OF_STREAM);
+      {
+        MonitorAutoLock mon(mVideo.mMonitor);
+        mVideo.mEOS = true;
+      }
       return false;
     }
     parsed++;
     if (!compressed->is_sync_point ||
         compressed->composition_timestamp < aTimeThreshold) {
       continue;
     }
     mQueuedVideoSample = compressed;
     break;
   }
 
   return true;
 }
 
-bool
-MP4Reader::DecodeVideoFrame(bool &aKeyframeSkip,
-                            int64_t aTimeThreshold)
-{
-  // Record number of frames decoded and parsed. Automatically update the
-  // stats counters using the AutoNotifyDecoded stack-based class.
-  uint32_t parsed = 0, decoded = 0;
-  AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
-
-  MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder);
-
-  if (aKeyframeSkip) {
-    bool ok = SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed);
-    if (!ok) {
-      NS_WARNING("Failed to skip demux up to next keyframe");
-      return false;
-    }
-    aKeyframeSkip = false;
-    nsresult rv = mVideo.mDecoder->Flush();
-    NS_ENSURE_SUCCESS(rv, false);
-  }
-
-  bool rv = Decode(kVideo);
-  {
-    // Report the number of "decoded" frames as the difference in the
-    // mNumSamplesOutput field since the last time we were called.
-    MonitorAutoLock mon(mVideo.mMonitor);
-    uint64_t delta = mVideo.mNumSamplesOutput - mLastReportedNumDecodedFrames;
-    decoded = static_cast<uint32_t>(delta);
-    mLastReportedNumDecodedFrames = mVideo.mNumSamplesOutput;
-  }
-  return rv;
-}
-
 void
 MP4Reader::Seek(int64_t aTime,
                 int64_t aStartTime,
                 int64_t aEndTime,
                 int64_t aCurrentTime)
 {
+  LOG("MP4Reader::Seek(%lld)", aTime);
+  MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
   if (!mDecoder->GetResource()->IsTransportSeekable() || !mDemuxer->CanSeek()) {
+    VLOG("Seek() END (Unseekable)");
     GetCallback()->OnSeekCompleted(NS_ERROR_FAILURE);
     return;
   }
 
   mQueuedVideoSample = nullptr;
   if (mDemuxer->HasValidVideo()) {
     mDemuxer->SeekVideo(aTime);
     mQueuedVideoSample = PopSample(kVideo);
   }
   if (mDemuxer->HasValidAudio()) {
     mDemuxer->SeekAudio(
       mQueuedVideoSample ? mQueuedVideoSample->composition_timestamp : aTime);
   }
-
+  LOG("MP4Reader::Seek(%lld) exit", aTime);
   GetCallback()->OnSeekCompleted(NS_OK);
 }
 
 void
 MP4Reader::NotifyDataArrived(const char* aBuffer, uint32_t aLength,
                              int64_t aOffset)
 {
   UpdateIndex();
--- a/dom/media/fmp4/MP4Reader.h
+++ b/dom/media/fmp4/MP4Reader.h
@@ -23,27 +23,30 @@ class TimeRanges;
 }
 
 typedef std::deque<mp4_demuxer::MP4Sample*> MP4SampleQueue;
 
 class MP4Stream;
 
 class MP4Reader : public MediaDecoderReader
 {
+  typedef mp4_demuxer::TrackType TrackType;
+
 public:
   explicit MP4Reader(AbstractMediaDecoder* aDecoder);
 
   virtual ~MP4Reader();
 
   virtual nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE;
 
-  virtual bool DecodeAudioData() MOZ_OVERRIDE;
-  virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
+  virtual void RequestVideoData(bool aSkipToNextKeyframe,
                                 int64_t aTimeThreshold) MOZ_OVERRIDE;
 
+  virtual void RequestAudioData() MOZ_OVERRIDE;
+
   virtual bool HasAudio() MOZ_OVERRIDE;
   virtual bool HasVideo() MOZ_OVERRIDE;
 
   virtual nsresult ReadMetadata(MediaInfo* aInfo,
                                 MetadataTags** aTags) MOZ_OVERRIDE;
 
   virtual void ReadUpdatedMetadata(MediaInfo* aInfo) MOZ_OVERRIDE;
 
@@ -70,31 +73,43 @@ public:
     MOZ_OVERRIDE;
 
   virtual nsresult ResetDecode() MOZ_OVERRIDE;
 
   virtual void Shutdown() MOZ_OVERRIDE;
 
 private:
 
+  void ReturnEOS(TrackType aTrack);
+  void ReturnOutput(MediaData* aData, TrackType aTrack);
+
+  // Sends input to decoder for aTrack, and output to the state machine,
+  // if necessary.
+  void Update(TrackType aTrack);
+
+  // Enqueues a task to call Update(aTrack) on the decoder task queue.
+  // Lock for corresponding track must be held.
+  void ScheduleUpdate(TrackType aTrack);
+
   void ExtractCryptoInitData(nsTArray<uint8_t>& aInitData);
 
   // Initializes mLayersBackendType if possible.
   void InitLayersBackendType();
 
   // Blocks until the demuxer produces an sample of specified type.
   // Returns nullptr on error on EOS. Caller must delete sample.
   mp4_demuxer::MP4Sample* PopSample(mp4_demuxer::TrackType aTrack);
 
   bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed);
 
+  // DecoderCallback proxies the MediaDataDecoderCallback calls to these
+  // functions.
   void Output(mp4_demuxer::TrackType aType, MediaData* aSample);
   void InputExhausted(mp4_demuxer::TrackType aTrack);
   void Error(mp4_demuxer::TrackType aTrack);
-  bool Decode(mp4_demuxer::TrackType aTrack);
   void Flush(mp4_demuxer::TrackType aTrack);
   void DrainComplete(mp4_demuxer::TrackType aTrack);
   void UpdateIndex();
   bool IsSupportedAudioMimeType(const char* aMimeType);
   void NotifyResourcesStatusChanged();
   bool IsWaitingOnCodecResource();
   virtual bool IsWaitingOnCDMResource() MOZ_OVERRIDE;
 
@@ -139,47 +154,61 @@ private:
       , mNumSamplesInput(0)
       , mNumSamplesOutput(0)
       , mDecodeAhead(aDecodeAhead)
       , mActive(false)
       , mInputExhausted(false)
       , mError(false)
       , mIsFlushing(false)
       , mDrainComplete(false)
+      , mOutputRequested(false)
+      , mUpdateScheduled(false)
       , mEOS(false)
+      , mDiscontinuity(false)
     {
     }
 
     // The platform decoder.
     nsRefPtr<MediaDataDecoder> mDecoder;
     // TaskQueue on which decoder can choose to decode.
     // Only non-null up until the decoder is created.
     nsRefPtr<MediaTaskQueue> mTaskQueue;
     // Callback that receives output and error notifications from the decoder.
     nsAutoPtr<DecoderCallback> mCallback;
+    // Decoded samples returned my mDecoder awaiting being returned to
+    // state machine upon request.
+    nsTArray<nsRefPtr<MediaData> > mOutput;
+
     // Monitor that protects all non-threadsafe state; the primitives
     // that follow.
     Monitor mMonitor;
     uint64_t mNumSamplesInput;
     uint64_t mNumSamplesOutput;
     uint32_t mDecodeAhead;
     // Whether this stream exists in the media.
     bool mActive;
     bool mInputExhausted;
     bool mError;
     bool mIsFlushing;
     bool mDrainComplete;
+    bool mOutputRequested;
+    bool mUpdateScheduled;
     bool mEOS;
+    bool mDiscontinuity;
   };
   DecoderData mAudio;
   DecoderData mVideo;
   // Queued samples extracted by the demuxer, but not yet sent to the platform
   // decoder.
   nsAutoPtr<mp4_demuxer::MP4Sample> mQueuedVideoSample;
 
+  // Returns true when the decoder for this track needs input.
+  // aDecoder.mMonitor must be locked.
+  bool NeedInput(DecoderData& aDecoder);
+
   // The last number of decoded output frames that we've reported to
   // MediaDecoder::NotifyDecoded(). We diff the number of output video
   // frames every time that DecodeVideoData() is called, and report the
   // delta there.
   uint64_t mLastReportedNumDecodedFrames;
 
   DecoderData& GetDecoderData(mp4_demuxer::TrackType aTrack);
 
--- a/dom/media/fmp4/PlatformDecoderModule.h
+++ b/dom/media/fmp4/PlatformDecoderModule.h
@@ -159,18 +159,19 @@ public:
   virtual void ReleaseMediaResources() {};
 };
 
 // MediaDataDecoder is the interface exposed by decoders created by the
 // PlatformDecoderModule's Create*Decoder() functions. The type of
 // media data that the decoder accepts as valid input and produces as
 // output is determined when the MediaDataDecoder is created.
 //
-// All functions must be threadsafe, and be able to be called on an
-// arbitrary thread.
+// All functions are only called on the decode task queue. Don't block
+// inside these functions, unless it's explicitly noted that you should
+// (like in Flush() and Drain()).
 //
 // Decoding is done asynchronously. Any async work can be done on the
 // MediaTaskQueue passed into the PlatformDecoderModules's Create*Decoder()
 // function. This may not be necessary for platforms with async APIs
 // for decoding.
 class MediaDataDecoder {
 protected:
   virtual ~MediaDataDecoder() {};
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -109,22 +109,23 @@ public:
 
     uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_CSTRING("channel-count"));
     uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_CSTRING("sample-rate"));
     uint32_t numFrames = (aInfo->getSize() / numChannels) / 2;
 
     AudioDataValue* audio = new AudioDataValue[aInfo->getSize()];
     PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), aInfo->getSize());
 
-    mCallback->Output(new AudioData(aInfo->getOffset(), aInfo->getPresentationTimeUs(),
-                                    aDuration,
-                                    numFrames,
-                                    audio,
-                                    numChannels,
-                                    sampleRate));
+    nsRefPtr<AudioData> data = new AudioData(aInfo->getOffset(), aInfo->getPresentationTimeUs(),
+                                             aDuration,
+                                             numFrames,
+                                             audio,
+                                             numChannels,
+                                             sampleRate);
+    mCallback->Output(data);
     return NS_OK;
   }
 };
 
 
 bool AndroidDecoderModule::SupportsAudioMimeType(const char* aMimeType) {
   JNIEnv* env = GetJNIForThread();
   MediaCodec* decoder = CreateDecoder(env, aMimeType);
--- a/dom/media/fmp4/apple/AppleATDecoder.cpp
+++ b/dom/media/fmp4/apple/AppleATDecoder.cpp
@@ -262,23 +262,23 @@ AppleATDecoder::SubmitSample(nsAutoPtr<m
 
     LOG("pushed audio at time %lfs; duration %lfs\n",
         (double)aSample->composition_timestamp / USECS_PER_S,
         (double)duration.value() / USECS_PER_S);
 
     nsAutoArrayPtr<AudioDataValue>
       data(new AudioDataValue[outputData.Length()]);
     PodCopy(data.get(), &outputData[0], outputData.Length());
-    AudioData* audio = new AudioData(aSample->byte_offset,
-                                     aSample->composition_timestamp,
-                                     duration.value(),
-                                     numFrames,
-                                     data.forget(),
-                                     channels,
-                                     rate);
+    nsRefPtr<AudioData> audio = new AudioData(aSample->byte_offset,
+                                              aSample->composition_timestamp,
+                                              duration.value(),
+                                              numFrames,
+                                              data.forget(),
+                                              channels,
+                                              rate);
     mCallback->Output(audio);
   }
 
   if (mTaskQueue->IsEmpty()) {
     mCallback->InputExhausted();
   }
 }
 
--- a/dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
@@ -123,23 +123,23 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePac
       CheckedInt<Microseconds> duration =
         FramesToUsecs(mFrame->nb_samples, samplingRate);
       if (!duration.isValid()) {
         NS_WARNING("Invalid count of accumulated audio samples");
         mCallback->Error();
         return;
       }
 
-      AudioData* data = new AudioData(samplePosition,
-                                      pts,
-                                      duration.value(),
-                                      mFrame->nb_samples,
-                                      audio.forget(),
-                                      numChannels,
-                                      samplingRate);
+      nsRefPtr<AudioData> data = new AudioData(samplePosition,
+                                               pts,
+                                               duration.value(),
+                                               mFrame->nb_samples,
+                                               audio.forget(),
+                                               numChannels,
+                                               samplingRate);
       mCallback->Output(data);
       pts += duration.value();
     }
     packet.data += bytesConsumed;
     packet.size -= bytesConsumed;
     samplePosition += bytesConsumed;
   }
 
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
@@ -157,17 +157,18 @@ GonkMediaDataDecoder::Drain()
 
 bool
 GonkMediaDataDecoder::IsWaitingMediaResources() {
   return mDecoder->IsWaitingResources();
 }
 
 bool
 GonkMediaDataDecoder::IsDormantNeeded() {
-  return mDecoder->IsDormantNeeded();
+
+  return mDecoder.get() ? true : false;
 }
 
 void
 GonkMediaDataDecoder::ReleaseMediaResources() {
-  mDecoder->ReleaseMediaResources();
+  mManager->ReleaseMediaResources();
 }
 
 } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
@@ -29,16 +29,17 @@ public:
   // is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE
   // if there's not enough data to produce more output. If this returns a failure
   // code other than NS_ERROR_NOT_AVAILABLE, an error will be reported to the
   // MP4Reader.
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) = 0;
   virtual nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) = 0;
 
+  virtual void ReleaseMediaResources() {};
 };
 
 // Samples are decoded using the GonkDecoder (MediaCodec)
 // created by the GonkDecoderManager. This class implements
 // the higher-level logic that drives mapping the Gonk to the async
 // MediaDataDecoder interface. The specifics of decoding the exact stream
 // type are handled by GonkDecoderManager and the GonkDecoder it creates.
 class GonkMediaDataDecoder : public MediaDataDecoder {
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
@@ -450,29 +450,30 @@ GonkVideoDecoderManager::codecCanceled()
 void
 GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
 {
   switch (aMessage->what()) {
     case kNotifyCodecReserved:
     {
       // Our decode may have acquired the hardware resource that it needs
       // to start. Notify the state machine to resume loading metadata.
+      ALOG("CodecReserved!");
       mReaderCallback->NotifyResourcesStatusChanged();
       break;
     }
 
     case kNotifyCodecCanceled:
     {
       mReaderCallback->ReleaseMediaResources();
       break;
     }
 
     case kNotifyPostReleaseBuffer:
     {
-      ReleaseAllPendingVideoBuffersLocked();
+      ReleaseAllPendingVideoBuffers();
       break;
     }
 
     default:
       TRESPASS();
       break;
   }
 }
@@ -557,17 +558,17 @@ void GonkVideoDecoderManager::PostReleas
     }
   }
   sp<AMessage> notify =
             new AMessage(kNotifyPostReleaseBuffer, mHandler->id());
   notify->post();
 
 }
 
-void GonkVideoDecoderManager::ReleaseAllPendingVideoBuffersLocked()
+void GonkVideoDecoderManager::ReleaseAllPendingVideoBuffers()
 {
   Vector<android::MediaBuffer*> releasingVideoBuffers;
   {
     MutexAutoLock autoLock(mPendingVideoBuffersLock);
     int size = mPendingVideoBuffers.length();
     for (int i = 0; i < size; i++) {
       releasingVideoBuffers.append(mPendingVideoBuffers[i]);
     }
@@ -579,9 +580,14 @@ void GonkVideoDecoderManager::ReleaseAll
     android::MediaBuffer *buffer;
     buffer = releasingVideoBuffers[i];
     mDecoder->ReleaseMediaBuffer(buffer);
     buffer = nullptr;
   }
   releasingVideoBuffers.clear();
 }
 
+void GonkVideoDecoderManager::ReleaseMediaResources() {
+  ALOG("ReleseMediaResources");
+  ReleaseAllPendingVideoBuffers();
+  mDecoder->ReleaseMediaResources();
+}
 } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
@@ -45,17 +45,20 @@ public:
 
   virtual android::sp<MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
 
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
 
   virtual nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
+  virtual void ReleaseMediaResources();
+
   static void RecycleCallback(TextureClient* aClient, void* aClosure);
+
 private:
   struct FrameInfo
   {
     int32_t mWidth = 0;
     int32_t mHeight = 0;
     int32_t mStride = 0;
     int32_t mSliceHeight = 0;
     int32_t mColorFormat = 0;
@@ -107,17 +110,17 @@ private:
   void ReleaseVideoBuffer();
   uint8_t* GetColorConverterBuffer(int32_t aWidth, int32_t aHeight);
 
   // For codec resource management
   void codecReserved();
   void codecCanceled();
   void onMessageReceived(const sp<AMessage> &aMessage);
 
-  void ReleaseAllPendingVideoBuffersLocked();
+  void ReleaseAllPendingVideoBuffers();
   void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer);
 
   uint32_t mVideoWidth;
   uint32_t mVideoHeight;
   uint32_t mDisplayWidth;
   uint32_t mDisplayHeight;
   nsIntRect mPicture;
   nsIntSize mInitialFrame;
--- a/dom/media/gmp-plugin/gmp-test-decryptor.cpp
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.cpp
@@ -280,16 +280,55 @@ public:
     } else {
       FakeDecryptor::Message("retrieved " + mRecordId + " " + aData);
     }
     delete this;
   }
   string mRecordId;
 };
 
+static void
+RecvGMPRecordIterator(GMPRecordIterator* aRecordIterator,
+                      void* aUserArg,
+                      GMPErr aStatus)
+{
+  FakeDecryptor* decryptor = reinterpret_cast<FakeDecryptor*>(aUserArg);
+  decryptor->ProcessRecordNames(aRecordIterator, aStatus);
+}
+
+void
+FakeDecryptor::ProcessRecordNames(GMPRecordIterator* aRecordIterator,
+                                  GMPErr aStatus)
+{
+  if (sInstance != this) {
+    FakeDecryptor::Message("Error aUserArg was not passed through GetRecordIterator");
+    return;
+  }
+  if (GMP_FAILED(aStatus)) {
+    FakeDecryptor::Message("Error GetRecordIterator failed");
+    return;
+  }
+  std::string response("record-names ");
+  bool first = true;
+  const char* name = nullptr;
+  uint32_t len = 0;
+  while (GMP_SUCCEEDED(aRecordIterator->GetName(&name, &len))) {
+    std::string s(name, name+len);
+    if (!first) {
+      response += ",";
+    } else {
+      first = false;
+    }
+    response += s;
+    aRecordIterator->NextRecord();
+  }
+  aRecordIterator->Close();
+  FakeDecryptor::Message(response);
+}
+
 enum ShutdownMode {
   ShutdownNormal,
   ShutdownTimeout,
   ShutdownStoreToken
 };
 
 static ShutdownMode sShutdownMode = ShutdownNormal;
 static string sShutdownToken = "";
@@ -330,16 +369,18 @@ FakeDecryptor::UpdateSession(uint32_t aP
   } else if (task == "test-op-apis") {
     mozilla::gmptest::TestOuputProtectionAPIs();
   } else if (task == "retrieve-plugin-voucher") {
     const uint8_t* rawVoucher = nullptr;
     uint32_t length = 0;
     mHost->GetPluginVoucher(&rawVoucher, &length);
     std::string voucher((const char*)rawVoucher, (const char*)(rawVoucher + length));
     Message("retrieved plugin-voucher: " + voucher);
+  } else if (task == "retrieve-record-names") {
+    GMPEnumRecordNames(&RecvGMPRecordIterator, this);
   }
 }
 
 class CompleteShutdownTask : public GMPTask {
 public:
   explicit CompleteShutdownTask(GMPAsyncShutdownHost* aHost)
     : mHost(aHost)
   {
--- a/dom/media/gmp-plugin/gmp-test-decryptor.h
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.h
@@ -63,16 +63,19 @@ public:
                        GMPEncryptedBufferMetadata* aMetadata) MOZ_OVERRIDE
   {
   }
 
   virtual void DecryptingComplete() MOZ_OVERRIDE;
 
   static void Message(const std::string& aMessage);
 
+  void ProcessRecordNames(GMPRecordIterator* aRecordIterator,
+                          GMPErr aStatus);
+
 private:
 
   virtual ~FakeDecryptor() {}
   static FakeDecryptor* sInstance;
 
   void TestStorage();
 
   GMPDecryptorCallback* mCallback;
--- a/dom/media/gmp-plugin/gmp-test-storage.cpp
+++ b/dom/media/gmp-plugin/gmp-test-storage.cpp
@@ -188,8 +188,15 @@ GMPOpenRecord(const std::string& aRecord
                            aRecordName.size(),
                            &record,
                            client);
   if (GMP_FAILED(err)) {
     return err;
   }
   return client->Init(record, aContinuation);
 }
+
+GMPErr
+GMPEnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
+                   void* aUserArg)
+{
+  return g_platform_api->getrecordenumerator(aRecvIteratorFunc, aUserArg);
+}
--- a/dom/media/gmp-plugin/gmp-test-storage.h
+++ b/dom/media/gmp-plugin/gmp-test-storage.h
@@ -47,11 +47,15 @@ GMPRunOnMainThread(GMPTask* aTask);
 class OpenContinuation {
 public:
   virtual ~OpenContinuation() {}
   virtual void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) = 0;
 };
 
 GMPErr
 GMPOpenRecord(const std::string& aRecordName,
-           OpenContinuation* aContinuation);
+              OpenContinuation* aContinuation);
+
+GMPErr
+GMPEnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
+                   void* aUserArg);
 
 #endif // TEST_GMP_STORAGE_H__
--- a/dom/media/gmp/GMPPlatform.cpp
+++ b/dom/media/gmp/GMPPlatform.cpp
@@ -153,18 +153,20 @@ CreateMutex(GMPMutex** aMutex)
 }
 
 GMPErr
 CreateRecord(const char* aRecordName,
              uint32_t aRecordNameSize,
              GMPRecord** aOutRecord,
              GMPRecordClient* aClient)
 {
+  MOZ_ASSERT(IsOnChildMainThread());
+
   if (sMainLoop != MessageLoop::current()) {
-    NS_WARNING("GMP called CreateRecord() on non-main thread!");
+    MOZ_ASSERT(false, "GMP called CreateRecord() on non-main thread!");
     return GMPGenericErr;
   }
   if (aRecordNameSize > GMP_MAX_RECORD_NAME_SIZE) {
     NS_WARNING("GMP tried to CreateRecord with too long record name");
     return GMPGenericErr;
   }
   GMPStorageChild* storage = sChild->GetGMPStorage();
   if (!storage) {
@@ -189,16 +191,35 @@ SetTimerOnMainThread(GMPTask* aTask, int
 
 GMPErr
 GetClock(GMPTimestamp* aOutTime)
 {
   *aOutTime = time(0) * 1000;
   return GMPNoErr;
 }
 
+GMPErr
+CreateRecordIterator(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
+                     void* aUserArg)
+{
+  if (sMainLoop != MessageLoop::current()) {
+    MOZ_ASSERT(false, "GMP called CreateRecord() on non-main thread!");
+    return GMPGenericErr;
+  }
+  if (!aRecvIteratorFunc) {
+    return GMPInvalidArgErr;
+  }
+  GMPStorageChild* storage = sChild->GetGMPStorage();
+  if (!storage) {
+    return GMPGenericErr;
+  }
+  MOZ_ASSERT(storage);
+  return storage->EnumerateRecords(aRecvIteratorFunc, aUserArg);
+}
+
 void
 InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild)
 {
   if (!sMainLoop) {
     sMainLoop = MessageLoop::current();
   }
   if (!sChild) {
     sChild = aChild;
@@ -207,16 +228,17 @@ InitPlatformAPI(GMPPlatformAPI& aPlatfor
   aPlatformAPI.version = 0;
   aPlatformAPI.createthread = &CreateThread;
   aPlatformAPI.runonmainthread = &RunOnMainThread;
   aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
   aPlatformAPI.createmutex = &CreateMutex;
   aPlatformAPI.createrecord = &CreateRecord;
   aPlatformAPI.settimer = &SetTimerOnMainThread;
   aPlatformAPI.getcurrenttime = &GetClock;
+  aPlatformAPI.getrecordenumerator = &CreateRecordIterator;
 }
 
 GMPThreadImpl::GMPThreadImpl()
 : mMutex("GMPThreadImpl"),
   mThread("GMPThread")
 {
   MOZ_COUNT_CTOR(GMPThread);
 }
--- a/dom/media/gmp/GMPStorageChild.cpp
+++ b/dom/media/gmp/GMPStorageChild.cpp
@@ -263,20 +263,99 @@ GMPStorageChild::RecvWriteComplete(const
   }
   record->WriteComplete(aStatus);
   if (GMP_FAILED(aStatus)) {
     Close(record);
   }
   return true;
 }
 
+GMPErr
+GMPStorageChild::EnumerateRecords(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
+                                  void* aUserArg)
+{
+  if (mPlugin->GMPMessageLoop() != MessageLoop::current()) {
+    MOZ_ASSERT(false, "GMP used GMPStorage on non-main thread.");
+    return GMPGenericErr;
+  }
+  if (mShutdown) {
+    NS_WARNING("GMPStorage used after it's been shutdown!");
+    return GMPClosedErr;
+  }
+  if (!SendGetRecordNames()) {
+    return GMPGenericErr;
+  }
+  MOZ_ASSERT(aRecvIteratorFunc);
+  mPendingRecordIterators.push(RecordIteratorContext(aRecvIteratorFunc, aUserArg));
+  return GMPNoErr;
+}
+
+class GMPRecordIteratorImpl : public GMPRecordIterator {
+public:
+  GMPRecordIteratorImpl(const InfallibleTArray<nsCString>& aRecordNames)
+    : mRecordNames(aRecordNames)
+    , mIndex(0)
+  {
+    mRecordNames.Sort();
+  }
+
+  virtual GMPErr GetName(const char** aOutName, uint32_t* aOutNameLength) MOZ_OVERRIDE {
+    if (!aOutName || !aOutNameLength) {
+      return GMPInvalidArgErr;
+    }
+    if (mIndex == mRecordNames.Length()) {
+      return GMPEndOfEnumeration;
+    }
+    *aOutName = mRecordNames[mIndex].get();
+    *aOutNameLength = mRecordNames[mIndex].Length();
+    return GMPNoErr;
+  }
+
+  virtual GMPErr NextRecord() MOZ_OVERRIDE {
+    if (mIndex < mRecordNames.Length()) {
+      mIndex++;
+    }
+    return (mIndex < mRecordNames.Length()) ? GMPNoErr
+                                            : GMPEndOfEnumeration;
+  }
+
+  virtual void Close() MOZ_OVERRIDE {
+    delete this;
+  }
+
+private:
+  nsTArray<nsCString> mRecordNames;
+  size_t mIndex;
+};
+
+bool
+GMPStorageChild::RecvRecordNames(const InfallibleTArray<nsCString>& aRecordNames,
+                                 const GMPErr& aStatus)
+{
+  if (mShutdown || mPendingRecordIterators.empty()) {
+    return true;
+  }
+  RecordIteratorContext ctx = mPendingRecordIterators.front();
+  mPendingRecordIterators.pop();
+
+  if (GMP_FAILED(aStatus)) {
+    ctx.mFunc(nullptr, ctx.mUserArg, aStatus);
+  } else {
+    ctx.mFunc(new GMPRecordIteratorImpl(aRecordNames), ctx.mUserArg, GMPNoErr);
+  }
+  return true;
+}
+
 bool
 GMPStorageChild::RecvShutdown()
 {
   // Block any new storage requests, and thus any messages back to the
   // parent. We don't delete any objects here, as that may invalidate
   // GMPRecord pointers held by the GMP.
   mShutdown = true;
+  while (!mPendingRecordIterators.empty()) {
+    mPendingRecordIterators.pop();
+  }
   return true;
 }
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/GMPStorageChild.h
+++ b/dom/media/gmp/GMPStorageChild.h
@@ -5,16 +5,19 @@
 
 #ifndef GMPStorageChild_h_
 #define GMPStorageChild_h_
 
 #include "mozilla/gmp/PGMPStorageChild.h"
 #include "gmp-storage.h"
 #include "nsTHashtable.h"
 #include "nsRefPtrHashtable.h"
+#include "gmp-platform.h"
+
+#include <queue>
 
 namespace mozilla {
 namespace gmp {
 
 class GMPChild;
 class GMPStorageChild;
 
 class GMPRecordImpl : public GMPRecord
@@ -65,31 +68,48 @@ public:
   GMPErr Read(GMPRecordImpl* aRecord);
 
   GMPErr Write(GMPRecordImpl* aRecord,
                const uint8_t* aData,
                uint32_t aDataSize);
 
   GMPErr Close(GMPRecordImpl* aRecord);
 
+  GMPErr EnumerateRecords(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
+                          void* aUserArg);
+
 protected:
   ~GMPStorageChild() {}
 
   // PGMPStorageChild
   virtual bool RecvOpenComplete(const nsCString& aRecordName,
                                 const GMPErr& aStatus) MOZ_OVERRIDE;
   virtual bool RecvReadComplete(const nsCString& aRecordName,
                                 const GMPErr& aStatus,
                                 const InfallibleTArray<uint8_t>& aBytes) MOZ_OVERRIDE;
   virtual bool RecvWriteComplete(const nsCString& aRecordName,
                                  const GMPErr& aStatus) MOZ_OVERRIDE;
+  virtual bool RecvRecordNames(const InfallibleTArray<nsCString>& aRecordNames,
+                               const GMPErr& aStatus) MOZ_OVERRIDE;
   virtual bool RecvShutdown() MOZ_OVERRIDE;
 
 private:
   nsRefPtrHashtable<nsCStringHashKey, GMPRecordImpl> mRecords;
   GMPChild* mPlugin;
+
+  struct RecordIteratorContext {
+    explicit RecordIteratorContext(RecvGMPRecordIteratorPtr aFunc,
+                                   void* aUserArg)
+      : mFunc(aFunc)
+      , mUserArg(aUserArg)
+    {}
+    RecvGMPRecordIteratorPtr mFunc;
+    void* mUserArg;
+  };
+
+  std::queue<RecordIteratorContext> mPendingRecordIterators;
   bool mShutdown;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPStorageChild_h_
--- a/dom/media/gmp/GMPStorageParent.cpp
+++ b/dom/media/gmp/GMPStorageParent.cpp
@@ -13,16 +13,18 @@
 #include "gmp-storage.h"
 #include "mozilla/unused.h"
 #include "nsTHashtable.h"
 #include "nsDataHashtable.h"
 #include "prio.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "nsContentCID.h"
 #include "nsServiceManagerUtils.h"
+#include "mozilla/Base64.h"
+#include "nsISimpleEnumerator.h"
 
 namespace mozilla {
 
 #ifdef LOG
 #undef LOG
 #endif
 
 #ifdef PR_LOGGING
@@ -99,19 +101,27 @@ OpenStorageFile(const nsCString& aRecord
   MOZ_ASSERT(aOutFD);
 
   nsCOMPtr<nsIFile> f;
   nsresult rv = GetGMPStorageDir(getter_AddRefs(f), aNodeId);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  nsAutoString recordNameHash;
-  recordNameHash.AppendInt(HashString(aRecordName.get()));
-  f->Append(recordNameHash);
+  nsAutoCString recordNameBase64;
+  rv = Base64Encode(aRecordName, recordNameBase64);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  // Base64 can encode to a '/' character, which will mess with file paths,
+  // so we need to replace that here with something that won't mess with paths.
+  recordNameBase64.ReplaceChar('/', '-');
+
+  f->AppendNative(recordNameBase64);
 
   auto mode = PR_RDWR | PR_CREATE_FILE;
   if (aMode == Truncate) {
     mode |= PR_TRUNCATE;
   }
 
   return f->OpenNSPRFileDesc(mode, PR_IRWXU, aOutFD);
 }
@@ -188,16 +198,64 @@ public:
       return GMPGenericErr;
     }
     mFiles.Put(aRecordName, fd);
 
     int32_t bytesWritten = PR_Write(fd, aBytes.Elements(), aBytes.Length());
     return (bytesWritten == (int32_t)aBytes.Length()) ? GMPNoErr : GMPGenericErr;
   }
 
+  virtual GMPErr GetRecordNames(nsTArray<nsCString>& aOutRecordNames) MOZ_OVERRIDE
+  {
+    nsCOMPtr<nsIFile> storageDir;
+    nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mNodeId);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return GMPGenericErr;
+    }
+
+    nsCOMPtr<nsISimpleEnumerator> iter;
+    rv = storageDir->GetDirectoryEntries(getter_AddRefs(iter));
+    if (NS_FAILED(rv)) {
+      return GMPGenericErr;
+    }
+
+    bool hasMore;
+    while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
+      nsCOMPtr<nsISupports> supports;
+      rv = iter->GetNext(getter_AddRefs(supports));
+      if (NS_FAILED(rv)) {
+        continue;
+      }
+      nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
+      if (NS_FAILED(rv)) {
+        continue;
+      }
+
+      nsAutoCString leafName;
+      rv = dirEntry->GetNativeLeafName(leafName);
+      if (NS_FAILED(rv)) {
+        continue;
+      }
+
+      // The record's file name is the Base64 encode of the record name,
+      // with '/' characters replaced with '-' characters. Base64 decode
+      // to extract the file name.
+      leafName.ReplaceChar('-', '/');
+      nsAutoCString recordName;
+      rv = Base64Decode(leafName, recordName);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        continue;
+      }
+
+      aOutRecordNames.AppendElement(recordName);
+    }
+
+    return GMPNoErr;
+  }
+
   virtual void Close(const nsCString& aRecordName) MOZ_OVERRIDE
   {
     PRFileDesc* fd = mFiles.Get(aRecordName);
     if (fd) {
       if (PR_Close(fd) == PR_SUCCESS) {
         mFiles.Remove(aRecordName);
       } else {
         NS_WARNING("GMPDiskStorage Failed to clsose file.");
@@ -250,16 +308,22 @@ public:
     Record* record = nullptr;
     if (!mRecords.Get(aRecordName, &record)) {
       return GMPClosedErr;
     }
     record->mData = aBytes;
     return GMPNoErr;
   }
 
+  virtual GMPErr GetRecordNames(nsTArray<nsCString>& aOutRecordNames) MOZ_OVERRIDE
+  {
+    mRecords.EnumerateRead(EnumRecordNames, &aOutRecordNames);
+    return GMPNoErr;
+  }
+
   virtual void Close(const nsCString& aRecordName) MOZ_OVERRIDE
   {
     Record* record = nullptr;
     if (!mRecords.Get(aRecordName, &record)) {
       return;
     }
     if (!record->mData.Length()) {
       // Record is empty, delete.
@@ -272,16 +336,26 @@ public:
 private:
 
   struct Record {
     Record() : mIsOpen(false) {}
     nsTArray<uint8_t> mData;
     bool mIsOpen;
   };
 
+  static PLDHashOperator
+  EnumRecordNames(const nsACString& aKey,
+                  Record* aRecord,
+                  void* aUserArg)
+  {
+    nsTArray<nsCString>* names = reinterpret_cast<nsTArray<nsCString>*>(aUserArg);
+    names->AppendElement(aKey);
+    return PL_DHASH_NEXT;
+  }
+
   nsClassHashtable<nsCStringHashKey, Record> mRecords;
 };
 
 GMPStorageParent::GMPStorageParent(const nsCString& aNodeId,
                                    GMPParent* aPlugin)
   : mNodeId(aNodeId)
   , mPlugin(aPlugin)
   , mShutdown(false)
@@ -385,16 +459,32 @@ GMPStorageParent::RecvWrite(const nsCStr
   }
 
   unused << SendWriteComplete(aRecordName, mStorage->Write(aRecordName, aBytes));
 
   return true;
 }
 
 bool
+GMPStorageParent::RecvGetRecordNames()
+{
+  LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
+
+  if (mShutdown) {
+    return true;
+  }
+
+  nsTArray<nsCString> recordNames;
+  GMPErr status = mStorage->GetRecordNames(recordNames);
+  unused << SendRecordNames(recordNames, status);
+
+  return true;
+}
+
+bool
 GMPStorageParent::RecvClose(const nsCString& aRecordName)
 {
   LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get()));
 
   if (mShutdown) {
     return true;
   }
 
--- a/dom/media/gmp/GMPStorageParent.h
+++ b/dom/media/gmp/GMPStorageParent.h
@@ -20,16 +20,17 @@ public:
   virtual ~GMPStorage() {}
 
   virtual GMPErr Open(const nsCString& aRecordName) = 0;
   virtual bool IsOpen(const nsCString& aRecordName) = 0;
   virtual GMPErr Read(const nsCString& aRecordName,
                       nsTArray<uint8_t>& aOutBytes) = 0;
   virtual GMPErr Write(const nsCString& aRecordName,
                        const nsTArray<uint8_t>& aBytes) = 0;
+  virtual GMPErr GetRecordNames(nsTArray<nsCString>& aOutRecordNames) = 0;
   virtual void Close(const nsCString& aRecordName) = 0;
 };
 
 class GMPStorageParent : public PGMPStorageParent {
 public:
   NS_INLINE_DECL_REFCOUNTING(GMPStorageParent)
   GMPStorageParent(const nsCString& aNodeId,
                    GMPParent* aPlugin);
@@ -37,16 +38,17 @@ public:
   nsresult Init();
   void Shutdown();
 
 protected:
   virtual bool RecvOpen(const nsCString& aRecordName) MOZ_OVERRIDE;
   virtual bool RecvRead(const nsCString& aRecordName) MOZ_OVERRIDE;
   virtual bool RecvWrite(const nsCString& aRecordName,
                          const InfallibleTArray<uint8_t>& aBytes) MOZ_OVERRIDE;
+  virtual bool RecvGetRecordNames() MOZ_OVERRIDE;
   virtual bool RecvClose(const nsCString& aRecordName) MOZ_OVERRIDE;
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
 private:
   ~GMPStorageParent() {}
 
   UniquePtr<GMPStorage> mStorage;
 
--- a/dom/media/gmp/PGMPStorage.ipdl
+++ b/dom/media/gmp/PGMPStorage.ipdl
@@ -14,21 +14,23 @@ namespace gmp {
 async protocol PGMPStorage
 {
   manager PGMP;
 
 child:
   OpenComplete(nsCString aRecordName, GMPErr aStatus);
   ReadComplete(nsCString aRecordName, GMPErr aStatus, uint8_t[] aBytes);
   WriteComplete(nsCString aRecordName, GMPErr aStatus);
+  RecordNames(nsCString[] aRecordNames, GMPErr aStatus);
   Shutdown();
 
 parent:
   Open(nsCString aRecordName);
   Read(nsCString aRecordName);
   Write(nsCString aRecordName, uint8_t[] aBytes);
   Close(nsCString aRecordName);
+  GetRecordNames();
   __delete__();
 
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/gmp-api/gmp-audio-codec.h
+++ b/dom/media/gmp/gmp-api/gmp-audio-codec.h
@@ -32,12 +32,12 @@ struct GMPAudioCodec
   uint32_t mChannelCount;
   uint32_t mBitsPerChannel;
   uint32_t mSamplesPerSecond;
 
   // Codec extra data, such as vorbis setup header, or
   // AAC AudioSpecificConfig.
   // These are null/0 if not externally negotiated
   const uint8_t* mExtraData;
-  size_t         mExtraDataLen;
+  uint32_t       mExtraDataLen;
 };
 
 #endif // GMP_AUDIO_CODEC_h_
--- a/dom/media/gmp/gmp-api/gmp-errors.h
+++ b/dom/media/gmp/gmp-api/gmp-errors.h
@@ -40,15 +40,17 @@ typedef enum {
   GMPAllocErr = 3,
   GMPNotImplementedErr = 4,
   GMPRecordInUse = 5,
   GMPQuotaExceededErr = 6,
   GMPDecodeErr = 7,
   GMPEncodeErr = 8,
   GMPNoKeyErr = 9,
   GMPCryptoErr = 10,
+  GMPEndOfEnumeration = 11,
+  GMPInvalidArgErr = 12,
   GMPLastErr // Placeholder, must be last. This enum's values must remain consecutive!
 } GMPErr;
 
 #define GMP_SUCCEEDED(x) ((x) == GMPNoErr)
 #define GMP_FAILED(x) ((x) != GMPNoErr)
 
 #endif // GMP_ERRORS_h_
--- a/dom/media/gmp/gmp-api/gmp-platform.h
+++ b/dom/media/gmp/gmp-api/gmp-platform.h
@@ -77,25 +77,42 @@ typedef GMPErr (*GMPCreateRecordPtr)(con
                                      uint32_t aRecordNameSize,
                                      GMPRecord** aOutRecord,
                                      GMPRecordClient* aClient);
 
 // Call on main thread only.
 typedef GMPErr (*GMPSetTimerOnMainThreadPtr)(GMPTask* aTask, int64_t aTimeoutMS);
 typedef GMPErr (*GMPGetCurrentTimePtr)(GMPTimestamp* aOutTime);
 
+typedef void (*RecvGMPRecordIteratorPtr)(GMPRecordIterator* aRecordIterator,
+                                         void* aUserArg,
+                                         GMPErr aStatus);
+
+// Creates a GMPCreateRecordIterator to enumerate the records in storage.
+// When the iterator is ready, the function at aRecvIteratorFunc
+// is called with the GMPRecordIterator as an argument. If the operation
+// fails, RecvGMPRecordIteratorPtr is called with a failure aStatus code.
+// The list that the iterator is covering is fixed when
+// GMPCreateRecordIterator is called, it is *not* updated when changes are
+// made to storage.
+// Iterator begins pointing at first record.
+// aUserArg is passed to the aRecvIteratorFunc upon completion.
+typedef GMPErr (*GMPCreateRecordIteratorPtr)(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
+                                             void* aUserArg);
+
 struct GMPPlatformAPI {
   // Increment the version when things change. Can only add to the struct,
   // do not change what already exists. Pointers to functions may be NULL
   // when passed to plugins, but beware backwards compat implications of
   // doing that.
   uint16_t version; // Currently version 0
 
   GMPCreateThreadPtr createthread;
   GMPRunOnMainThreadPtr runonmainthread;
   GMPSyncRunOnMainThreadPtr syncrunonmainthread;
   GMPCreateMutexPtr createmutex;
   GMPCreateRecordPtr createrecord;
   GMPSetTimerOnMainThreadPtr settimer;
   GMPGetCurrentTimePtr getcurrenttime;
+  GMPCreateRecordIteratorPtr getrecordenumerator;
 };
 
 #endif // GMP_PLATFORM_h_
--- a/dom/media/gmp/gmp-api/gmp-storage.h
+++ b/dom/media/gmp/gmp-api/gmp-storage.h
@@ -105,9 +105,36 @@ class GMPRecordClient {
   // - GMPGenericErr - Unspecified error.
   // If aStatus is not GMPNoErr, the GMPRecord is unusable, and you must
   // call Close() on the GMPRecord to dispose of it.
   virtual void WriteComplete(GMPErr aStatus) = 0;
 
   virtual ~GMPRecordClient() {}
 };
 
+// Iterates over the records that are available. Note: this list maintains
+// a snapshot of the records that were present when the iterator was created.
+// Create by calling the GMPCreateRecordIteratorPtr function on the
+// GMPPlatformAPI struct.
+// Iteration is in alphabetical order.
+class GMPRecordIterator {
+public:
+  // Retrieve the name for the current record.
+  // Returns GMPNoErr if successful, or GMPEndOfEnumeration if iteration has
+  // reached the end.
+  virtual GMPErr GetName(const char ** aOutName, uint32_t * aOutNameLength) = 0;
+
+  // Advance iteration to the next record.
+  // Returns GMPNoErr if successful, or GMPEndOfEnumeration if iteration has
+  // reached the end.
+  virtual GMPErr NextRecord() = 0;
+
+  // Signals to the GMP host that the GMP is finished with the
+  // GMPRecordIterator. GMPs must call this to release memory held by
+  // the GMPRecordIterator. Do not access the GMPRecordIterator pointer
+  // after calling this!
+  // Memory retrieved by GetName is *not* valid after calling Close()!
+  virtual void Close() = 0;
+
+  virtual ~GMPRecordIterator() {}
+};
+
 #endif // GMP_STORAGE_h_
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -575,16 +575,77 @@ class GMPStorageTest : public GMPDecrypt
     CreateDecryptor(NS_LITERAL_STRING("example17.com"),
                     NS_LITERAL_STRING("example18.com"),
                     false);
     Expect(NS_LITERAL_CSTRING("retrieved plugin-voucher: gmp-fake placeholder voucher"),
            NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
     Update(NS_LITERAL_CSTRING("retrieve-plugin-voucher"));
   }
 
+  void TestGetRecordNamesInMemoryStorage() {
+    TestGetRecordNames(true);
+  }
+
+  nsCString mRecordNames;
+
+  void AppendIntPadded(nsACString& aString, uint32_t aInt) {
+    if (aInt > 0 && aInt < 10) {
+      aString.AppendLiteral("0");
+    }
+    aString.AppendInt(aInt);
+  }
+
+  void TestGetRecordNames(bool aPrivateBrowsing) {
+    CreateDecryptor(NS_LITERAL_STRING("foo.com"),
+                    NS_LITERAL_STRING("bar.com"),
+                    aPrivateBrowsing);
+
+    // Create a number of records of different names.
+    const uint32_t num = 100;
+    for (uint32_t i = 0; i < num; i++) {
+      nsAutoCString response;
+      response.AppendLiteral("stored data");
+      AppendIntPadded(response, i);
+      response.AppendLiteral(" test-data");
+      AppendIntPadded(response, i);
+
+      if (i != 0) {
+        mRecordNames.AppendLiteral(",");
+      }
+      mRecordNames.AppendLiteral("data");
+      AppendIntPadded(mRecordNames, i);
+
+      nsAutoCString update;
+      update.AppendLiteral("store data");
+      AppendIntPadded(update, i);
+      update.AppendLiteral(" test-data");
+      AppendIntPadded(update, i);
+
+      nsIRunnable* continuation = nullptr;
+      if (i + 1 == num) {
+        continuation =
+          NS_NewRunnableMethod(this, &GMPStorageTest::TestGetRecordNames_QueryNames);
+      }
+      Expect(response, continuation);
+      Update(update);
+    }
+  }
+
+  void TestGetRecordNames_QueryNames() {
+    nsCString response("record-names ");
+    response.Append(mRecordNames);
+    Expect(response,
+           NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
+    Update(NS_LITERAL_CSTRING("retrieve-record-names"));
+  }
+
+  void GetRecordNamesPersistentStorage() {
+    TestGetRecordNames(false);
+  }
+
   void Expect(const nsCString& aMessage, nsIRunnable* aContinuation) {
     mExpected.AppendElement(ExpectedMessage(aMessage, aContinuation));
   }
 
   void AwaitFinished() {
     while (!mFinished) {
       NS_ProcessNextEvent(nullptr, true);
     }
@@ -746,8 +807,18 @@ TEST(GeckoMediaPlugins, GMPOutputProtect
   if (!IsVistaOrLater()) {
     return;
   }
 
   nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
   runner->DoTest(&GMPStorageTest::TestOutputProtection);
 }
 #endif
+
+TEST(GeckoMediaPlugins, GMPStorageGetRecordNamesInMemoryStorage) {
+  nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
+  runner->DoTest(&GMPStorageTest::TestGetRecordNamesInMemoryStorage);
+}
+
+TEST(GeckoMediaPlugins, GMPStorageGetRecordNamesPersistentStorage) {
+  nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
+  runner->DoTest(&GMPStorageTest::GetRecordNamesPersistentStorage);
+}
--- a/dom/media/gtest/TestMP4Reader.cpp
+++ b/dom/media/gtest/TestMP4Reader.cpp
@@ -31,16 +31,18 @@ public:
   {
     EXPECT_EQ(NS_OK, Preferences::SetBool(
                        "media.fragmented-mp4.use-blank-decoder", true));
 
     EXPECT_EQ(NS_OK, resource->Open(nullptr));
     decoder->SetResource(resource);
 
     reader->Init(nullptr);
+    reader->SetTaskQueue(
+      new MediaTaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("TestMP4Reader"))));
     {
       // This needs to be done before invoking GetBuffered. This is normally
       // done by MediaDecoderStateMachine.
       ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
       reader->SetStartTime(0);
     }
   }
 
@@ -50,16 +52,20 @@ public:
                                NS_NewRunnableMethod(this, &TestBinding::ReadMetadata));
     EXPECT_EQ(NS_OK, rv);
     thread->Shutdown();
   }
 
 private:
   virtual ~TestBinding()
   {
+    reader->GetTaskQueue()->Dispatch(NS_NewRunnableMethod(reader,
+                                                          &MP4Reader::Shutdown));
+    reader->GetTaskQueue()->Shutdown();
+
     decoder = nullptr;
     resource = nullptr;
     reader = nullptr;
     SharedThreadPool::SpinUntilShutdown();
   }
 
   void ReadMetadata()
   {
--- a/dom/media/omx/MediaCodecProxy.cpp
+++ b/dom/media/omx/MediaCodecProxy.cpp
@@ -105,20 +105,16 @@ MediaCodecProxy::MediaCodecProxy(sp<ALoo
   } else {
     allocateCodec();
   }
 }
 
 MediaCodecProxy::~MediaCodecProxy()
 {
   releaseCodec();
-
-  // Complete all pending Binder ipc transactions
-  IPCThreadState::self()->flushCommands();
-
   cancelResource();
 }
 
 bool
 MediaCodecProxy::requestResource()
 {
   if (mResourceHandler == nullptr) {
     return false;
@@ -176,25 +172,30 @@ MediaCodecProxy::releaseCodec()
   {
     // Write Lock for mCodec
     RWLock::AutoWLock awl(mCodecLock);
 
     codec = mCodec;
 
     // Release MediaCodec
     if (mCodec != nullptr) {
+      status_t err = mCodec->stop();
       mCodec->release();
       mCodec = nullptr;
     }
   }
 
   while (codec.promote() != nullptr) {
     // this value come from stagefright's AwesomePlayer.
     usleep(1000);
   }
+
+  // Complete all pending Binder ipc transactions
+  IPCThreadState::self()->flushCommands();
+
 }
 
 bool
 MediaCodecProxy::allocated() const
 {
   // Read Lock for mCodec
   RWLock::AutoRLock arl(mCodecLock);
 
@@ -592,31 +593,30 @@ status_t MediaCodecProxy::Output(MediaBu
   if (flags & MediaCodec::BUFFER_FLAG_EOS) {
     return ERROR_END_OF_STREAM;
   }
   return err;
 }
 
 bool MediaCodecProxy::IsWaitingResources()
 {
+  // Write Lock for mCodec
+  RWLock::AutoWLock awl(mCodecLock);
   return mCodec == nullptr;
 }
 
 bool MediaCodecProxy::IsDormantNeeded()
 {
   return mCodecLooper.get() ? true : false;
 }
 
 void MediaCodecProxy::ReleaseMediaResources()
 {
-  if (mCodec.get()) {
-    mCodec->stop();
-    mCodec->release();
-    mCodec.clear();
-  }
+  releaseCodec();
+  cancelResource();
 }
 
 void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) {
   if (aBuffer) {
     sp<MetaData> metaData = aBuffer->meta_data();
     int32_t index;
     metaData->findInt32(kKeyBufferIndex, &index);
     aBuffer->release();
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -608,26 +608,26 @@ PeerConnectionTest.prototype.close = fun
         is(self.pcRemote.signalingState, "closed", "pcRemote is in 'closed' state");
       }
       clearTimeout(closeTimeout);
       everythingClosed = true;
       onSuccess();
     }
   }
 
-  function signalingstatechangeLocalClose(state) {
-    info("'onsignalingstatechange' event '" + state + "' received");
-    is(state, "closed", "onsignalingstatechange event is closed");
+  function signalingstatechangeLocalClose(e) {
+    info("'signalingstatechange' event received");
+    is(e.target.signalingState, "closed", "signalingState is closed");
     self.waitingForLocal = false;
     verifyClosed();
   }
 
-  function signalingstatechangeRemoteClose(state) {
-    info("'onsignalingstatechange' event '" + state + "' received");
-    is(state, "closed", "onsignalingstatechange event is closed");
+  function signalingstatechangeRemoteClose(e) {
+    info("'signalingstatechange' event received");
+    is(e.target.signalingState, "closed", "signalingState is closed");
     self.waitingForRemote = false;
     verifyClosed();
   }
 
   function closeEverything() {
     if ((self.pcLocal) && (self.pcLocal.signalingState !== "closed")) {
       info("Closing pcLocal");
       self.pcLocal.onsignalingstatechange = signalingstatechangeLocalClose;
@@ -739,19 +739,20 @@ function PCT_setLocalDescription(peer, d
   var stateChanged = false;
 
   function check_next_test() {
     if (eventFired && stateChanged) {
       onSuccess();
     }
   }
 
-  peer.onsignalingstatechange = function (state) {
-    info(peer + ": 'onsignalingstatechange' event '" + state + "' received");
-    if(stateExpected === state && eventFired == false) {
+  peer.onsignalingstatechange = function (e) {
+    info(peer + ": 'signalingstatechange' event received");
+    var state = e.target.signalingState;
+    if(stateExpected === state && !eventFired) {
       eventFired = true;
       peer.setLocalDescStableEventDate = new Date();
       check_next_test();
     } else {
       ok(false, "This event has either already fired or there has been a " +
                 "mismatch between event received " + state +
                 " and event expected " + stateExpected);
     }
@@ -807,19 +808,20 @@ function PCT_setRemoteDescription(peer, 
   var stateChanged = false;
 
   function check_next_test() {
     if (eventFired && stateChanged) {
       onSuccess();
     }
   }
 
-  peer.onsignalingstatechange = function (state) {
-    info(peer + ": 'onsignalingstatechange' event '" + state + "' received");
-    if(stateExpected === state && eventFired == false) {
+  peer.onsignalingstatechange = function(e) {
+    info(peer + ": 'signalingstatechange' event received");
+    var state = e.target.signalingState;
+    if(stateExpected === state && !eventFired) {
       eventFired = true;
       peer.setRemoteDescStableEventDate = new Date();
       check_next_test();
     } else {
       ok(false, "This event has either already fired or there has been a " +
                 "mismatch between event received " + state +
                 " and event expected " + stateExpected);
     }
@@ -1613,17 +1615,16 @@ function PeerConnectionWrapper(label, co
   this.signalingStateCallbacks = {};
 
   /**
    * Callback for native peer connection 'onsignalingstatechange' events. If no
    * custom handler has been specified via 'this.onsignalingstatechange', a
    * failure will be raised if an event of this type is caught.
    *
    * @param {Object} aEvent
-   *        Event data which includes the newly created data channel
    */
   this._pc.onsignalingstatechange = function (anEvent) {
     info(self + ": 'onsignalingstatechange' event fired");
 
     Object.keys(self.signalingStateCallbacks).forEach(function(name) {
       self.signalingStateCallbacks[name](anEvent);
     });
     // this calls the eventhandler only once and then overwrites it with the
@@ -1925,17 +1926,17 @@ PeerConnectionWrapper.prototype = {
 
   /**
    * Registers a callback for the signaling state change and
    * appends the new state to an array for logging it later.
    */
   logSignalingState: function PCW_logSignalingState() {
     var self = this;
 
-    function _logSignalingState(state) {
+    function _logSignalingState(e) {
       var newstate = self._pc.signalingState;
       var oldstate = self.signalingStateLog[self.signalingStateLog.length - 1]
       if (Object.keys(signalingStateTransitions).indexOf(oldstate) != -1) {
         ok(signalingStateTransitions[oldstate].indexOf(newstate) != -1, self + ": legal signaling state transition from " + oldstate + " to " + newstate);
       } else {
         ok(false, self + ": old signaling state " + oldstate + " missing in signaling transition array");
       }
       self.signalingStateLog.push(newstate);
@@ -1951,17 +1952,17 @@ PeerConnectionWrapper.prototype = {
    *
    * @param {object} candidate
    *        The mozRTCIceCandidate to be added or stored
    */
   storeOrAddIceCandidate : function PCW_storeOrAddIceCandidate(candidate) {
     var self = this;
 
     self._remote_ice_candidates.push(candidate);
-    if (self.signalingstate === 'closed') {
+    if (self.signalingState === 'closed') {
       info("Received ICE candidate for closed PeerConnection - discarding");
       return;
     }
     if (!self.holdIceCandidates) {
       self.addIceCandidate(candidate);
     } else {
       self._ice_candidates_to_add.push(candidate);
     }
--- a/dom/media/tests/mochitest/test_peerConnection_bug827843.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug827843.html
@@ -19,33 +19,35 @@
   var steps = [
     [
       "CHECK_SDP_ON_CLOSED_PC",
       function (test) {
         var description;
         var exception = null;
 
         // handle the event which the close() triggers
-        test.pcLocal.onsignalingstatechange = function (state) {
-          is(state, "closed", "Received expected onsignalingstatechange event 'closed'");
+        test.pcLocal.onsignalingstatechange = function (e) {
+          is(e.target.signalingState, "closed",
+             "Received expected onsignalingstatechange event on 'closed'");
         }
 
         test.pcLocal.close();
 
         try { description = test.pcLocal.localDescription; } catch (e) { exception = e; }
         ok(exception, "Attempt to access localDescription of pcLocal after close throws exception");
         exception = null;
 
         try { description = test.pcLocal.remoteDescription; } catch (e) { exception = e; }
         ok(exception, "Attempt to access remoteDescription of pcLocal after close throws exception");
         exception = null;
 
         // handle the event which the close() triggers
-        test.pcRemote.onsignalingstatechange = function (state) {
-          is(state, "closed", "Received expected onsignalingstatechange event 'closed'");
+        test.pcRemote.onsignalingstatechange = function (e) {
+          is(e.target.signalingState, "closed",
+             "Received expected onsignalingstatechange event on 'closed'");
         }
 
         test.pcRemote.close();
 
         try  { description = test.pcRemote.localDescription; } catch (e) { exception = e; }
         ok(exception, "Attempt to access localDescription of pcRemote after close throws exception");
         exception = null;
 
--- a/dom/media/tests/mochitest/test_peerConnection_close.html
+++ b/dom/media/tests/mochitest/test_peerConnection_close.html
@@ -11,31 +11,33 @@
 <script type="application/javascript">
   createHTML({
     bug: "991877",
     title: "Basic RTCPeerConnection.close() tests"
   });
 
   runNetworkTest(function () {
     var pc = new mozRTCPeerConnection();
-    var signalStateChanged = false;
     var exception = null;
     var eTimeout = null;
 
     // everything should be in initial state
     is(pc.signalingState, "stable", "Initial signalingState is 'stable'");
     is(pc.iceConnectionState, "new", "Initial iceConnectionState is 'new'");
     is(pc.iceGatheringState, "new", "Initial iceGatheringState is 'new'");
 
-    pc.onsignalingstatechange = function(aEvent) {
+    var finish;
+    var finished = new Promise(function(resolve) {
+      finish = resolve;
+    });
+
+    pc.onsignalingstatechange = function(e) {
       clearTimeout(eTimeout);
-      signalStateChanged = true;
-      is(aEvent, "closed", "onsignalingstatechange event is 'closed'");
-      is(pc.signalingState, "closed", "Event callback signalingState is 'closed'");
-      is(pc.iceConnectionState, "closed", "Event callback iceConnectionState is 'closed'");
+      is(pc.signalingState, "closed", "signalingState is 'closed'");
+      is(pc.iceConnectionState, "closed", "iceConnectionState is 'closed'");
 
       try {
         pc.close();
       } catch (e) {
         exception = e;
       }
       is(exception, null, "A second close() should not raise an exception");
       is(pc.signalingState, "closed", "Final signalingState stays at 'closed'");
@@ -77,52 +79,32 @@
       SimpleTest.doesThrow(function() {
         pc.getStats()},
         "getStats() on closed PC raised expected exception");
 
       SimpleTest.doesThrow(function() {
         pc.setIdentityProvider("Invalid Provider")},
         "setIdentityProvider() on closed PC raised expected exception");
 
-      // in case we are ending the test from within here
-      if(pc !== null) {
-        pc = null;
-        networkTestFinished();
-      }
+      finish();
     }
 
-    // This is only a shortcut to prevent a mochitest timeout in case the
-    // event does not fire
+    // This prevents a mochitest timeout in case the event does not fire
     eTimeout = setTimeout(function() {
-      ok(signalStateChanged, "Failed to receive expected onsignalingstatechange event in 60s");
-
-      // in case we are ending the test in this timeout
-      if (pc !== null) {
-        pc = null;
-        networkTestFinished();
-      }
+      ok(false, "Failed to receive expected onsignalingstatechange event in 60s");
+      finish();
     }, 60000);
 
     try {
       pc.close();
     } catch (e) {
       exception = e;
     }
     is(exception, null, "closing the connection raises no exception");
-    if (pc !== null) {
-      is(pc.signalingState, "closed", "Final signalingState is 'closed'");
-      is(pc.iceConnectionState, "closed", "Final iceConnectionState is 'closed'");
-    }
+    is(pc.signalingState, "closed", "Final signalingState is 'closed'");
+    is(pc.iceConnectionState, "closed", "Final iceConnectionState is 'closed'");
 
-    if (signalStateChanged) {
-      clearTimeout(eTimeout);
-      // in case we are ending the test outside the even handler
-      if (pc !== null) {
-        pc = null;
-        networkTestFinished();
-      }
-    }
-
+    finished.then(networkTestFinished);
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/webaudio/DelayBuffer.cpp
+++ b/dom/media/webaudio/DelayBuffer.cpp
@@ -242,19 +242,17 @@ DelayBuffer::UpdateUpmixChannels(int aNe
   }
 
   static const float silenceChannel[WEBAUDIO_BLOCK_SIZE] = {};
 
   NS_WARN_IF_FALSE(mHaveWrittenBlock || aNewReadChunk != mCurrentChunk,
                    "Smoothing is making feedback delay too small.");
 
   mLastReadChunk = aNewReadChunk;
-  // Missing assignment operator is bug 976927
-  mUpmixChannels.ReplaceElementsAt(0, mUpmixChannels.Length(),
-                                   mChunks[aNewReadChunk].mChannelData);
+  mUpmixChannels = mChunks[aNewReadChunk].mChannelData;
   MOZ_ASSERT(mUpmixChannels.Length() <= aChannelCount);
   if (mUpmixChannels.Length() < aChannelCount) {
     if (aChannelInterpretation == ChannelInterpretation::Speakers) {
       AudioChannelsUpMix(&mUpmixChannels, aChannelCount, silenceChannel);
       MOZ_ASSERT(mUpmixChannels.Length() == aChannelCount,
                  "We called GetAudioChannelsSuperset to avoid this");
     } else {
       // Fill up the remaining channels with zeros
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -2815,17 +2815,17 @@ nsPluginInstanceOwner::GetContentsScaleF
   double scaleFactor = 1.0;
   // On Mac, device pixels need to be translated to (and from) "display pixels"
   // for plugins. On other platforms, plugin coordinates are always in device
   // pixels.
 #if defined(XP_MACOSX)
   nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(mContent->OwnerDoc());
   if (presShell) {
     scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
-      presShell->GetPresContext()->DeviceContext()->UnscaledAppUnitsPerDevPixel();
+      presShell->GetPresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
   }
 #endif
   *result = scaleFactor;
   return NS_OK;
 }
 
 void nsPluginInstanceOwner::SetFrame(nsPluginFrame *aFrame)
 {
--- a/dom/webidl/Fetch.webidl
+++ b/dom/webidl/Fetch.webidl
@@ -4,32 +4,32 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://fetch.spec.whatwg.org/
  */
 
 typedef object JSON;
 // FIXME(nsm): Bug 739173: FormData is not available in workers.
-// typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or ScalarValueString or URLSearchParams) BodyInit;
-typedef (ArrayBuffer or ArrayBufferView or Blob or ScalarValueString or URLSearchParams) BodyInit;
+// typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or USVString or URLSearchParams) BodyInit;
+typedef (ArrayBuffer or ArrayBufferView or Blob or USVString or URLSearchParams) BodyInit;
 
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface Body {
   readonly attribute boolean bodyUsed;
   [Throws]
   Promise<ArrayBuffer> arrayBuffer();
   [Throws]
   Promise<Blob> blob();
   // FIXME(nsm): Bug 739173 FormData is not supported in workers.
   // Promise<FormData> formData();
   [Throws]
   Promise<JSON> json();
   [Throws]
-  Promise<ScalarValueString> text();
+  Promise<USVString> text();
 };
 
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface GlobalFetch {
   [Throws, Func="mozilla::dom::Headers::PrefEnabled"]
   Promise<Response> fetch(RequestInfo input, optional RequestInit init);
 };
 
--- a/dom/webidl/File.webidl
+++ b/dom/webidl/File.webidl
@@ -2,22 +2,22 @@
 /* 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/.
  */
 
 interface nsIFile;
 
 [Constructor(sequence<(ArrayBuffer or ArrayBufferView or Blob or DOMString)> fileBits,
-             ScalarValueString fileName, optional FilePropertyBag options),
+             USVString fileName, optional FilePropertyBag options),
 
  // These constructors are just for chrome callers:
  Constructor(Blob fileBits, optional ChromeFilePropertyBag options),
  Constructor(nsIFile fileBits, optional ChromeFilePropertyBag options),
- Constructor(ScalarValueString fileBits, optional ChromeFilePropertyBag options),
+ Constructor(USVString fileBits, optional ChromeFilePropertyBag options),
 
  Exposed=(Window,Worker)]
 interface File : Blob {
 
   readonly attribute DOMString name;
 
   [GetterThrows]
   readonly attribute long long lastModified;
--- a/dom/webidl/Request.webidl
+++ b/dom/webidl/Request.webidl
@@ -2,24 +2,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * https://fetch.spec.whatwg.org/#request-class
  */
 
-typedef (Request or ScalarValueString) RequestInfo;
+typedef (Request or USVString) RequestInfo;
 
 [Constructor(RequestInfo input, optional RequestInit init),
  Exposed=(Window,Worker),
  Func="mozilla::dom::Headers::PrefEnabled"]
 interface Request {
   readonly attribute ByteString method;
-  readonly attribute ScalarValueString url;
+  readonly attribute USVString url;
   readonly attribute Headers headers;
 
   readonly attribute DOMString referrer;
   readonly attribute RequestMode mode;
   readonly attribute RequestCredentials credentials;
 
   Request clone();
 };
--- a/dom/webidl/Response.webidl
+++ b/dom/webidl/Response.webidl
@@ -7,21 +7,21 @@
  * https://fetch.spec.whatwg.org/#response-class
  */
 
 [Constructor(optional BodyInit body, optional ResponseInit init),
  Exposed=(Window,Worker),
  Func="mozilla::dom::Headers::PrefEnabled"]
 interface Response {
   static Response error();
-  static Response redirect(ScalarValueString url, optional unsigned short status = 302);
+  static Response redirect(USVString url, optional unsigned short status = 302);
 
   readonly attribute ResponseType type;
 
-  readonly attribute ScalarValueString url;
+  readonly attribute USVString url;
   readonly attribute unsigned short status;
   readonly attribute ByteString statusText;
   readonly attribute Headers headers;
 
   Response clone();
 };
 
 Response implements Body;
--- a/dom/webidl/ServiceWorkerContainer.webidl
+++ b/dom/webidl/ServiceWorkerContainer.webidl
@@ -15,21 +15,21 @@ interface ServiceWorkerContainer : Event
   // https://github.com/slightlyoff/ServiceWorker/issues/198
   // and discussion at https://etherpad.mozilla.org/serviceworker07apr
   [Unforgeable] readonly attribute ServiceWorker? controller;
 
   [Throws]
   readonly attribute Promise<ServiceWorkerRegistration> ready;
 
   [Throws]
-  Promise<ServiceWorkerRegistration> register(ScalarValueString scriptURL,
+  Promise<ServiceWorkerRegistration> register(USVString scriptURL,
                                               optional RegistrationOptionList options);
 
   [Throws]
-  Promise<ServiceWorkerRegistration> getRegistration(optional ScalarValueString documentURL = "");
+  Promise<ServiceWorkerRegistration> getRegistration(optional USVString documentURL = "");
 
   [Throws]
    Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
 
   attribute EventHandler oncontrollerchange;
   attribute EventHandler onreloadpage;
   attribute EventHandler onerror;
 };
@@ -42,10 +42,10 @@ partial interface ServiceWorkerContainer
   [Throws,Pref="dom.serviceWorkers.testing.enabled"]
   DOMString getScopeForUrl(DOMString url);
 
   [Throws,Pref="dom.serviceWorkers.testing.enabled"]
   DOMString getControllingWorkerScriptURLForPath(DOMString path);
 };
 
 dictionary RegistrationOptionList {
-  ScalarValueString scope = "/";
+  USVString scope = "/";
 };
--- a/dom/webidl/ServiceWorkerRegistration.webidl
+++ b/dom/webidl/ServiceWorkerRegistration.webidl
@@ -10,16 +10,16 @@
 
 [Pref="dom.serviceWorkers.enabled",
  Exposed=Window]
 interface ServiceWorkerRegistration : EventTarget {
   [Unforgeable] readonly attribute ServiceWorker? installing;
   [Unforgeable] readonly attribute ServiceWorker? waiting;
   [Unforgeable] readonly attribute ServiceWorker? active;
 
-  readonly attribute ScalarValueString scope;
+  readonly attribute USVString scope;
 
   [Throws]
   Promise<boolean> unregister();
 
   // event
   attribute EventHandler onupdatefound;
 };
--- a/dom/webidl/TestInterfaceJS.webidl
+++ b/dom/webidl/TestInterfaceJS.webidl
@@ -26,17 +26,17 @@ interface TestInterfaceJS {
   long pingPongDictionaryOrLong(optional (TestInterfaceJSUnionableDictionary or long) dictOrLong);
   DOMString pingPongMap(MozMap<any> map);
   long objectSequenceLength(sequence<object> seq);
   long anySequenceLength(sequence<any> seq);
 
   // For testing bug 968335.
   DOMString getCallerPrincipal();
 
-  DOMString convertSVS(ScalarValueString svs);
+  DOMString convertSVS(USVString svs);
 
   (TestInterfaceJS or long) pingPongUnion((TestInterfaceJS or long) something);
   (DOMString or TestInterfaceJS?) pingPongUnionContainingNull((TestInterfaceJS? or DOMString) something);
   (TestInterfaceJS or long)? pingPongNullableUnion((TestInterfaceJS or long)? something);
   (Location or TestInterfaceJS) returnBadUnion();
 
   [Cached, Pure]
   readonly attribute short cachedAttr;
--- a/dom/webidl/URLSearchParams.webidl
+++ b/dom/webidl/URLSearchParams.webidl
@@ -8,21 +8,21 @@
  *
  * To the extent possible under law, the editors have waived all copyright
  * and related or neighboring rights to this work. In addition, as of 17
  * February 2013, the editors have made this specification available under
  * the Open Web Foundation Agreement Version 1.0, which is available at
  * http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
  */
 
-[Constructor(optional ScalarValueString init = ""),
+[Constructor(optional USVString init = ""),
  Constructor(URLSearchParams init),
  Exposed=(Window,Worker)]
 interface URLSearchParams {
-  void append(ScalarValueString name, ScalarValueString value);
-  void delete(ScalarValueString name);
-  ScalarValueString? get(ScalarValueString name);
-  sequence<ScalarValueString> getAll(ScalarValueString name);
-  boolean has(ScalarValueString name);
-  void set(ScalarValueString name, ScalarValueString value);
-  // iterable<ScalarValueString, ScalarValueString>; - Bug 1085284
+  void append(USVString name, USVString value);
+  void delete(USVString name);
+  USVString? get(USVString name);
+  sequence<USVString> getAll(USVString name);
+  boolean has(USVString name);
+  void set(USVString name, USVString value);
+  // iterable<USVString, USVString>; - Bug 1085284
   stringifier;
 };
--- a/dom/webidl/URLUtils.webidl
+++ b/dom/webidl/URLUtils.webidl
@@ -12,41 +12,41 @@
  * the Open Web Foundation Agreement Version 1.0, which is available at
  * http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
  */
 
 [NoInterfaceObject,
  Exposed=(Window, Worker)]
 interface URLUtils {
   // Bug 824857: no support for stringifier attributes yet.
-  //  stringifier attribute ScalarValueString href;
+  //  stringifier attribute USVString href;
   [Throws, CrossOriginWritable=Location]
-           attribute ScalarValueString href;
+           attribute USVString href;
   [Throws]
-  readonly attribute ScalarValueString origin;
+  readonly attribute USVString origin;
 
   [Throws]
-           attribute ScalarValueString protocol;
+           attribute USVString protocol;
   [Throws]
-           attribute ScalarValueString username;
+           attribute USVString username;
   [Throws]
-           attribute ScalarValueString password;
+           attribute USVString password;
   [Throws]
-           attribute ScalarValueString host;
+           attribute USVString host;
   [Throws]
-           attribute ScalarValueString hostname;
+           attribute USVString hostname;
   [Throws]
-           attribute ScalarValueString port;
+           attribute USVString port;
   [Throws]
-           attribute ScalarValueString pathname;
+           attribute USVString pathname;
   [Throws]
-           attribute ScalarValueString search;
+           attribute USVString search;
 
   [Throws]
-           attribute ScalarValueString hash;
+           attribute USVString hash;
 
   // Bug 824857 should remove this.
   [Throws]
   stringifier;
 };
 
 [NoInterfaceObject,
  Exposed=(Window, Worker)]
--- a/dom/webidl/URLUtilsReadOnly.webidl
+++ b/dom/webidl/URLUtilsReadOnly.webidl
@@ -12,19 +12,19 @@
  * the Open Web Foundation Agreement Version 1.0, which is available at
  * http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
  */
 
 [NoInterfaceObject,
  Exposed=(Window, Worker)]
 interface URLUtilsReadOnly {
   stringifier;
-  readonly attribute ScalarValueString href;
+  readonly attribute USVString href;
 
-  readonly attribute ScalarValueString protocol;
-  readonly attribute ScalarValueString host;
-  readonly attribute ScalarValueString hostname;
-  readonly attribute ScalarValueString port;
-  readonly attribute ScalarValueString pathname;
-  readonly attribute ScalarValueString search;
-  readonly attribute ScalarValueString hash;
-  readonly attribute ScalarValueString origin;
+  readonly attribute USVString protocol;
+  readonly attribute USVString host;
+  readonly attribute USVString hostname;
+  readonly attribute USVString port;
+  readonly attribute USVString pathname;
+  readonly attribute USVString search;
+  readonly attribute USVString hash;
+  readonly attribute USVString origin;
 };
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -299,17 +299,17 @@ WorkerGlobalScope::GetPerformance()
   if (!mPerformance) {
     mPerformance = new Performance(mWorkerPrivate);
   }
 
   return mPerformance;
 }
 
 already_AddRefed<Promise>
-WorkerGlobalScope::Fetch(const RequestOrScalarValueString& aInput,
+WorkerGlobalScope::Fetch(const RequestOrUSVString& aInput,
                          const RequestInit& aInit, ErrorResult& aRv)
 {
   return FetchRequest(this, aInput, aInit, aRv);
 }
 
 DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
 : WorkerGlobalScope(aWorkerPrivate)
 {
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -12,17 +12,17 @@
 #include "mozilla/dom/RequestBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 class Console;
 class Function;
 class Promise;
-class RequestOrScalarValueString;
+class RequestOrUSVString;
 
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_WORKERS_NAMESPACE
 
 class ServiceWorkerClients;
 class WorkerPrivate;
@@ -121,17 +121,17 @@ public:
   IMPL_EVENT_HANDLER(close)
 
   void
   Dump(const Optional<nsAString>& aString) const;
 
   Performance* GetPerformance();
 
   already_AddRefed<Promise>
-  Fetch(const RequestOrScalarValueString& aInput, const RequestInit& aInit, ErrorResult& aRv);
+  Fetch(const RequestOrUSVString& aInput, const RequestInit& aInit, ErrorResult& aRv);
 };
 
 class DedicatedWorkerGlobalScope MOZ_FINAL : public WorkerGlobalScope
 {
   ~DedicatedWorkerGlobalScope() { }
 
 public:
   explicit DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate);
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -733,23 +733,23 @@ ShadowLayerForwarder::DeallocShmem(ipc::
     return;
   }
   mShadowManager->DeallocShmem(aShmem);
 }
 
 bool
 ShadowLayerForwarder::IPCOpen() const
 {
-  return mShadowManager->IPCOpen();
+  return HasShadowManager() && mShadowManager->IPCOpen();
 }
 
 bool
 ShadowLayerForwarder::IsSameProcess() const
 {
-  if (!mShadowManager->IPCOpen()) {
+  if (!HasShadowManager() || !mShadowManager->IPCOpen()) {
     return false;
   }
   return mShadowManager->OtherProcess() == kInvalidProcessHandle;
 }
 
 /**
   * We bail out when we have no shadow manager. That can happen when the
   * layer manager is created by the preallocated process.
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -239,19 +239,19 @@ nsFontCache::Flush()
         fm->Destroy();
         NS_RELEASE(fm);
     }
     mFontMetrics.Clear();
 }
 
 nsDeviceContext::nsDeviceContext()
     : mWidth(0), mHeight(0), mDepth(0),
-      mAppUnitsPerDevPixel(-1), mAppUnitsPerDevNotScaledPixel(-1),
+      mAppUnitsPerDevPixel(-1), mAppUnitsPerDevPixelAtUnitFullZoom(-1),
       mAppUnitsPerPhysicalInch(-1),
-      mPixelScale(1.0f), mPrintingScale(1.0f),
+      mFullZoom(1.0f), mPrintingScale(1.0f),
       mFontCache(nullptr)
 {
     MOZ_ASSERT(NS_IsMainThread(), "nsDeviceContext created off main thread");
 }
 
 // Note: we use a bare pointer for mFontCache so that nsFontCache
 // can be an incomplete type in nsDeviceContext.h.
 // Therefore we have to do all the refcounting by hand.
@@ -328,17 +328,17 @@ nsDeviceContext::SetDPI()
             break;
         }
 #endif
         default:
             NS_NOTREACHED("Unexpected printing surface type");
             break;
         }
 
-        mAppUnitsPerDevNotScaledPixel =
+        mAppUnitsPerDevPixelAtUnitFullZoom =
             NS_lround((AppUnitsPerCSSPixel() * 96) / dpi);
     } else {
         // A value of -1 means use the maximum of 96 and the system DPI.
         // A value of 0 means use the system DPI. A positive value is used as the DPI.
         // This sets the physical size of a device pixel and thus controls the
         // interpretation of physical units.
         int32_t prefDPI = Preferences::GetInt("layout.css.dpi", -1);
 
@@ -353,24 +353,24 @@ nsDeviceContext::SetDPI()
         } else {
             dpi = 96.0f;
         }
 
         CSSToLayoutDeviceScale scale = mWidget ? mWidget->GetDefaultScale()
                                                : CSSToLayoutDeviceScale(1.0);
         double devPixelsPerCSSPixel = scale.scale;
 
-        mAppUnitsPerDevNotScaledPixel =
+        mAppUnitsPerDevPixelAtUnitFullZoom =
             std::max(1, NS_lround(AppUnitsPerCSSPixel() / devPixelsPerCSSPixel));
     }
 
     NS_ASSERTION(dpi != -1.0, "no dpi set");
 
-    mAppUnitsPerPhysicalInch = NS_lround(dpi * mAppUnitsPerDevNotScaledPixel);
-    UpdateScaledAppUnits();
+    mAppUnitsPerPhysicalInch = NS_lround(dpi * mAppUnitsPerDevPixelAtUnitFullZoom);
+    UpdateAppUnitsForFullZoom();
 }
 
 nsresult
 nsDeviceContext::Init(nsIWidget *aWidget)
 {
     if (mScreenManager && mWidget == aWidget)
         return NS_OK;
 
@@ -717,38 +717,38 @@ nsDeviceContext::CalcPrintingSize()
         mHeight = NSToCoordRound(float(size.height) * AppUnitsPerPhysicalInch() / 72);
     } else {
         mWidth = NSToIntRound(size.width);
         mHeight = NSToIntRound(size.height);
     }
 }
 
 bool nsDeviceContext::CheckDPIChange() {
-    int32_t oldDevPixels = mAppUnitsPerDevNotScaledPixel;
+    int32_t oldDevPixels = mAppUnitsPerDevPixelAtUnitFullZoom;
     int32_t oldInches = mAppUnitsPerPhysicalInch;
 
     SetDPI();
 
-    return oldDevPixels != mAppUnitsPerDevNotScaledPixel ||
+    return oldDevPixels != mAppUnitsPerDevPixelAtUnitFullZoom ||
         oldInches != mAppUnitsPerPhysicalInch;
 }
 
 bool
-nsDeviceContext::SetPixelScale(float aScale)
+nsDeviceContext::SetFullZoom(float aScale)
 {
     if (aScale <= 0) {
-        NS_NOTREACHED("Invalid pixel scale value");
+        NS_NOTREACHED("Invalid full zoom value");
         return false;
     }
     int32_t oldAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
-    mPixelScale = aScale;
-    UpdateScaledAppUnits();
+    mFullZoom = aScale;
+    UpdateAppUnitsForFullZoom();
     return oldAppUnitsPerDevPixel != mAppUnitsPerDevPixel;
 }
 
 void
-nsDeviceContext::UpdateScaledAppUnits()
+nsDeviceContext::UpdateAppUnitsForFullZoom()
 {
     mAppUnitsPerDevPixel =
-        std::max(1, NSToIntRound(float(mAppUnitsPerDevNotScaledPixel) / mPixelScale));
-    // adjust mPixelScale to reflect appunit rounding
-    mPixelScale = float(mAppUnitsPerDevNotScaledPixel) / mAppUnitsPerDevPixel;
+        std::max(1, NSToIntRound(float(mAppUnitsPerDevPixelAtUnitFullZoom) / mFullZoom));
+    // adjust mFullZoom to reflect appunit rounding
+    mFullZoom = float(mAppUnitsPerDevPixelAtUnitFullZoom) / mAppUnitsPerDevPixel;
 }
--- a/gfx/src/nsDeviceContext.h
+++ b/gfx/src/nsDeviceContext.h
@@ -98,21 +98,21 @@ public:
 
     /**
      * Gets the number of app units in one CSS inch; this is
      * 96 times AppUnitsPerCSSPixel.
      */
     static int32_t AppUnitsPerCSSInch() { return mozilla::AppUnitsPerCSSInch(); }
 
     /**
-     * Get the unscaled ratio of app units to dev pixels; useful if something
-     * needs to be converted from to unscaled pixels
+     * Get the ratio of app units to dev pixels that would be used at unit
+     * (100%) full zoom.
      */
-    int32_t UnscaledAppUnitsPerDevPixel() const
-    { return mAppUnitsPerDevNotScaledPixel; }
+    int32_t AppUnitsPerDevPixelAtUnitFullZoom() const
+    { return mAppUnitsPerDevPixelAtUnitFullZoom; }
 
     /**
      * Get the nsFontMetrics that describe the properties of
      * an nsFont.
      * @param aFont font description to obtain metrics for
      * @param aLanguage the language of the document
      * @param aMetrics out parameter for font metrics
      * @param aUserFontSet user font set
@@ -229,50 +229,50 @@ public:
      * Check to see if the DPI has changed
      * @return whether there was actually a change in the DPI (whether
      *         AppUnitsPerDevPixel() or AppUnitsPerPhysicalInch()
      *         changed)
      */
     bool CheckDPIChange();
 
     /**
-     * Set the pixel scaling factor: all lengths are multiplied by this factor
+     * Set the full zoom factor: all lengths are multiplied by this factor
      * when we convert them to device pixels. Returns whether the ratio of
-     * app units to dev pixels changed because of the scale factor.
+     * app units to dev pixels changed because of the zoom factor.
      */
-    bool SetPixelScale(float aScale);
+    bool SetFullZoom(float aScale);
 
     /**
-     * Returns the pixel scaling factor (page zoom factor) applied.
+     * Returns the page full zoom factor applied.
      */
-    float GetPixelScale() const { return mPixelScale; }
+    float GetFullZoom() const { return mFullZoom; }
 
     /**
      * True if this device context was created for printing.
      */
     bool IsPrinterSurface();
 
 private:
     // Private destructor, to discourage deletion outside of Release():
     ~nsDeviceContext();
 
     void SetDPI();
     void ComputeClientRectUsingScreen(nsRect *outRect);
     void ComputeFullAreaUsingScreen(nsRect *outRect);
     void FindScreen(nsIScreen **outScreen);
     void CalcPrintingSize();
-    void UpdateScaledAppUnits();
+    void UpdateAppUnitsForFullZoom();
 
     nscoord  mWidth;
     nscoord  mHeight;
     uint32_t mDepth;
     int32_t  mAppUnitsPerDevPixel;
-    int32_t  mAppUnitsPerDevNotScaledPixel;
+    int32_t  mAppUnitsPerDevPixelAtUnitFullZoom;
     int32_t  mAppUnitsPerPhysicalInch;
-    float    mPixelScale;
+    float    mFullZoom;
     float    mPrintingScale;
 
     nsFontCache*                   mFontCache;
     nsCOMPtr<nsIWidget>            mWidget;
     nsCOMPtr<nsIScreenManager>     mScreenManager;
     nsCOMPtr<nsIDeviceContextSpec> mDeviceContextSpec;
     nsRefPtr<gfxASurface>          mPrintingSurface;
 #ifdef XP_MACOSX
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -576,16 +576,60 @@ function ArrayFill(value, start = 0, end
     for (; k < final; k++) {
         O[k] = value;
     }
 
     // Step 13.
     return O;
 }
 
+// Proposed for ES7:
+// https://github.com/domenic/Array.prototype.includes/blob/master/spec.md
+function ArrayIncludes(searchElement, fromIndex = 0) {
+    // Steps 1-2.
+    var O = ToObject(this);
+
+    // Steps 3-4.
+    var len = ToLength(O.length);
+
+    // Step 5.
+    if (len === 0)
+        return false;
+
+    // Steps 6-7.
+    var n = ToInteger(fromIndex);
+
+    // Step 8.
+    var k;
+    if (n >= 0) {
+        k = n;
+    }
+    // Step 9.
+    else {
+        // Step a.
+        k = len + n;
+        // Step b.
+        if (k < 0)
+            k = 0;
+    }
+
+    // Step 10.
+    while (k < len) {
+        // Steps a-c.
+        if (SameValueZero(searchElement, O[k]))
+            return true;
+
+        // Step d.
+        k++;
+    }
+
+    // Step 11.
+    return false;
+}
+
 #define ARRAY_ITERATOR_SLOT_ITERATED_OBJECT 0
 #define ARRAY_ITERATOR_SLOT_NEXT_INDEX 1
 #define ARRAY_ITERATOR_SLOT_ITEM_KIND 2
 
 #define ITEM_KIND_VALUE 0
 #define ITEM_KIND_KEY_AND_VALUE 1
 #define ITEM_KIND_KEY 2
 
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -98,16 +98,21 @@ function ToLength(v) {
 
     if (v <= 0)
         return 0;
 
     // Math.pow(2, 53) - 1 = 0x1fffffffffffff
     return std_Math_min(v, 0x1fffffffffffff);
 }
 
+// Spec: ECMAScript Draft, 6th edition Oct 14, 2014, 7.2.4.
+function SameValueZero(x, y) {
+    return x === y || (x !== x && y !== y);
+}
+
 /********** Testing code **********/
 
 #ifdef ENABLE_PARALLEL_JS
 
 /**
  * Internal debugging tool: checks that the given `mode` permits
  * sequential execution
  */
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -10245,22 +10245,20 @@ CodeGenerator::visitThrowUninitializedLe
 }
 
 bool
 CodeGenerator::visitDebugger(LDebugger *ins)
 {
     Register cx = ToRegister(ins->getTemp(0));
     Register temp = ToRegister(ins->getTemp(1));
 
-    // The check for cx->compartment()->isDebuggee() could be inlined, but the
-    // performance of |debugger;| does not matter.
     masm.loadJSContext(cx);
     masm.setupUnalignedABICall(1, temp);
     masm.passABIArg(cx);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, IsCompartmentDebuggee));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, GlobalHasLiveOnDebuggerStatement));
 
     Label bail;
     masm.branchIfTrueBool(ReturnReg, &bail);
     return bailoutFrom(&bail, ins->snapshot());
 }
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -413,22 +413,20 @@ CloseLiveIterator(JSContext *cx, const I
 static void
 HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe,
                    bool *overrecursed)
 {
     RootedScript script(cx, frame.script());
     jsbytecode *pc = frame.pc();
 
     if (cx->compartment()->isDebuggee()) {
-        // We need to bail when debug mode is active to observe the Debugger's
-        // exception unwinding handler if either a Debugger is observing all
-        // execution in the compartment, or it has a live onExceptionUnwind
-        // hook, or it has observed this frame (e.g., for onPop).
-        bool shouldBail = cx->compartment()->debugObservesAllExecution() ||
-                          Debugger::hasLiveOnExceptionUnwind(cx->global());
+        // We need to bail when we are the debuggee of a Debugger with a live
+        // onExceptionUnwind hook, or if a Debugger has observed this frame
+        // (e.g., for onPop).
+        bool shouldBail = Debugger::hasLiveHook(cx->global(), Debugger::OnExceptionUnwind);
         if (!shouldBail) {
             JitActivation *act = cx->mainThread().activation()->asJit();
             RematerializedFrame *rematFrame =
                 act->lookupRematerializedFrame(frame.frame().fp(), frame.frameNo());
             shouldBail = rematFrame && rematFrame->isDebuggee();
         }
 
         if (shouldBail) {
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1041,19 +1041,20 @@ OnDebuggerStatement(JSContext *cx, Basel
         return false;
 
       default:
         MOZ_CRASH("Invalid trap status");
     }
 }
 
 bool
-IsCompartmentDebuggee(JSContext *cx)
+GlobalHasLiveOnDebuggerStatement(JSContext *cx)
 {
-    return cx->compartment()->isDebuggee();
+    return cx->compartment()->isDebuggee() &&
+           Debugger::hasLiveHook(cx->global(), Debugger::OnDebuggerStatement);
 }
 
 bool
 PushBlockScope(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block)
 {
     return frame->pushBlock(cx, block);
 }
 
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -721,17 +721,17 @@ bool HeavyweightFunPrologue(JSContext *c
 
 bool NewArgumentsObject(JSContext *cx, BaselineFrame *frame, MutableHandleValue res);
 
 JSObject *InitRestParameter(JSContext *cx, uint32_t length, Value *rest, HandleObject templateObj,
                             HandleObject res);
 
 bool HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, bool *mustReturn);
 bool OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn);
-bool IsCompartmentDebuggee(JSContext *cx);
+bool GlobalHasLiveOnDebuggerStatement(JSContext *cx);
 
 bool EnterWith(JSContext *cx, BaselineFrame *frame, HandleValue val,
                Handle<StaticWithObject *> templ);
 bool LeaveWith(JSContext *cx, BaselineFrame *frame);
 
 bool PushBlockScope(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block);
 bool PopBlockScope(JSContext *cx, BaselineFrame *frame);
 bool DebugLeaveBlock(JSContext *cx, BaselineFrame *frame, jsbytecode *pc);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3222,16 +3222,20 @@ static const JSFunctionSpec array_method
     JS_SELF_HOSTED_FN("findIndex",   "ArrayFindIndex",   1,0),
     JS_SELF_HOSTED_FN("copyWithin",  "ArrayCopyWithin",  3,0),
 
     JS_SELF_HOSTED_FN("fill",        "ArrayFill",        3,0),
 
     JS_SELF_HOSTED_SYM_FN(iterator,  "ArrayValues",      0,0),
     JS_SELF_HOSTED_FN("entries",     "ArrayEntries",     0,0),
     JS_SELF_HOSTED_FN("keys",        "ArrayKeys",        0,0),
+
+    /* ES7 additions */
+    JS_SELF_HOSTED_FN("includes",    "ArrayIncludes",    2,0),
+
     JS_FS_END
 };
 
 static const JSFunctionSpec array_static_methods[] = {
     JS_FN("isArray",            array_isArray,      1,0),
     JS_SELF_HOSTED_FN("lastIndexOf", "ArrayStaticLastIndexOf", 2,0),
     JS_SELF_HOSTED_FN("indexOf",     "ArrayStaticIndexOf", 2,0),
     JS_SELF_HOSTED_FN("forEach",     "ArrayStaticForEach", 2,0),
--- a/js/src/tests/Makefile.in
+++ b/js/src/tests/Makefile.in
@@ -13,16 +13,17 @@ TEST_FILES = \
   js-test-driver-end.js \
   user.js \
   ecma/ \
   ecma_2/ \
   ecma_3/ \
   ecma_3_1/ \
   ecma_5/ \
   ecma_6/ \
+  ecma_7/ \
   Intl/ \
   js1_1/ \
   js1_2/ \
   js1_3/ \
   js1_4/ \
   js1_5/ \
   js1_6/ \
   js1_7/ \
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/Array/includes.js
@@ -0,0 +1,59 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+var BUGNUMBER = 1069063;
+var summary = "Implement Array.prototype.includes";
+
+print(BUGNUMBER + ": " + summary);
+
+assertEq(typeof [].includes, "function");
+assertEq([].includes.length, 1);
+
+assertTrue([1, 2, 3].includes(2));
+assertTrue([1,,2].includes(2));
+assertTrue([1, 2, 3].includes(2, 1));
+assertTrue([1, 2, 3].includes(2, -2));
+assertTrue([1, 2, 3].includes(2, -100));
+assertTrue([Object, Function, Array].includes(Function));
+assertTrue([-0].includes(0));
+assertTrue([NaN].includes(NaN));
+assertTrue([,].includes());
+assertTrue(staticIncludes("123", "2"));
+assertTrue(staticIncludes({length: 3, 1: 2}, 2));
+assertTrue(staticIncludes({length: 3, 1: 2, get 3(){throw ""}}, 2));
+assertTrue(staticIncludes({length: 3, get 1() {return 2}}, 2));
+assertTrue(staticIncludes({__proto__: {1: 2}, length: 3}, 2));
+assertTrue(staticIncludes(new Proxy([1], {get(){return 2}}), 2));
+
+assertFalse([1, 2, 3].includes("2"));
+assertFalse([1, 2, 3].includes(2, 2));
+assertFalse([1, 2, 3].includes(2, -1));
+assertFalse([undefined].includes(NaN));
+assertFalse([{}].includes({}));
+assertFalse(staticIncludes({length: 3, 1: 2}, 2, 2));
+assertFalse(staticIncludes({length: 3, get 0(){delete this[1]}, 1: 2}, 2));
+assertFalse(staticIncludes({length: -100, 0: 1}, 1));
+
+assertThrowsInstanceOf(() => staticIncludes(), TypeError);
+assertThrowsInstanceOf(() => staticIncludes(null), TypeError);
+assertThrowsInstanceOf(() => staticIncludes({get length(){throw TypeError()}}), TypeError);
+assertThrowsInstanceOf(() => staticIncludes({length: 3, get 1() {throw TypeError()}}, 2), TypeError);
+assertThrowsInstanceOf(() => staticIncludes({__proto__: {get 1() {throw TypeError()}}, length: 3}, 2), TypeError);
+assertThrowsInstanceOf(() => staticIncludes(new Proxy([1], {get(){throw TypeError()}})), TypeError);
+
+function assertTrue(v) {
+    assertEq(v, true);
+}
+
+function assertFalse(v) {
+    assertEq(v, false);
+}
+
+function staticIncludes(o, v, f) {
+    return [].includes.call(o, v, f);
+}
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
new file mode 100644
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/shell.js
@@ -0,0 +1,205 @@
+/* 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 (typeof assertThrowsInstanceOf === 'undefined') {
+    var assertThrowsInstanceOf = function assertThrowsInstanceOf(f, ctor, msg) {
+        var fullmsg;
+        try {
+            f();
+        } catch (exc) {
+            if (exc instanceof ctor)
+                return;
+            fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc;
+        }
+        if (fullmsg === undefined)
+            fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown";
+        if (msg !== undefined)
+            fullmsg += " - " + msg;
+        throw new Error(fullmsg);
+    };
+}
+
+if (typeof assertThrowsValue === 'undefined') {
+    var assertThrowsValue = function assertThrowsValue(f, val, msg) {
+        var fullmsg;
+        try {
+            f();
+        } catch (exc) {
+            if ((exc === val) === (val === val) && (val !== 0 || 1 / exc === 1 / val))
+                return;
+            fullmsg = "Assertion failed: expected exception " + val + ", got " + exc;
+        }
+        if (fullmsg === undefined)
+            fullmsg = "Assertion failed: expected exception " + val + ", no exception thrown";
+        if (msg !== undefined)
+            fullmsg += " - " + msg;
+        throw new Error(fullmsg);
+    };
+}
+
+if (typeof assertDeepEq === 'undefined') {
+    var assertDeepEq = (function(){
+        var call = Function.prototype.call,
+            Array_isArray = Array.isArray,
+            Map_ = Map,
+            Error_ = Error,
+            Map_has = call.bind(Map.prototype.has),
+            Map_get = call.bind(Map.prototype.get),
+            Map_set = call.bind(Map.prototype.set),
+            Object_toString = call.bind(Object.prototype.toString),
+            Function_toString = call.bind(Function.prototype.toString),
+            Object_getPrototypeOf = Object.getPrototypeOf,
+            Object_hasOwnProperty = call.bind(Object.prototype.hasOwnProperty),
+            Object_getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor,
+            Object_isExtensible = Object.isExtensible,
+            Object_getOwnPropertyNames = Object.getOwnPropertyNames,
+            uneval_ = uneval;
+
+        // Return true iff ES6 Type(v) isn't Object.
+        // Note that `typeof document.all === "undefined"`.
+        function isPrimitive(v) {
+            return (v === null ||
+                    v === undefined ||
+                    typeof v === "boolean" ||
+                    typeof v === "number" ||
+                    typeof v === "string" ||
+                    typeof v === "symbol");
+        }
+
+        function assertSameValue(a, b, msg) {
+            try {
+                assertEq(a, b);
+            } catch (exc) {
+                throw Error_(exc.message + (msg ? " " + msg : ""));
+            }
+        }
+
+        function assertSameClass(a, b, msg) {
+            var ac = Object_toString(a), bc = Object_toString(b);
+            assertSameValue(ac, bc, msg);
+            switch (ac) {
+            case "[object Function]":
+                assertSameValue(Function_toString(a), Function_toString(b), msg);
+            }
+        }
+
+        function at(prevmsg, segment) {
+            return prevmsg ? prevmsg + segment : "at _" + segment;
+        }
+
+        // Assert that the arguments a and b are thoroughly structurally equivalent.
+        //
+        // For the sake of speed, we cut a corner:
+        //        var x = {}, y = {}, ax = [x];
+        //        assertDeepEq([ax, x], [ax, y]);  // passes (?!)
+        //
+        // Technically this should fail, since the two object graphs are different.
+        // (The graph of [ax, y] contains one more object than the graph of [ax, x].)
+        //
+        // To get technically correct behavior, pass {strictEquivalence: true}.
+        // This is slower because we have to walk the entire graph, and Object.prototype
+        // is big.
+        //
+        return function assertDeepEq(a, b, options) {
+            var strictEquivalence = options ? options.strictEquivalence : false;
+
+            function assertSameProto(a, b, msg) {
+                check(Object_getPrototypeOf(a), Object_getPrototypeOf(b), at(msg, ".__proto__"));
+            }
+
+            function failPropList(na, nb, msg) {
+                throw Error_("got own properties " + uneval_(na) + ", expected " + uneval_(nb) +
+                             (msg ? " " + msg : ""));
+            }
+
+            function assertSameProps(a, b, msg) {
+                var na = Object_getOwnPropertyNames(a),
+                    nb = Object_getOwnPropertyNames(b);
+                if (na.length !== nb.length)
+                    failPropList(na, nb, msg);
+
+                // Ignore differences in whether Array elements are stored densely.
+                if (Array_isArray(a)) {
+                    na.sort();
+                    nb.sort();
+                }
+
+                for (var i = 0; i < na.length; i++) {
+                    var name = na[i];
+                    if (name !== nb[i])
+                        failPropList(na, nb, msg);
+                    var da = Object_getOwnPropertyDescriptor(a, name),
+                        db = Object_getOwnPropertyDescriptor(b, name);
+                    var pmsg = at(msg, /^[_$A-Za-z0-9]+$/.test(name)
+                                       ? /0|[1-9][0-9]*/.test(name) ? "[" + name + "]" : "." + name
+                                       : "[" + uneval_(name) + "]");
+                    assertSameValue(da.configurable, db.configurable, at(pmsg, ".[[Configurable]]"));
+                    assertSameValue(da.enumerable, db.enumerable, at(pmsg, ".[[Enumerable]]"));
+                    if (Object_hasOwnProperty(da, "value")) {
+                        if (!Object_hasOwnProperty(db, "value"))
+                            throw Error_("got data property, expected accessor property" + pmsg);
+                        check(da.value, db.value, pmsg);
+                    } else {
+                        if (Object_hasOwnProperty(db, "value"))
+                            throw Error_("got accessor property, expected data property" + pmsg);
+                        check(da.get, db.get, at(pmsg, ".[[Get]]"));
+                        check(da.set, db.set, at(pmsg, ".[[Set]]"));
+                    }
+                }
+            };
+
+            var ab = Map_();
+            var bpath = Map_();
+
+            function check(a, b, path) {
+                if (typeof a === "symbol") {
+                    // Symbols are primitives, but they have identity.
+                    // Symbol("x") !== Symbol("x") but
+                    // assertDeepEq(Symbol("x"), Symbol("x")) should pass.
+                    if (typeof b !== "symbol") {
+                        throw Error_("got " + uneval_(a) + ", expected " + uneval_(b) + " " + path);
+                    } else if (uneval_(a) !== uneval_(b)) {
+                        // We lamely use uneval_ to distinguish well-known symbols
+                        // from user-created symbols. The standard doesn't offer
+                        // a convenient way to do it.
+                        throw Error_("got " + uneval_(a) + ", expected " + uneval_(b) + " " + path);
+                    } else if (Map_has(ab, a)) {
+                        assertSameValue(Map_get(ab, a), b, path);
+                    } else if (Map_has(bpath, b)) {
+                        var bPrevPath = Map_get(bpath, b) || "_";
+                        throw Error_("got distinct symbols " + at(path, "") + " and " +
+                                     at(bPrevPath, "") + ", expected the same symbol both places");
+                    } else {
+                        Map_set(ab, a, b);
+                        Map_set(bpath, b, path);
+                    }
+                } else if (isPrimitive(a)) {
+                    assertSameValue(a, b, path);
+                } else if (isPrimitive(b)) {
+                    throw Error_("got " + Object_toString(a) + ", expected " + uneval_(b) + " " + path);
+                } else if (Map_has(ab, a)) {
+                    assertSameValue(Map_get(ab, a), b, path);
+                } else if (Map_has(bpath, b)) {
+                    var bPrevPath = Map_get(bpath, b) || "_";
+                    throw Error_("got distinct objects " + at(path, "") + " and " + at(bPrevPath, "") +
+                                 ", expected the same object both places");
+                } else {
+                    Map_set(ab, a, b);
+                    Map_set(bpath, b, path);
+                    if (a !== b || strictEquivalence) {
+                        assertSameClass(a, b, path);
+                        assertSameProto(a, b, path);
+                        assertSameProps(a, b, path);
+                        assertSameValue(Object_isExtensible(a),
+                                        Object_isExtensible(b),
+                                        at(path, ".[[Extensible]]"));
+                    }
+                }
+            }
+
+            check(a, b, "");
+        };
+    })();
+}
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -463,22 +463,22 @@ Debugger::getScriptFrameWithIter(JSConte
         if (!ensureExecutionObservabilityOfFrame(cx, frame))
             return false;
     }
     vp.setObject(*p->value());
     return true;
 }
 
 /* static */ bool
-Debugger::hasLiveOnExceptionUnwind(GlobalObject *global)
+Debugger::hasLiveHook(GlobalObject *global, Hook which)
 {
     if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
         for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) {
             Debugger *dbg = *p;
-            if (dbg->enabled && dbg->getHook(OnExceptionUnwind))
+            if (dbg->enabled && dbg->getHook(which))
                 return true;
         }
     }
     return false;
 }
 
 JSObject *
 Debugger::getHook(Hook hook) const
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -576,17 +576,17 @@ class Debugger : private mozilla::Linked
     static inline void onNewScript(JSContext *cx, HandleScript script, GlobalObject *compileAndGoGlobal);
     static inline void onNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global);
     static inline bool onLogAllocationSite(JSContext *cx, HandleSavedFrame frame, int64_t when);
     static JSTrapStatus onTrap(JSContext *cx, MutableHandleValue vp);
     static JSTrapStatus onSingleStep(JSContext *cx, MutableHandleValue vp);
     static bool handleBaselineOsr(JSContext *cx, InterpreterFrame *from, jit::BaselineFrame *to);
     static bool handleIonBailout(JSContext *cx, jit::RematerializedFrame *from, jit::BaselineFrame *to);
     static void propagateForcedReturn(JSContext *cx, AbstractFramePtr frame, HandleValue rval);
-    static bool hasLiveOnExceptionUnwind(GlobalObject *global);
+    static bool hasLiveHook(GlobalObject *global, Hook which);
 
     /************************************* Functions for use by Debugger.cpp. */
 
     inline bool observesEnterFrame() const;
     inline bool observesNewScript() const;
     inline bool observesNewGlobalObject() const;
     inline bool observesGlobal(GlobalObject *global) const;
     bool observesFrame(AbstractFramePtr frame) const;
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -164,17 +164,17 @@ https://bugzilla.mozilla.org/show_bug.cg
                                       the JS engine filters it out of getOwnPropertyNames */
     ["constructor", "toSource", "toString", "toLocaleString", "valueOf", "watch",
      "unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
      "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__"];
   gPrototypeProperties['Array'] =
     ["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push",
       "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf",
       "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
-      "findIndex", "copyWithin", "fill", kIteratorSymbol, "entries", "keys", "constructor"];
+      "findIndex", "copyWithin", "fill", "includes", kIteratorSymbol, "entries", "keys", "constructor"];
   if (isNightlyBuild) {
     let pjsMethods = ['mapPar', 'reducePar', 'scanPar', 'scatterPar', 'filterPar'];
     gPrototypeProperties['Array'] = gPrototypeProperties['Array'].concat(pjsMethods);
   }
   for (var c of typedArrayClasses) {
     gPrototypeProperties[c] = ["constructor", "BYTES_PER_ELEMENT"];
   }
   gPrototypeProperties['TypedArray'] =
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -528,16 +528,17 @@ nsDisplayListBuilder::AddAnimationsAndTr
 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
     Mode aMode, bool aBuildCaret)
     : mReferenceFrame(aReferenceFrame),
       mIgnoreScrollFrame(nullptr),
       mLayerEventRegions(nullptr),
       mCurrentTableItem(nullptr),
       mCurrentFrame(aReferenceFrame),
       mCurrentReferenceFrame(aReferenceFrame),
+      mCurrentAnimatedGeometryRoot(aReferenceFrame),
       mWillChangeBudgetCalculated(false),
       mDirtyRect(-1,-1,-1,-1),
       mGlassDisplayItem(nullptr),
       mMode(aMode),
       mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
       mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
       mCurrentScrollbarFlags(0),
       mBuildCaret(aBuildCaret),
@@ -1083,16 +1084,114 @@ nsDisplayListBuilder::FindReferenceFrame
     }
   }
   if (aOffset) {
     *aOffset = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
   }
   return mReferenceFrame;
 }
 
+// Sticky frames are active if their nearest scrollable frame is also active.
+static bool
+IsStickyFrameActive(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aParent)
+{
+  MOZ_ASSERT(aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY);
+
+  // Find the nearest scrollframe.
+  nsIFrame* cursor = aFrame;
+  nsIFrame* parent = aParent;
+  while (parent->GetType() != nsGkAtoms::scrollFrame) {
+    cursor = parent;
+    if ((parent = nsLayoutUtils::GetCrossDocParentFrame(cursor)) == nullptr) {
+      return false;
+    }
+  }
+
+  nsIScrollableFrame* sf = do_QueryFrame(parent);
+  return sf->IsScrollingActive(aBuilder) && sf->GetScrolledFrame() == cursor;
+}
+
+bool
+nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent)
+{
+  if (nsLayoutUtils::IsPopup(aFrame))
+    return true;
+  if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(aFrame))
+    return true;
+  if (!aFrame->GetParent() &&
+      nsLayoutUtils::ViewportHasDisplayPort(aFrame->PresContext())) {
+    // Viewport frames in a display port need to be animated geometry roots
+    // for background-attachment:fixed elements.
+    return true;
+  }
+
+  nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
+  if (!parent)
+    return true;
+
+  nsIAtom* parentType = parent->GetType();
+  // Treat the slider thumb as being as an active scrolled root when it wants
+  // its own layer so that it can move without repainting.
+  if (parentType == nsGkAtoms::sliderFrame && nsLayoutUtils::IsScrollbarThumbLayerized(aFrame)) {
+    return true;
+  }
+
+  if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY &&
+      IsStickyFrameActive(this, aFrame, parent))
+  {
+    return true;
+  }
+
+  if (parentType == nsGkAtoms::scrollFrame) {
+    nsIScrollableFrame* sf = do_QueryFrame(parent);
+    if (sf->IsScrollingActive(this) && sf->GetScrolledFrame() == aFrame) {
+      return true;
+    }
+  }
+
+  // Fixed-pos frames are parented by the viewport frame, which has no parent.
+  if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) {
+    return true;
+  }
+
+  if (aParent) {
+    *aParent = parent;
+  }
+  return false;
+}
+
+static nsIFrame*
+ComputeAnimatedGeometryRootFor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+                               const nsIFrame* aStopAtAncestor = nullptr)
+{
+  nsIFrame* cursor = aFrame;
+  while (cursor != aStopAtAncestor) {
+    nsIFrame* next;
+    if (aBuilder->IsAnimatedGeometryRoot(cursor, &next))
+      return cursor;
+    cursor = next;
+  }
+  return cursor;
+}
+
+nsIFrame*
+nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame, const nsIFrame* aStopAtAncestor)
+{
+  if (aFrame == mCurrentFrame) {
+    return mCurrentAnimatedGeometryRoot;
+  }
+  return ComputeAnimatedGeometryRootFor(this, aFrame, aStopAtAncestor);
+}
+
+void
+nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
+{
+  mCurrentAnimatedGeometryRoot = ComputeAnimatedGeometryRootFor(this, const_cast<nsIFrame *>(mCurrentFrame));
+}
+
 void
 nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame* aFrame)
 {
   if (!IsForPainting() || IsInSubdocument() || IsInTransform()) {
     return;
   }
 
   // We do some basic visibility checking on the frame's border box here.
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -204,17 +204,29 @@ public:
   nsISelection* GetBoundingSelection() { return mBoundingSelection; }
 
   /**
    * @return the root of given frame's (sub)tree, whose origin
    * establishes the coordinate system for the child display items.
    */
   const nsIFrame* FindReferenceFrameFor(const nsIFrame *aFrame,
                                         nsPoint* aOffset = nullptr);
-  
+
+  /**
+   * Returns whether a frame acts as an animated geometry root, optionally
+   * returning the next ancestor to check.
+   */
+  bool IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent = nullptr);
+
+  /**
+   * Returns the nearest ancestor frame to aFrame that is considered to have
+   * (or will have) animated geometry. This can return aFrame.
+   */
+  nsIFrame* FindAnimatedGeometryRootFor(nsIFrame* aFrame, const nsIFrame* aStopAtAncestor = nullptr);
+
   /**
    * @return the root of the display list's frame (sub)tree, whose origin
    * establishes the coordinate system for the display list
    */
   nsIFrame* RootReferenceFrame() 
   {
     return mReferenceFrame;
   }
@@ -306,16 +318,20 @@ public:
   /**
    * Get dirty rect relative to current frame (the frame that we're calling
    * BuildDisplayList on right now).
    */
   const nsRect& GetDirtyRect() { return mDirtyRect; }
   const nsIFrame* GetCurrentFrame() { return mCurrentFrame; }
   const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; }
   const nsPoint& GetCurrentFrameOffsetToReferenceFrame() { return mCurrentOffsetToReferenceFrame; }
+  const nsIFrame* GetCurrentAnimatedGeometryRoot() {
+    return mCurrentAnimatedGeometryRoot;
+  }
+  void RecomputeCurrentAnimatedGeometryRoot();
 
   /**
    * Returns true if merging and flattening of display lists should be
    * performed while computing visibility.
    */
   bool AllowMergingAndFlattening() { return mAllowMergingAndFlattening; }
   void SetAllowMergingAndFlattening(bool aAllow) { mAllowMergingAndFlattening = aAllow; }
 
@@ -534,56 +550,74 @@ public:
   class AutoBuildingDisplayList {
   public:
     AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder,
                             nsIFrame* aForChild,
                             const nsRect& aDirtyRect, bool aIsRoot)
       : mBuilder(aBuilder),
         mPrevFrame(aBuilder->mCurrentFrame),
         mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame),
+        mPrevAnimatedGeometryRoot(mBuilder->mCurrentAnimatedGeometryRoot),
         mPrevLayerEventRegions(aBuilder->mLayerEventRegions),
         mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame),
         mPrevDirtyRect(aBuilder->mDirtyRect),
         mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext),
         mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler)
     {
       if (aForChild->IsTransformed()) {
         aBuilder->mCurrentOffsetToReferenceFrame = nsPoint();
         aBuilder->mCurrentReferenceFrame = aForChild;
       } else if (aBuilder->mCurrentFrame == aForChild->GetParent()) {
         aBuilder->mCurrentOffsetToReferenceFrame += aForChild->GetPosition();
       } else {
         aBuilder->mCurrentReferenceFrame =
           aBuilder->FindReferenceFrameFor(aForChild,
               &aBuilder->mCurrentOffsetToReferenceFrame);
       }
+      if (aBuilder->mCurrentFrame == aForChild->GetParent()) {
+        if (aBuilder->IsAnimatedGeometryRoot(aForChild)) {
+          aBuilder->mCurrentAnimatedGeometryRoot = aForChild;
+        }
+      } else {
+        // Stop at the previous animated geometry root to help cases that
+        // aren't immediate descendents.
+        aBuilder->mCurrentAnimatedGeometryRoot =
+          aBuilder->FindAnimatedGeometryRootFor(aForChild, aBuilder->mCurrentAnimatedGeometryRoot);
+      }
       aBuilder->mCurrentFrame = aForChild;
       aBuilder->mDirtyRect = aDirtyRect;
       aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
     }
     void SetDirtyRect(const nsRect& aRect) {
       mBuilder->mDirtyRect = aRect;
     }
     void SetReferenceFrameAndCurrentOffset(const nsIFrame* aFrame, const nsPoint& aOffset) {
       mBuilder->mCurrentReferenceFrame = aFrame;
       mBuilder->mCurrentOffsetToReferenceFrame = aOffset;
     }
+    // Return the previous frame's animated geometry root, whether or not the
+    // current frame is an immediate descendant.
+    const nsIFrame* GetPrevAnimatedGeometryRoot() const {
+      return mPrevAnimatedGeometryRoot;
+    }
     ~AutoBuildingDisplayList() {
       mBuilder->mCurrentFrame = mPrevFrame;
       mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame;
       mBuilder->mLayerEventRegions = mPrevLayerEventRegions;
       mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset;
       mBuilder->mDirtyRect = mPrevDirtyRect;
       mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext;
       mBuilder->mAncestorHasTouchEventHandler = mPrevAncestorHasTouchEventHandler;
+      mBuilder->mCurrentAnimatedGeometryRoot = mPrevAnimatedGeometryRoot;
     }
   private:
     nsDisplayListBuilder* mBuilder;
     const nsIFrame*       mPrevFrame;
     const nsIFrame*       mPrevReferenceFrame;
+    nsIFrame*             mPrevAnimatedGeometryRoot;
     nsDisplayLayerEventRegions* mPrevLayerEventRegions;
     nsPoint               mPrevOffset;
     nsRect                mPrevDirtyRect;
     bool                  mPrevIsAtRootOfPseudoStackingContext;
     bool                  mPrevAncestorHasTouchEventHandler;
   };
 
   /**
@@ -790,16 +824,18 @@ private:
   DisplayListClipState           mClipState;
   // mCurrentFrame is the frame that we're currently calling (or about to call)
   // BuildDisplayList on.
   const nsIFrame*                mCurrentFrame;
   // The reference frame for mCurrentFrame.
   const nsIFrame*                mCurrentReferenceFrame;
   // The offset from mCurrentFrame to mCurrentReferenceFrame.
   nsPoint                        mCurrentOffsetToReferenceFrame;
+  // The animated geometry root for mCurrentFrame.
+  nsIFrame*                      mCurrentAnimatedGeometryRoot;
   // will-change budget tracker
   nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget>
                                  mWillChangeBudget;
   // Assert that we never check the budget before its fully calculated.
   mutable mozilla::DebugOnly<bool> mWillChangeBudgetCalculated;
   // Relative to mCurrentFrame.
   nsRect                         mDirtyRect;
   nsRegion                       mWindowExcludeGlassRegion;
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -661,17 +661,18 @@ nsDocumentViewer::InitPresentationStuff(
 
     mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
   }
 
   mPresShell->BeginObservingDocument();
 
   // Initialize our view manager
   int32_t p2a = mPresContext->AppUnitsPerDevPixel();
-  MOZ_ASSERT(p2a == mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel());
+  MOZ_ASSERT(p2a ==
+             mPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
   nscoord width = p2a * mBounds.width;
   nscoord height = p2a * mBounds.height;
 
   mViewManager->SetWindowDimensions(width, height);
   mPresContext->SetTextZoom(mTextZoom);
   mPresContext->SetFullZoom(mPageZoom);
   mPresContext->SetBaseMinFontSize(mMinFontSize);
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1713,76 +1713,28 @@ NS_DECLARE_FRAME_PROPERTY(ScrollbarThumb
 
 /* static */ void
 nsLayoutUtils::SetScrollbarThumbLayerization(nsIFrame* aThumbFrame, bool aLayerize)
 {
   aThumbFrame->Properties().Set(ScrollbarThumbLayerized(),
     reinterpret_cast<void*>(intptr_t(aLayerize)));
 }
 
-static bool
-IsScrollbarThumbLayerized(nsIFrame* aThumbFrame)
+bool
+nsLayoutUtils::IsScrollbarThumbLayerized(nsIFrame* aThumbFrame)
 {
   return reinterpret_cast<intptr_t>(aThumbFrame->Properties().Get(ScrollbarThumbLayerized()));
 }
 
 nsIFrame*
 nsLayoutUtils::GetAnimatedGeometryRootForFrame(nsDisplayListBuilder* aBuilder,
                                                nsIFrame* aFrame,
                                                const nsIFrame* aStopAtAncestor)
 {
-  nsIFrame* f = aFrame;
-  nsIFrame* stickyFrame = nullptr;
-  while (f != aStopAtAncestor) {
-    if (nsLayoutUtils::IsPopup(f))
-      break;
-    if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(f))
-      break;
-    if (!f->GetParent() &&
-        nsLayoutUtils::ViewportHasDisplayPort(f->PresContext())) {
-      // Viewport frames in a display port need to be animated geometry roots
-      // for background-attachment:fixed elements.
-      break;
-    }
-    nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(f);
-    if (!parent)
-      break;
-    nsIAtom* parentType = parent->GetType();
-    // Treat the slider thumb as being as an active scrolled root when it wants
-    // its own layer so that it can move without repainting.
-    if (parentType == nsGkAtoms::sliderFrame && IsScrollbarThumbLayerized(f)) {
-      break;
-    }
-    // Sticky frames are active if their nearest scrollable frame
-    // is also active, just keep a record of sticky frames that we
-    // encounter for now.
-    if (f->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY &&
-        !stickyFrame) {
-      stickyFrame = f;
-    }
-    if (parentType == nsGkAtoms::scrollFrame) {
-      nsIScrollableFrame* sf = do_QueryFrame(parent);
-      if (sf->IsScrollingActive(aBuilder) && sf->GetScrolledFrame() == f) {
-        // If we found a sticky frame inside this active scroll frame,
-        // then use that. Otherwise use the scroll frame.
-        if (stickyFrame) {
-          return stickyFrame;
-        }
-        return f;
-      } else {
-        stickyFrame = nullptr;
-      }
-    }
-    // Fixed-pos frames are parented by the viewport frame, which has no parent
-    if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(f)) {
-      return f;
-    }
-    f = parent;
-  }
-  return f;
+  return aBuilder->FindAnimatedGeometryRootFor(aFrame, aStopAtAncestor);
 }
 
 nsIFrame*
 nsLayoutUtils::GetAnimatedGeometryRootFor(nsDisplayItem* aItem,
                                           nsDisplayListBuilder* aBuilder,
                                           LayerManager* aManager)
 {
   nsIFrame* f = aItem->Frame();
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -508,16 +508,22 @@ public:
 
   /**
    * Store whether aThumbFrame wants its own layer. This sets a property on
    * the frame.
    */
   static void SetScrollbarThumbLayerization(nsIFrame* aThumbFrame, bool aLayerize);
 
   /**
+   * Returns whether aThumbFrame wants its own layer due to having called
+   * SetScrollbarThumbLayerization.
+   */
+  static bool IsScrollbarThumbLayerized(nsIFrame* aThumbFrame);
+
+  /**
    * Finds the nearest ancestor frame to aItem that is considered to have (or
    * will have) "animated geometry". For example the scrolled frames of
    * scrollframes which are actively being scrolled fall into this category.
    * Frames with certain CSS properties that are being animated (e.g.
    * 'left'/'top' etc) are also placed in this category.
    * Frames with different active geometry roots are in different PaintedLayers,
    * so that we can animate the geometry root by changing its transform (either
    * on the main thread or in the compositor).
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -924,17 +924,17 @@ nsPresContext::UpdateAfterPreferencesCha
 nsresult
 nsPresContext::Init(nsDeviceContext* aDeviceContext)
 {
   NS_ASSERTION(!mInitialized, "attempt to reinit pres context");
   NS_ENSURE_ARG(aDeviceContext);
 
   mDeviceContext = aDeviceContext;
 
-  if (mDeviceContext->SetPixelScale(mFullZoom))
+  if (mDeviceContext->SetFullZoom(mFullZoom))
     mDeviceContext->FlushFontCache();
   mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
 
   mEventManager = new mozilla::EventStateManager();
 
   mTransitionManager = new nsTransitionManager(this);
 
   mAnimationManager = new nsAnimationManager(this);
@@ -1442,17 +1442,17 @@ nsPresContext::SetFullZoom(float aZoom)
   }
 
   // Re-fetch the view manager's window dimensions in case there's a deferred
   // resize which hasn't affected our mVisibleArea yet
   nscoord oldWidthAppUnits, oldHeightAppUnits;
   mShell->GetViewManager()->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
   float oldWidthDevPixels = oldWidthAppUnits / float(mCurAppUnitsPerDevPixel);
   float oldHeightDevPixels = oldHeightAppUnits / float(mCurAppUnitsPerDevPixel);
-  mDeviceContext->SetPixelScale(aZoom);
+  mDeviceContext->SetFullZoom(aZoom);
 
   NS_ASSERTION(!mSupressResizeReflow, "two zooms happening at the same time? impossible!");
   mSupressResizeReflow = true;
 
   mFullZoom = aZoom;
   mShell->GetViewManager()->
     SetWindowDimensions(NSToCoordRound(oldWidthDevPixels * AppUnitsPerDevPixel()),
                         NSToCoordRound(oldHeightDevPixels * AppUnitsPerDevPixel()));
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2390,16 +2390,31 @@ nsIFrame::BuildDisplayListForChild(nsDis
     }
 
     child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
 
     if (!pseudoStackingContext) {
       // THIS IS THE COMMON CASE.
       // Not a pseudo or real stacking context. Do the simple thing and
       // return early.
+
+      if (aBuilder->IsBuildingLayerEventRegions()) {
+        MOZ_ASSERT(buildingForChild.GetPrevAnimatedGeometryRoot() ==
+                   aBuilder->FindAnimatedGeometryRootFor(child->GetParent()));
+
+        // If this frame has a different animated geometry root than its parent,
+        // make sure we accumulate event regions for its layer.
+        nsIFrame *animatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(child);
+        if (animatedGeometryRoot != buildingForChild.GetPrevAnimatedGeometryRoot()) {
+          nsDisplayLayerEventRegions* eventRegions =
+            new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
+          aBuilder->SetLayerEventRegions(eventRegions);
+        }
+      }
+
       nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
       if (eventRegions) {
         eventRegions->AddFrame(aBuilder, child);
       }
       child->BuildDisplayList(aBuilder, dirty, aLists);
       aBuilder->DisplayCaret(child, dirty, aLists.Content());
 #ifdef DEBUG
       DisplayDebugBorders(aBuilder, child, aLists);
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2874,16 +2874,18 @@ ScrollFrameHelper::BuildDisplayList(nsDi
   // had dirty rects saved for them by their parent frames calling
   // MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our
   // dirty rect here.
   nsRect dirtyRect = aDirtyRect.Intersect(mScrollPort);
 
   nsRect displayPort;
   bool usingDisplayport = false;
   if (aBuilder->IsPaintingToWindow()) {
+    bool wasUsingDisplayPort = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), nullptr);
+
     if (!mIsRoot) {
       // For a non-root scroll frame, override the value of the display port
       // base rect, and possibly create a display port if there isn't one
       // already. For root scroll frame, nsLayoutUtils::PaintFrame or
       // nsSubDocumentFrame::BuildDisplayList takes care of this.
       nsRect displayportBase = dirtyRect;
       usingDisplayport = nsLayoutUtils::GetOrMaybeCreateDisplayPort(
           *aBuilder, mOuter, displayportBase, &displayPort);
@@ -2898,16 +2900,22 @@ ScrollFrameHelper::BuildDisplayList(nsDi
       // If we have low-res painting enabled we should check the critical displayport too
       nsRect critDp;
       nsLayoutUtils::GetCriticalDisplayPort(mOuter->GetContent(), &critDp);
     }
 
     // Override the dirty rectangle if the displayport has been set.
     if (usingDisplayport) {
       dirtyRect = displayPort;
+
+      // The cached animated geometry root for the display builder is out of
+      // date if we just introduced a new animated geometry root.
+      if (!wasUsingDisplayPort) {
+        aBuilder->RecomputeCurrentAnimatedGeometryRoot();
+      }
     }
   }
 
   // Now display the scrollbars and scrollcorner. These parts are drawn
   // in the border-background layer, on top of our own background and
   // borders and underneath borders and backgrounds of later elements
   // in the tree.
   // Note that this does not apply for overlay scrollbars; those are drawn
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -3384,30 +3384,31 @@ nsRuleNode::SetFont(nsPresContext* aPres
   nsFont systemFont = *defaultVariableFont;
   const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
   if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
     gfxFontStyle fontStyle;
     LookAndFeel::FontID fontID =
       (LookAndFeel::FontID)systemFontValue->GetIntValue();
     float devPerCSS =
       (float)nsPresContext::AppUnitsPerCSSPixel() /
-      aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
+      aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
     nsAutoString systemFontName;
     if (LookAndFeel::GetFont(fontID, systemFontName, fontStyle, devPerCSS)) {
       systemFontName.Trim("\"'");
       systemFont.fontlist = FontFamilyList(systemFontName, eUnquotedName);
       systemFont.fontlist.SetDefaultFontType(eFamily_none);
       systemFont.style = fontStyle.style;
       systemFont.systemFont = fontStyle.systemFont;
       systemFont.weight = fontStyle.weight;
       systemFont.stretch = fontStyle.stretch;
       systemFont.decorations = NS_FONT_DECORATION_NONE;
-      systemFont.size = NSFloatPixelsToAppUnits(fontStyle.size,
-                                                aPresContext->DeviceContext()->
-                                                UnscaledAppUnitsPerDevPixel());
+      systemFont.size =
+        NSFloatPixelsToAppUnits(fontStyle.size,
+                                aPresContext->DeviceContext()->
+                                  AppUnitsPerDevPixelAtUnitFullZoom());
       //systemFont.langGroup = fontStyle.langGroup;
       systemFont.sizeAdjust = fontStyle.sizeAdjust;
 
 #ifdef XP_WIN
       // XXXldb This platform-specific stuff should be in the
       // LookAndFeel implementation, not here.
       // XXXzw Should we even still *have* this code?  It looks to be making
       // old, probably obsolete assumptions.
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -1295,30 +1295,30 @@ nsMenuPopupFrame::SetPopupPosition(nsIFr
       // the next time SetPopupPosition is called.
       mScreenXPos = presContext->AppUnitsToIntCSSPixels(screenPoint.x - margin.left);
       mScreenYPos = presContext->AppUnitsToIntCSSPixels(screenPoint.y - margin.top);
     }
   }
   else {
     // the popup is positioned at a screen coordinate.
     // first convert the screen position in mScreenXPos and mScreenYPos from
-    // CSS pixels into device pixels, ignoring any scaling as mScreenXPos and
-    // mScreenYPos are unscaled screen coordinates.
-    int32_t factor = devContext->UnscaledAppUnitsPerDevPixel();
+    // CSS pixels into device pixels, ignoring any zoom as mScreenXPos and
+    // mScreenYPos are unzoomed screen coordinates.
+    int32_t factor = devContext->AppUnitsPerDevPixelAtUnitFullZoom();
 
     // context menus should be offset by two pixels so that they don't appear
     // directly where the cursor is. Otherwise, it is too easy to have the
     // context menu close up again.
     if (mAdjustOffsetForContextMenu) {
       int32_t offsetForContextMenuDev =
         nsPresContext::CSSPixelsToAppUnits(CONTEXT_MENU_OFFSET_PIXELS) / factor;
       offsetForContextMenu = presContext->DevPixelsToAppUnits(offsetForContextMenuDev);
     }
 
-    // next, convert into app units accounting for the scaling
+    // next, convert into app units accounting for the zoom
     screenPoint.x = presContext->DevPixelsToAppUnits(
                       nsPresContext::CSSPixelsToAppUnits(mScreenXPos) / factor);
     screenPoint.y = presContext->DevPixelsToAppUnits(
                       nsPresContext::CSSPixelsToAppUnits(mScreenYPos) / factor);
     anchorRect = nsRect(screenPoint, nsSize(0, 0));
 
     // add the margins on the popup
     screenPoint.MoveBy(margin.left + offsetForContextMenu,
--- a/media/libstagefright/binding/Box.cpp
+++ b/media/libstagefright/binding/Box.cpp
@@ -54,36 +54,43 @@ Box::Box(BoxContext* aContext, uint64_t 
     }
     size = BigEndian::readUint64(bigLength);
     mChildOffset = bigLengthRange.mEnd;
   } else {
     mChildOffset = headerRange.mEnd;
   }
 
   MediaByteRange boxRange(aOffset, aOffset + size);
-  if (mChildOffset >= boxRange.mEnd ||
+  if (mChildOffset > boxRange.mEnd ||
       (mParent && !mParent->mRange.Contains(boxRange)) ||
       !byteRange->Contains(boxRange)) {
     return;
   }
-  mRange = MediaByteRange(aOffset, aOffset + size);
+  mRange = boxRange;
   mType = BigEndian::readUint32(&header[4]);
 }
 
+Box::Box()
+  : mContext(nullptr), mType(0)
+{}
+
 Box
 Box::Next() const
 {
   MOZ_ASSERT(IsAvailable());
   return Box(mContext, mRange.mEnd, mParent);
 }
 
 Box
 Box::FirstChild() const
 {
   MOZ_ASSERT(IsAvailable());
+  if (mChildOffset == mRange.mEnd) {
+    return Box();
+  }
   return Box(mContext, mChildOffset, this);
 }
 
 void
 Box::Read(nsTArray<uint8_t>* aDest)
 {
   aDest->SetLength(mRange.mEnd - mChildOffset);
   size_t bytes;
--- a/media/libstagefright/binding/include/mp4_demuxer/Box.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Box.h
@@ -30,16 +30,17 @@ public:
   Stream* mSource;
   const nsTArray<MediaByteRange>& mByteRanges;
 };
 
 class Box
 {
 public:
   Box(BoxContext* aContext, uint64_t aOffset, const Box* aParent = nullptr);
+  Box();
 
   bool IsAvailable() const { return !mRange.IsNull(); }
   uint64_t Offset() const { return mRange.mStart; }
   uint64_t Length() const { return mRange.mEnd - mRange.mStart; }
   uint64_t NextOffset() const { return mRange.mEnd; }
   const MediaByteRange& Range() const { return mRange; }
 
   const Box* Parent() const { return mParent; }
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -77,17 +77,23 @@ HttpBaseChannel::HttpBaseChannel()
   , mContentDispositionHint(UINT32_MAX)
   , mHttpHandler(gHttpHandler)
   , mReferrerPolicy(REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE)
   , mRedirectCount(0)
   , mForcePending(false)
 {
   LOG(("Creating HttpBaseChannel @%x\n", this));
 
-  // Subfields of unions cannot be targeted in an initializer list
+  // Subfields of unions cannot be targeted in an initializer list.
+#ifdef MOZ_VALGRIND
+  // Zero the entire unions so that Valgrind doesn't complain when we send them
+  // to another process.
+  memset(&mSelfAddr, 0, sizeof(NetAddr));
+  memset(&mPeerAddr, 0, sizeof(NetAddr));
+#endif
   mSelfAddr.raw.family = PR_AF_UNSPEC;
   mPeerAddr.raw.family = PR_AF_UNSPEC;
 }
 
 HttpBaseChannel::~HttpBaseChannel()
 {
   LOG(("Destroying HttpBaseChannel @%x\n", this));
 
--- a/testing/web-platform/meta/media-source/mediasource-duration.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-duration.html.ini
@@ -1,22 +1,15 @@
 [mediasource-duration.html]
   type: testharness
   expected: TIMEOUT
   [Test seek starts on duration truncation below currentTime]
-    expected:
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): FAIL
-      if debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
-      if debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): FAIL
-      TIMEOUT
+    disabled: TIMEOUT or FAIL https://bugzilla.mozilla.org/show_bug.cgi?id=1085247
 
   [Test appendBuffer completes previous seek to truncated duration]
-    disabled: TIMEOUT or FAIL https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
+    disabled: TIMEOUT or FAIL https://bugzilla.mozilla.org/show_bug.cgi?id=1085247
 
   [Test endOfStream completes previous seek to truncated duration]
-    expected:
-      if not debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): FAIL
-      if debug and (os == "mac") and (version == "OS X 10.6.8") and (processor == "x86_64") and (bits == 64): FAIL
-      TIMEOUT
+    disabled: TIMEOUT or FAIL https://bugzilla.mozilla.org/show_bug.cgi?id=1085247
 
   [Test setting same duration multiple times does not fire duplicate durationchange]
     expected: FAIL
 
--- a/testing/web-platform/meta/url/interfaces.html.ini
+++ b/testing/web-platform/meta/url/interfaces.html.ini
@@ -1,14 +1,14 @@
 [interfaces.html]
   type: testharness
-  [URL interface: operation domainToASCII(ScalarValueString)]
+  [URL interface: operation domainToASCII(USVString)]
     expected: FAIL
 
-  [URL interface: operation domainToUnicode(ScalarValueString)]
+  [URL interface: operation domainToUnicode(USVString)]
     expected: FAIL
 
   [URLSearchParams interface: existence and properties of interface object]
     expected: FAIL
 
   [URL interface object length]
     expected: FAIL
 
--- a/testing/web-platform/tests/service-workers/stub-4.1-service-worker-global-scope.html
+++ b/testing/web-platform/tests/service-workers/stub-4.1-service-worker-global-scope.html
@@ -16,17 +16,17 @@
 [Global]
 interface ServiceWorkerGlobalScope : WorkerGlobalScope {
   readonly attribute CacheStorage caches;
   // A container for a list of window objects, identifiable by ID, that
   // correspond to windows (or workers) that are "controlled" by this SW
   readonly attribute ServiceWorkerClients clients;
   [Unforgeable] readonly attribute DOMString scope;
 
-  Promise<any> fetch((Request or ScalarValueString) request);
+  Promise<any> fetch((Request or USVString) request);
 
   void update();
   void unregister();
 
   attribute EventHandler oninstall;
   attribute EventHandler onactivate;
   attribute EventHandler onfetch;
   attribute EventHandler onbeforeevicted;
@@ -50,17 +50,17 @@ synchronous requests MUST NOT be initiat
 [1]: #navigator-service-worker-register
 -->
 
 
     <script type=text/plain id="untested_idls">
         interface CacheStorage {};
         interface ServiceWorkerClients {};
         interface Request {};
-        interface ScalarValueString {};
+        interface USVString {};
         interface EventHandler {};
         interface WorkerGlobalScope {};
     </pre>
 
     <script>
         var idl_array = new IdlArray();
         idl_array.add_untested_idls(document.getElementById("untested_idls").textContent);
         idl_array.add_idls(document.getElementById("idl_0").textContent);
--- a/testing/web-platform/tests/service-workers/stub-4.6.2-cache.html
+++ b/testing/web-platform/tests/service-workers/stub-4.6.2-cache.html
@@ -10,40 +10,40 @@
         <script src=/resources/idlharness.js></script>
 
     </head>
     <body>
 
 <script type=text/plain id="idl_0">
 [Constructor]
 interface Cache {
-  Promise<AbstractResponse> match((Request or ScalarValueString) request, optional QueryParams params);
-  Promise<sequence<AbstractResponse>> matchAll((Request or ScalarValueString) request, optional QueryParams params);
-  Promise<any> add((Request or ScalarValueString)... requests);
-  Promise<any> put((Request or ScalarValueString) request, AbstractResponse response);
-  Promise<any> delete((Request or ScalarValueString) request, optional QueryParams params);
+  Promise<AbstractResponse> match((Request or USVString) request, optional QueryParams params);
+  Promise<sequence<AbstractResponse>> matchAll((Request or USVString) request, optional QueryParams params);
+  Promise<any> add((Request or USVString)... requests);
+  Promise<any> put((Request or USVString) request, AbstractResponse response);
+  Promise<any> delete((Request or USVString) request, optional QueryParams params);
   Promise<any> each(CacheIterationCallback callback, optional object thisArg);
 };
 
 dictionary QueryParams {
   boolean ignoreSearch;
   boolean ignoreMethod;
   boolean ignoreVary;
   boolean prefixMatch;
 };
 
-callback CacheIterationCallback = void (AbstractResponse value, (Request or ScalarValueString) key, Cache map);
+callback CacheIterationCallback = void (AbstractResponse value, (Request or USVString) key, Cache map);
 </pre>
 
 
 
     <script type=text/plain id="untested_idls">
         interface AbstractResponse {};
         interface Request {};
-        interface ScalarValueString {};
+        interface USVString {};
     </pre>
 
     <script>
         var idl_array = new IdlArray();
         idl_array.add_untested_idls(document.getElementById("untested_idls").textContent);
         idl_array.add_idls(document.getElementById("idl_0").textContent);
         idl_array.add_objects({
             Cache: ["throw new Error ('No object defined for the Cache interface')"],
--- a/testing/web-platform/tests/service-workers/stub-4.6.3-cache-storage.html
+++ b/testing/web-platform/tests/service-workers/stub-4.6.3-cache-storage.html
@@ -10,17 +10,17 @@
         <script src=/resources/idlharness.js></script>
 
     </head>
     <body>
 
 <script type=text/plain id="idl_0">
 [Constructor(sequence<any> iterable)]
 interface CacheStorage {
-  Promise<any> match(ScalarValueString url, optional DOMString cacheName);
+  Promise<any> match(USVString url, optional DOMString cacheName);
   Promise<Cache> get(DOMString key);
   Promise<boolean> has(DOMString key);
   Promise<any> set(DOMString key, Cache val);
   Promise<any> clear();
   Promise<any> delete(DOMString key);
   void forEach(CacheStorageIterationCallback callback, optional object thisArg);
   Promise<sequence<any>> entries();
   Promise<sequence<DOMString>> keys();
@@ -37,17 +37,17 @@ to[ECMAScript 6 Map objects][2]but entir
 convenience methods.
 
 [1]: #cache-storage-interface
 [2]: http://goo.gl/gNnDPO
 -->
 
 
     <script type=text/plain id="untested_idls">
-        interface ScalarValueString {};
+        interface USVString {};
         interface Cache {};
     </pre>
 
     <script>
         var idl_array = new IdlArray();
         idl_array.add_untested_idls(document.getElementById("untested_idls").textContent);
         idl_array.add_idls(document.getElementById("idl_0").textContent);
         idl_array.add_objects({
--- a/testing/web-platform/tests/service-workers/stub-4.7.4.1-fetch-event-section.html
+++ b/testing/web-platform/tests/service-workers/stub-4.7.4.1-fetch-event-section.html
@@ -16,17 +16,17 @@
 [Constructor]
 interface FetchEvent : Event {
   readonly attribute Request request;
   readonly attribute Client client; // The window issuing the request.
   readonly attribute Context context;
   readonly attribute boolean isReload;
 
   void respondWith(Promise<AbstractResponse> r);
-  Promise<any> forwardTo(ScalarValueString url);
+  Promise<any> forwardTo(USVString url);
   Promise<any> default();
 };
 
 enum Context {
   "connect",
   "font",
   "img",
   "object",
@@ -46,17 +46,17 @@ Service Workers use the `[FetchEvent][1]
 [2]: #fetch-event
 -->
 
 
     <script type=text/plain id="untested_idls">
         interface Request {};
         interface Client {};
         interface AbstractResponse {};
-        interface ScalarValueString {};
+        interface USVString {};
         interface Event {};
     </pre>
 
     <script>
         var idl_array = new IdlArray();
         idl_array.add_untested_idls(document.getElementById("untested_idls").textContent);
         idl_array.add_idls(document.getElementById("idl_0").textContent);
         idl_array.add_objects({
--- a/testing/web-platform/tests/url/interfaces.html
+++ b/testing/web-platform/tests/url/interfaces.html
@@ -7,61 +7,61 @@
 
 <h1>URL IDL tests</h1>
 <div id=log></div>
 
 <script type=text/plain>
 [Constructor(DOMString url, optional DOMString base = "about:blank"),
  Exposed=Window,Worker]
 interface URL {
-  static DOMString domainToASCII(ScalarValueString domain);
-  static DOMString domainToUnicode(ScalarValueString domain);
+  static DOMString domainToASCII(USVString domain);
+  static DOMString domainToUnicode(USVString domain);
 };
 URL implements URLUtils;
 
 [NoInterfaceObject]
 interface URLUtils {
-  stringifier attribute ScalarValueString href;
+  stringifier attribute USVString href;
   readonly attribute DOMString origin;
 
-           attribute ScalarValueString protocol;
-           attribute ScalarValueString username;
-           attribute ScalarValueString password;
-           attribute ScalarValueString host;
-           attribute ScalarValueString hostname;
-           attribute ScalarValueString port;
-           attribute ScalarValueString pathname;
-           attribute ScalarValueString search;
+           attribute USVString protocol;
+           attribute USVString username;
+           attribute USVString password;
+           attribute USVString host;
+           attribute USVString hostname;
+           attribute USVString port;
+           attribute USVString pathname;
+           attribute USVString search;
            attribute URLSearchParams searchParams;
-           attribute ScalarValueString hash;
+           attribute USVString hash;
 };
 
 [NoInterfaceObject]
 interface URLUtilsReadOnly {
   stringifier readonly attribute DOMString href;
   readonly attribute DOMString origin;
 
   readonly attribute DOMString protocol;
   readonly attribute DOMString host;
   readonly attribute DOMString hostname;
   readonly attribute DOMString port;
   readonly attribute DOMString pathname;
   readonly attribute DOMString search;
   readonly attribute DOMString hash;
 };
 interface URLSearchParams {
-  void append(ScalarValueString name, ScalarValueString value);
-  void delete(ScalarValueString name);
-  DOMString? get(ScalarValueString name);
-  sequence<DOMString> getAll(ScalarValueString name);
-  boolean has(ScalarValueString name);
-  void set(ScalarValueString name, ScalarValueString value);
+  void append(USVString name, USVString value);
+  void delete(USVString name);
+  DOMString? get(USVString name);
+  sequence<DOMString> getAll(USVString name);
+  boolean has(USVString name);
+  void set(USVString name, USVString value);
   stringifier;
 };
-typedef DOMString ScalarValueString;
+typedef DOMString USVString;
 </script>
 <script>
 "use strict";
 var idlArray;
 setup(function() {
 	idlArray = new IdlArray();
 	[].forEach.call(document.querySelectorAll("script[type=text\\/plain]"), function(node) {
 		if (node.className == "untested") {
--- a/tools/profiler/GeckoTaskTracer.cpp
+++ b/tools/profiler/GeckoTaskTracer.cpp
@@ -32,16 +32,17 @@ namespace mozilla {
 namespace tasktracer {
 
 static mozilla::ThreadLocal<TraceInfo*>* sTraceInfoTLS = nullptr;
 static mozilla::StaticMutex sMutex;
 static nsTArray<nsAutoPtr<TraceInfo>>* sTraceInfos = nullptr;
 static bool sIsLoggingStarted = false;
 
 static TimeStamp sStartTime;
+static const char sJSLabelPrefix[] = "#tt#";
 
 namespace {
 
 static TraceInfo*
 AllocTraceInfo(int aTid)
 {
   StaticMutexAutoLock lock(sMutex);
 
@@ -397,10 +398,16 @@ GetLoggedData(TimeStamp aStartTime)
 
   for (uint32_t i = 0; i < sTraceInfos->Length(); ++i) {
     (*sTraceInfos)[i]->MoveLogsInto(*result);
   }
 
   return result;
 }
 
+const char*
+GetJSLabelPrefix()
+{
+  return sJSLabelPrefix;
+}
+
 } // namespace tasktracer
 } // namespace mozilla
--- a/tools/profiler/GeckoTaskTracer.h
+++ b/tools/profiler/GeckoTaskTracer.h
@@ -78,12 +78,14 @@ already_AddRefed<nsIRunnable> CreateTrac
 
 already_AddRefed<FakeTracedTask> CreateFakeTracedTask(int* aVptr);
 
 // Free the TraceInfo allocated on a thread's TLS. Currently we are wrapping
 // tasks running on nsThreads and base::thread, so FreeTraceInfo is called at
 // where nsThread and base::thread release themselves.
 void FreeTraceInfo();
 
+const char* GetJSLabelPrefix();
+
 } // namespace tasktracer
 } // namespace mozilla.
 
 #endif
--- a/view/nsView.cpp
+++ b/view/nsView.cpp
@@ -332,24 +332,24 @@ void nsView::DoResetWidgetBounds(bool aM
 
   // Bug 861270: for correct widget manipulation at arbitrary scale factors,
   // prefer to base scaling on widget->GetDefaultScale(). But only do this if
   // it matches the view manager's device context scale after allowing for the
   // quantization to app units, because of OS X multiscreen issues (where the
   // only two scales are 1.0 or 2.0, and so the quantization doesn't actually
   // cause problems anyhow).
   // In the case of a mismatch, fall back to scaling based on the dev context's
-  // unscaledAppUnitsPerDevPixel value. On platforms where the device-pixel
+  // AppUnitsPerDevPixelAtUnitFullZoom value. On platforms where the device-pixel
   // scale is uniform across all displays (currently all except OS X), we'll
   // always use the precise value from mWindow->GetDefaultScale here.
   CSSToLayoutDeviceScale scale = widget->GetDefaultScale();
-  if (NSToIntRound(60.0 / scale.scale) == dx->UnscaledAppUnitsPerDevPixel()) {
+  if (NSToIntRound(60.0 / scale.scale) == dx->AppUnitsPerDevPixelAtUnitFullZoom()) {
     invScale = 1.0 / scale.scale;
   } else {
-    invScale = dx->UnscaledAppUnitsPerDevPixel() / 60.0;
+    invScale = dx->AppUnitsPerDevPixelAtUnitFullZoom() / 60.0;
   }
 
   if (changedPos) {
     if (changedSize && !aMoveOnly) {
       widget->ResizeClient(newBounds.x * invScale,
                            newBounds.y * invScale,
                            newBounds.width * invScale,
                            newBounds.height * invScale,
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -2284,17 +2284,17 @@ nsNativeThemeCocoa::IsParentScrollbarRol
     ? CheckBooleanAttr(scrollbarFrame, nsGkAtoms::hover)
     : GetContentState(scrollbarFrame, NS_THEME_NONE).HasState(NS_EVENT_STATE_HOVER);
 }
 
 static bool
 IsHiDPIContext(nsPresContext* aContext)
 {
   return nsPresContext::AppUnitsPerCSSPixel() >=
-    2 * aContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
+    2 * aContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
 }
 
 NS_IMETHODIMP
 nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
                                          nsIFrame* aFrame,
                                          uint8_t aWidgetType,
                                          const nsRect& aRect,
                                          const nsRect& aDirtyRect)
--- a/widget/nsBaseDragService.cpp
+++ b/widget/nsBaseDragService.cpp
@@ -643,17 +643,17 @@ nsBaseDragService::DrawDragForImage(nsPr
 
   return result;
 }
 
 void
 nsBaseDragService::ConvertToUnscaledDevPixels(nsPresContext* aPresContext,
                                               int32_t* aScreenX, int32_t* aScreenY)
 {
-  int32_t adj = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
+  int32_t adj = aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
   *aScreenX = nsPresContext::CSSPixelsToAppUnits(*aScreenX) / adj;
   *aScreenY = nsPresContext::CSSPixelsToAppUnits(*aScreenY) / adj;
 }
 
 NS_IMETHODIMP
 nsBaseDragService::Suppress()
 {
   EndDragSession(false);
--- a/xpcom/base/nsConsoleService.cpp
+++ b/xpcom/base/nsConsoleService.cpp
@@ -26,16 +26,21 @@
 #if defined(ANDROID)
 #include <android/log.h>
 #include "mozilla/dom/ContentChild.h"
 #endif
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
+#ifdef MOZ_TASK_TRACER
+#include "GeckoTaskTracer.h"
+using namespace mozilla::tasktracer;
+#endif
+
 using namespace mozilla;
 
 NS_IMPL_ADDREF(nsConsoleService)
 NS_IMPL_RELEASE(nsConsoleService)
 NS_IMPL_CLASSINFO(nsConsoleService, nullptr,
                   nsIClassInfo::THREADSAFE | nsIClassInfo::SINGLETON,
                   NS_CONSOLESERVICE_CID)
 NS_IMPL_QUERY_INTERFACE_CI(nsConsoleService, nsIConsoleService)
@@ -241,16 +246,27 @@ nsConsoleService::LogMessageWithMode(nsI
 #ifdef XP_WIN
     if (IsDebuggerPresent()) {
       nsString msg;
       aMessage->GetMessageMoz(getter_Copies(msg));
       msg.Append('\n');
       OutputDebugStringW(msg.get());
     }
 #endif
+#ifdef MOZ_TASK_TRACER
+    {
+      nsCString msg;
+      aMessage->ToString(msg);
+      int prefixPos = msg.Find(GetJSLabelPrefix());
+      if (prefixPos >= 0) {
+        nsDependentCSubstring submsg(msg, prefixPos);
+        AddLabel("%s", submsg.BeginReading());
+      }
+    }
+#endif
 
     /*
      * If there's already a message in the slot we're about to replace,
      * we've wrapped around, and we need to release the old message.  We
      * save a pointer to it, so we can release below outside the lock.
      */
     retiredMessage = mMessages[mCurrent];
 
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -1998,16 +1998,23 @@ public:
     Base::AppendElements(aOther);
   }
   template<typename Allocator>
   explicit nsAutoTArray(nsTArray_Impl<E, Allocator>&& aOther)
     : Base(mozilla::Move(aOther))
   {
   }
 
+  template<typename Allocator>
+  self_type& operator=(const nsTArray_Impl<E, Allocator>& other)
+  {
+    Base::operator=(other);
+    return *this;
+  }
+
   operator const AutoFallibleTArray<E, N>&() const
   {
     return *reinterpret_cast<const AutoFallibleTArray<E, N>*>(this);
   }
 };
 
 //
 // AutoFallibleTArray<E, N> is a fallible vector class with N elements of
@@ -2028,16 +2035,23 @@ public:
     Base::AppendElements(aOther);
   }
   template<typename Allocator>
   explicit AutoFallibleTArray(nsTArray_Impl<E, Allocator>&& aOther)
     : Base(mozilla::Move(aOther))
   {
   }
 
+  template<typename Allocator>
+  self_type& operator=(const nsTArray_Impl<E, Allocator>& other)
+  {
+    Base::operator=(other);
+    return *this;
+  }
+
   operator const nsAutoTArray<E, N>&() const
   {
     return *reinterpret_cast<const nsAutoTArray<E, N>*>(this);
   }
 };
 
 // Assert that nsAutoTArray doesn't have any extra padding inside.
 //
--- a/xpcom/threads/ThreadStackHelper.cpp
+++ b/xpcom/threads/ThreadStackHelper.cpp
@@ -33,16 +33,20 @@
 #if defined(MOZ_THREADSTACKHELPER_X86)
 #include "processor/stackwalker_x86.h"
 #elif defined(MOZ_THREADSTACKHELPER_X64)
 #include "processor/stackwalker_amd64.h"
 #elif defined(MOZ_THREADSTACKHELPER_ARM)
 #include "processor/stackwalker_arm.h"
 #endif
 
+#if defined(MOZ_VALGRIND)
+# include <valgrind/valgrind.h>
+#endif
+
 #include <string.h>
 #include <vector>
 
 #ifdef XP_LINUX
 #ifdef ANDROID
 // Android NDK doesn't contain ucontext.h; use Breakpad's copy.
 # include "common/android/include/sys/ucontext.h"
 #else
@@ -255,16 +259,24 @@ ThreadStackHelper::GetStack(Stack& aStac
   }
 
   FillStackBuffer();
   FillThreadContext();
 
   MOZ_ALWAYS_TRUE(::ResumeThread(mThreadID) != DWORD(-1));
 
 #elif defined(XP_MACOSX)
+# if defined(MOZ_VALGRIND) && defined(RUNNING_ON_VALGRIND)
+  if (RUNNING_ON_VALGRIND) {
+    /* thread_suspend and thread_resume sometimes hang runs on Valgrind,
+       for unknown reasons.  So, just avoid them.  See bug 1100911. */
+    return;
+  }
+# endif
+
   if (::thread_suspend(mThreadID) != KERN_SUCCESS) {
     MOZ_ASSERT(false);
     return;
   }
 
   FillStackBuffer();
   FillThreadContext();