Merge Fx-team to Mozilla-Central
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 28 Oct 2013 10:04:41 +0100
changeset 167210 4646259ab62d9afb1aca0d51aabf1c55b48388e3
parent 167208 9e0dbf6786543397dcc34d7664aa5094164d7a9c (diff)
parent 167209 f4b1b234f20df00ec7328bb25549fee2e1a6c2d9 (current diff)
child 167229 085c6286911f5a0537c96ccb7206ad9fedb5fa29
child 171469 dfb4db3ac4460112f98fa0b2277f8ccb3c129c4c
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.0a1
first release with
nightly linux32
4646259ab62d / 27.0a1 / 20131028030205 / files
nightly linux64
4646259ab62d / 27.0a1 / 20131028030205 / files
nightly mac
4646259ab62d / 27.0a1 / 20131028030205 / files
nightly win32
4646259ab62d / 27.0a1 / 20131028030205 / files
nightly win64
4646259ab62d / 27.0a1 / 20131028030205 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge Fx-team to Mozilla-Central
--- a/accessible/src/html/HTMLFormControlAccessible.cpp
+++ b/accessible/src/html/HTMLFormControlAccessible.cpp
@@ -19,17 +19,16 @@
 #include "nsIAccessibleRelation.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsIEditor.h"
 #include "nsIFormControl.h"
 #include "nsINameSpaceManager.h"
 #include "nsIPersistentProperties2.h"
 #include "nsISelectionController.h"
-#include "jsapi.h"
 #include "nsIServiceManager.h"
 #include "nsITextControlFrame.h"
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::a11y;
--- a/caps/src/nsJSPrincipals.cpp
+++ b/caps/src/nsJSPrincipals.cpp
@@ -6,17 +6,16 @@
 #include "xpcprivate.h"
 #include "nsString.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIObjectInputStream.h"
 #include "nsJSPrincipals.h"
 #include "plstr.h"
 #include "nsXPIDLString.h"
 #include "nsCOMPtr.h"
-#include "jsapi.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIServiceManager.h"
 #include "nsMemory.h"
 #include "nsStringBuffer.h"
 
 // for mozilla::dom::workers::kJSPrincipalsDebugToken
 #include "mozilla/dom/workers/Workers.h"
 
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -79,18 +79,16 @@
 #include "nsContentUtils.h"
 #include "ChildIterator.h"
 
 #include "nsIDOMEventListener.h"
 #include "nsIWebNavigation.h"
 #include "nsIBaseWindow.h"
 #include "nsIWidget.h"
 
-#include "jsapi.h"
-
 #include "nsNodeInfoManager.h"
 #include "nsICategoryManager.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIEditor.h"
 #include "nsIEditorIMESupport.h"
 #include "nsEventDispatcher.h"
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -74,17 +74,17 @@
 #include "nsGkAtoms.h"
 #include "nsContentUtils.h"
 
 #include "nsIDOMEventListener.h"
 #include "nsIWebNavigation.h"
 #include "nsIBaseWindow.h"
 #include "nsIWidget.h"
 
-#include "jsapi.h"
+#include "js/GCAPI.h"
 
 #include "nsNodeInfoManager.h"
 #include "nsICategoryManager.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIEditor.h"
 #include "nsIEditorIMESupport.h"
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -2854,37 +2854,37 @@ CanvasRenderingContext2D::SetMozDashOffs
 {
   ContextState& state = CurrentState();
   if (!state.dash.IsEmpty()) {
     state.dashOffset = mozDashOffset;
   }
 }
 
 void
-CanvasRenderingContext2D::SetLineDash(const mozilla::dom::AutoSequence<double>& mSegments) {
+CanvasRenderingContext2D::SetLineDash(const mozilla::dom::AutoSequence<double>& aSegments) {
   FallibleTArray<mozilla::gfx::Float>& dash = CurrentState().dash;
   dash.Clear();
 
-  for(mozilla::dom::AutoSequence<double>::index_type x = 0; x < mSegments.Length(); x++) {
-    dash.AppendElement(mSegments[x]);
+  for (uint32_t x = 0; x < aSegments.Length(); x++) {
+    dash.AppendElement(aSegments[x]);
   }
-  if(mSegments.Length()%2) { // If the number of elements is odd, concatenate again
-    for(mozilla::dom::AutoSequence<double>::index_type x = 0; x < mSegments.Length(); x++) {
-      dash.AppendElement(mSegments[x]);
+  if (aSegments.Length() % 2) { // If the number of elements is odd, concatenate again
+    for (uint32_t x = 0; x < aSegments.Length(); x++) {
+      dash.AppendElement(aSegments[x]);
     }
   }
 }
 
 void
-CanvasRenderingContext2D::GetLineDash(nsTArray<double>& mSegments) const {
+CanvasRenderingContext2D::GetLineDash(nsTArray<double>& aSegments) const {
   const FallibleTArray<mozilla::gfx::Float>& dash = CurrentState().dash;
-  mSegments.Clear();
-
-  for(FallibleTArray<mozilla::gfx::Float>::index_type x = 0; x < dash.Length(); x++) {
-    mSegments.AppendElement(dash[x]);
+  aSegments.Clear();
+
+  for (uint32_t x = 0; x < dash.Length(); x++) {
+    aSegments.AppendElement(dash[x]);
   }
 }
 
 void
 CanvasRenderingContext2D::SetLineDashOffset(double mOffset) {
   CurrentState().dashOffset = mOffset;
 }
 
--- a/content/html/content/src/HTMLScriptElement.cpp
+++ b/content/html/content/src/HTMLScriptElement.cpp
@@ -6,17 +6,16 @@
 
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsIDocument.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"  // for nsCaseInsensitiveStringComparator()
-#include "jsapi.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIXPConnect.h"
 #include "nsServiceManagerUtils.h"
 #include "nsError.h"
 #include "nsIArray.h"
 #include "nsTArray.h"
 #include "nsDOMJSUtils.h"
--- a/content/html/content/src/HTMLVideoElement.cpp
+++ b/content/html/content/src/HTMLVideoElement.cpp
@@ -19,17 +19,16 @@
 #include "nsNetUtil.h"
 #include "nsXPCOMStrings.h"
 #include "prlock.h"
 #include "nsThreadUtils.h"
 #include "ImageContainer.h"
 
 #include "nsIScriptSecurityManager.h"
 #include "nsIXPConnect.h"
-#include "jsapi.h"
 
 #include "nsITimer.h"
 
 #include "nsEventDispatcher.h"
 #include "nsIDOMProgressEvent.h"
 #include "nsIPowerManagerService.h"
 #include "MediaError.h"
 #include "MediaDecoder.h"
--- a/content/xbl/src/nsBindingManager.cpp
+++ b/content/xbl/src/nsBindingManager.cpp
@@ -28,17 +28,16 @@
 #include "nsXBLPrototypeBinding.h"
 #include "nsXBLDocumentInfo.h"
 #include "mozilla/dom/XBLChildrenElement.h"
 
 #include "nsIStyleRuleProcessor.h"
 #include "nsRuleProcessorData.h"
 #include "nsIWeakReference.h"
 
-#include "jsapi.h"
 #include "nsIXPConnect.h"
 #include "nsDOMCID.h"
 #include "nsIDOMScriptObjectFactory.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsTHashtable.h"
 
 #include "nsIScriptContext.h"
 #include "nsBindingManager.h"
--- a/content/xul/document/src/nsXULContentSink.cpp
+++ b/content/xul/document/src/nsXULContentSink.cpp
@@ -9,17 +9,16 @@
  * to build a content model (the "prototype" document) from XUL.
  *
  * For more information on XUL,
  * see http://developer.mozilla.org/en/docs/XUL
  */
 
 #include "nsXULContentSink.h"
 
-#include "jsapi.h"
 #include "jsfriendapi.h"
 
 #include "nsCOMPtr.h"
 #include "nsForwardReference.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsIContentSink.h"
 #include "nsIDocument.h"
 #include "nsIDOMEventListener.h"
--- a/content/xul/document/src/nsXULPrototypeCache.cpp
+++ b/content/xul/document/src/nsXULPrototypeCache.cpp
@@ -17,17 +17,16 @@
 #include "nsIObjectOutputStream.h"
 #include "nsIObserverService.h"
 #include "nsIStringStream.h"
 #include "nsIStorageStream.h"
 
 #include "nsNetUtil.h"
 #include "nsAppDirectoryServiceDefs.h"
 
-#include "jsapi.h"
 #include "js/Tracer.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 #include "mozilla/Telemetry.h"
 
 using namespace mozilla;
--- a/content/xul/templates/src/nsXULContentBuilder.cpp
+++ b/content/xul/templates/src/nsXULContentBuilder.cpp
@@ -28,17 +28,16 @@
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentUtils.h"
 #include "nsAttrName.h"
 #include "nsNodeUtils.h"
 #include "mozAutoDocUpdate.h"
 #include "nsTextNode.h"
 
-#include "jsapi.h"
 #include "pldhash.h"
 #include "rdf.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 //
--- a/dom/base/DOMException.cpp
+++ b/dom/base/DOMException.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/DOMException.h"
 
-#include "jsapi.h"
 #include "jsprf.h"
 #include "js/OldDebugAPI.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/Util.h"
 #include "mozilla/dom/Exceptions.h"
 #include "nsContentUtils.h"
 #include "nsCOMPtr.h"
 #include "nsIClassInfoImpl.h"
--- a/dom/base/nsDOMJSUtils.h
+++ b/dom/base/nsDOMJSUtils.h
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-
 #ifndef nsDOMJSUtils_h__
 #define nsDOMJSUtils_h__
 
 #include "nsIScriptContext.h"
+#include "jsapi.h"
 
 class nsIJSArgArray;
 
 // seems like overkill for just this 1 function - but let's see what else
 // falls out first.
 inline nsIScriptContext *
 GetScriptContextFromJSContext(JSContext *cx)
 {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -45,17 +45,16 @@
 #undef CreateEvent
 #endif
 #endif // XP_WIN
 
 // Helper Classes
 #include "nsJSUtils.h"
 #include "jsapi.h"              // for JSAutoRequest
 #include "js/OldDebugAPI.h"     // for JS_ClearWatchPointsForObject
-#include "jsfriendapi.h"        // for JS_GetGlobalForFrame
 #include "jswrapper.h"
 #include "nsReadableUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsJSEnvironment.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Likely.h"
 
 // Other Classes
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3056,24 +3056,31 @@ for (uint32_t i = 0; i < length; ++i) {
         templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}")
 
         typeName = ("Owning" if isMember else "") + type.name
         argumentTypeName = typeName + "Argument"
         if nullable:
             typeName = "Nullable<" + typeName + " >"
 
         def handleNull(templateBody, setToNullVar, extraConditionForNull=""):
-            null = CGGeneric("if (%s${val}.isNullOrUndefined()) {\n"
-                             "  %s.SetNull();\n"
-                             "}" % (extraConditionForNull, setToNullVar))
-            templateBody = CGWrapper(CGIndenter(templateBody), pre="{\n", post="\n}")
-            return CGList([null, templateBody], " else ")
+            nullTest = "%s${val}.isNullOrUndefined()" % extraConditionForNull
+            return CGIfElseWrapper(nullTest,
+                                   CGGeneric("%s.SetNull();" % setToNullVar),
+                                   templateBody)
 
         if type.hasNullableType:
-            templateBody = handleNull(templateBody, unionArgumentObj)
+            assert not nullable
+            # Make sure to handle a null default value here
+            if defaultValue and isinstance(defaultValue, IDLNullValue):
+                assert defaultValue.type == type
+                extraConditionForNull = "!(${haveValue}) || "
+            else:
+                extraConditionForNull = ""
+            templateBody = handleNull(templateBody, unionArgumentObj,
+                                      extraConditionForNull=extraConditionForNull)
 
         declType = CGGeneric(typeName)
         holderType = CGGeneric(argumentTypeName) if not isMember else None
 
         # If we're isOptional and not nullable the normal optional handling will
         # handle lazy construction of our holder.  If we're nullable we do it
         # all by hand because we do not want our holder constructed if we're
         # null.
@@ -3119,16 +3126,32 @@ for (uint32_t i = 0; i < length; ++i) {
                 if isinstance(defaultValue, IDLNullValue):
                     extraConditionForNull = "!(${haveValue}) || "
                 else:
                     extraConditionForNull = "${haveValue} && "
             else:
                 extraConditionForNull = ""
             templateBody = handleNull(templateBody, declLoc,
                                       extraConditionForNull=extraConditionForNull)
+        elif (not type.hasNullableType and defaultValue and
+              isinstance(defaultValue, IDLNullValue)):
+            assert type.hasDictionaryType
+            assert defaultValue.type.isDictionary()
+            if not isMember and typeNeedsRooting(defaultValue.type):
+                ctorArgs = "cx"
+            else:
+                ctorArgs = ""
+            initDictionaryWithNull = CGIfWrapper(
+                CGGeneric("return false;"),
+                ('!%s.SetAs%s(%s).Init(cx, JS::NullHandleValue, "Member of %s")'
+                 % (declLoc, getUnionMemberName(defaultValue.type),
+                    ctorArgs, type)))
+            templateBody = CGIfElseWrapper("!(${haveValue})",
+                                           initDictionaryWithNull,
+                                           templateBody)
 
         templateBody = CGList([constructDecl, templateBody], "\n")
 
         return JSToNativeConversionInfo(templateBody.define(),
                                         declType=declType,
                                         holderType=holderType,
                                         holderArgs=holderArgs,
                                         dealWithOptional=isOptional and not nullable)
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -2435,17 +2435,20 @@ class IDLValue(IDLObject):
 
     def coerceToType(self, type, location):
         if type == self.type:
             return self # Nothing to do
 
         # We first check for unions to ensure that even if the union is nullable
         # we end up with the right flat member type, not the union's type.
         if type.isUnion():
-            for subtype in type.unroll().memberTypes:
+            # We use the flat member types here, because if we have a nullable
+            # member type, or a nested union, we want the type the value
+            # actually coerces to, not the nullable or nested union type.
+            for subtype in type.unroll().flatMemberTypes:
                 try:
                     coercedValue = self.coerceToType(subtype, location)
                     # Create a new IDLValue to make sure that we have the
                     # correct float/double type.  This is necessary because we
                     # use the value's type when it is a default value of a
                     # union, and the union cares about the exact float type.
                     return IDLValue(self.location, subtype, coercedValue.value)
                 except:
@@ -2508,16 +2511,23 @@ class IDLNullValue(IDLObject):
             not (type.isUnion() and type.hasNullableType) and
             not (type.isUnion() and type.hasDictionaryType) and
             not type.isDictionary() and
             not type.isAny()):
             raise WebIDLError("Cannot coerce null value to type %s." % type,
                               [location])
 
         nullValue = IDLNullValue(self.location)
+        if type.isUnion() and not type.nullable() and type.hasDictionaryType:
+            # We're actually a default value for the union's dictionary member.
+            # Use its type.
+            for t in type.flatMemberTypes:
+                if t.isDictionary():
+                    nullValue.type = t
+                    return nullValue
         nullValue.type = type
         return nullValue
 
     def _getDependentObjects(self):
         return set()
   
 
 class IDLInterfaceMember(IDLObjectWithIdentifier):
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -508,16 +508,19 @@ public:
   void PassUnion4(const NodeOrLongOrBoolean& arg);
   void PassUnion5(JSContext*, const ObjectOrBoolean& arg);
   void PassUnion6(JSContext*, const ObjectOrString& arg);
   void PassUnion7(JSContext*, const ObjectOrStringOrLong& arg);
   void PassUnion8(JSContext*, const ObjectOrStringOrBoolean& arg);
   void PassUnion9(JSContext*, const ObjectOrStringOrLongOrBoolean& arg);
   void PassUnion10(const EventInitOrLong& arg);
   void PassUnion11(JSContext*, const CustomEventInitOrLong& arg);
+  void PassUnion12(const EventInitOrLong& arg);
+  void PassUnion13(JSContext*, const ObjectOrLongOrNull& arg);
+  void PassUnion14(JSContext*, const ObjectOrLongOrNull& arg);
 #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
@@ -448,16 +448,19 @@ interface TestInterface {
   void passUnion4((Node or long or boolean) arg);
   void passUnion5((object or boolean) arg);
   void passUnion6((object or DOMString) arg);
   void passUnion7((object or DOMString or long) arg);
   void passUnion8((object or DOMString or boolean) arg);
   void passUnion9((object or DOMString or long or boolean) arg);
   void passUnion10(optional (EventInit or long) arg);
   void passUnion11(optional (CustomEventInit or long) arg);
+  void passUnion12(optional (EventInit or long) arg = 5);
+  void passUnion13(optional (object or long?) arg = null);
+  void passUnion14(optional (object or long?) arg = 5);
 #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
@@ -344,16 +344,19 @@ interface TestExampleInterface {
   void passUnion4((Node or long or boolean) arg);
   void passUnion5((object or boolean) arg);
   void passUnion6((object or DOMString) arg);
   void passUnion7((object or DOMString or long) arg);
   void passUnion8((object or DOMString or boolean) arg);
   void passUnion9((object or DOMString or long or boolean) arg);
   void passUnion10(optional (EventInit or long) arg);
   void passUnion11(optional (CustomEventInit or long) arg);
+  void passUnion12(optional (EventInit or long) arg = 5);
+  void passUnion13(optional (object or long?) arg = null);
+  void passUnion14(optional (object or long?) arg = 5);
 #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
@@ -366,16 +366,19 @@ interface TestJSImplInterface {
   void passUnion4((Node or long or boolean) arg);
   void passUnion5((object or boolean) arg);
   void passUnion6((object or DOMString) arg);
   void passUnion7((object or DOMString or long) arg);
   void passUnion8((object or DOMString or boolean) arg);
   void passUnion9((object or DOMString or long or boolean) arg);
   void passUnion10(optional (EventInit or long) arg);
   void passUnion11(optional (CustomEventInit or long) arg);
+  void passUnion12(optional (EventInit or long) arg = 5);
+  void passUnion13(optional (object or long?) arg = null);
+  void passUnion14(optional (object or long?) arg = 5);
 #endif
   void passUnionWithNullable((object? or long) arg);
   // FIXME: Bug 863948 Nullable unions not supported yet
   //   void passNullableUnion((object or long)? arg);
   void passOptionalUnion(optional (object or long) arg);
   // FIXME: Bug 863948 Nullable unions not supported yet
   //  void passOptionalNullableUnion(optional (object or long)? arg);
   //  void passOptionalNullableUnionWithDefaultValue(optional (object or long)? arg = null);
--- a/dom/bindings/test/test_exceptions_from_jsimplemented.html
+++ b/dom/bindings/test/test_exceptions_from_jsimplemented.html
@@ -8,20 +8,24 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 923010</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript">
   /** Test for Bug 923010 **/
   try {
     var conn = new mozRTCPeerConnection();
     try {
-      conn.createAnswer(function() {}, null, { "mandatory": { "BOGUS": 5 } } )
+      conn.createAnswer(function() {
+          ok(false, "The call to createAnswer succeeded when it should have thrown");
+        }, function() {
+          ok(false, "The call to createAnswer failed when it should have thrown");
+        }, { "mandatory": { "BOGUS": 5 } } )
       ok(false, "That call to createAnswer should have thrown");
     } catch (e) {
-      is(e.lineNumber, 16, "Exception should have been on line 15");
+      is(e.lineNumber, 20, "Exception should have been on line 20");
       is(e.message,
          "createAnswer passed invalid constraints - unknown mandatory constraint: BOGUS",
          "Should have the exception we expect");
     }
   } catch (e) {
     // b2g has no WebRTC, apparently
     todo(false, "No WebRTC on b2g yet");
   }
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfo.h"
 #include "nsHashPropertyBag.h"
-#include "jsapi.h"
 #include "nsThread.h"
 #include "DeviceStorage.h"
 #include "mozilla/dom/CameraControlBinding.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "nsIAppsService.h"
 #include "nsIObserverService.h"
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -20,17 +20,16 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <libgen.h>
 #include "base/basictypes.h"
 #include "camera/CameraParameters.h"
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfo.h"
 #include "nsMemory.h"
-#include "jsapi.h"
 #include "nsThread.h"
 #include <media/MediaProfiles.h>
 #include "mozilla/FileUtils.h"
 #include "mozilla/Services.h"
 #include "nsAlgorithm.h"
 #include <media/mediaplayer.h>
 #include "nsPrintfCString.h"
 #include "nsIObserverService.h"
--- a/dom/camera/GonkCameraManager.cpp
+++ b/dom/camera/GonkCameraManager.cpp
@@ -11,17 +11,16 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include <camera/Camera.h>
 
-#include "jsapi.h"
 #include "GonkCameraControl.h"
 #include "DOMCameraManager.h"
 #include "CameraCommon.h"
 #include "mozilla/ErrorResult.h"
 
 using namespace mozilla;
 
 // From nsDOMCameraManager, but gonk-specific!
--- a/dom/icc/src/StkCommandEvent.cpp
+++ b/dom/icc/src/StkCommandEvent.cpp
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/StkCommandEvent.h"
 
-#include "jsapi.h"
 #include "jsfriendapi.h"
 #include "nsJSON.h"
 #include "SimToolKit.h"
 
 namespace mozilla {
 namespace dom {
 
 already_AddRefed<StkCommandEvent>
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1536,46 +1536,59 @@ TabChild::ProcessUpdateFrame(const Frame
   {
     if (!mGlobal || !mTabChildGlobal) {
         return true;
     }
 
     CSSRect cssCompositedRect = aFrameMetrics.CalculateCompositedRectInCssPixels();
     // The BrowserElementScrolling helper must know about these updated metrics
     // for other functions it performs, such as double tap handling.
+    // Note, %f must not be used because it is locale specific!
     nsCString data;
-    data += nsPrintfCString("{ \"x\" : %d", NS_lround(aFrameMetrics.mScrollOffset.x));
-    data += nsPrintfCString(", \"y\" : %d", NS_lround(aFrameMetrics.mScrollOffset.y));
-    data += nsPrintfCString(", \"viewport\" : ");
-        data += nsPrintfCString("{ \"width\" : %f", aFrameMetrics.mViewport.width);
-        data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mViewport.height);
-        data += nsPrintfCString(" }");
-    data += nsPrintfCString(", \"displayPort\" : ");
-        data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mDisplayPort.x);
-        data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mDisplayPort.y);
-        data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mDisplayPort.width);
-        data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mDisplayPort.height);
-        data += nsPrintfCString(" }");
-    data += nsPrintfCString(", \"compositionBounds\" : ");
-        data += nsPrintfCString("{ \"x\" : %d", aFrameMetrics.mCompositionBounds.x);
-        data += nsPrintfCString(", \"y\" : %d", aFrameMetrics.mCompositionBounds.y);
-        data += nsPrintfCString(", \"width\" : %d", aFrameMetrics.mCompositionBounds.width);
-        data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mCompositionBounds.height);
-        data += nsPrintfCString(" }");
-    data += nsPrintfCString(", \"cssPageRect\" : ");
-        data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mScrollableRect.x);
-        data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mScrollableRect.y);
-        data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mScrollableRect.width);
-        data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mScrollableRect.height);
-        data += nsPrintfCString(" }");
-    data += nsPrintfCString(", \"cssCompositedRect\" : ");
-            data += nsPrintfCString("{ \"width\" : %f", cssCompositedRect.width);
-            data += nsPrintfCString(", \"height\" : %f", cssCompositedRect.height);
-            data += nsPrintfCString(" }");
-    data += nsPrintfCString(" }");
+    data.AppendPrintf("{ \"x\" : %d", NS_lround(aFrameMetrics.mScrollOffset.x));
+    data.AppendPrintf(", \"y\" : %d", NS_lround(aFrameMetrics.mScrollOffset.y));
+    data.AppendLiteral(", \"viewport\" : ");
+        data.AppendLiteral("{ \"width\" : ");
+        data.AppendFloat(aFrameMetrics.mViewport.width);
+        data.AppendLiteral(", \"height\" : ");
+        data.AppendFloat(aFrameMetrics.mViewport.height);
+        data.AppendLiteral(" }");
+    data.AppendLiteral(", \"displayPort\" : ");
+        data.AppendLiteral("{ \"x\" : ");
+        data.AppendFloat(aFrameMetrics.mDisplayPort.x);
+        data.AppendLiteral(", \"y\" : ");
+        data.AppendFloat(aFrameMetrics.mDisplayPort.y);
+        data.AppendLiteral(", \"width\" : ");
+        data.AppendFloat(aFrameMetrics.mDisplayPort.width);
+        data.AppendLiteral(", \"height\" : ");
+        data.AppendFloat(aFrameMetrics.mDisplayPort.height);
+        data.AppendLiteral(" }");
+    data.AppendLiteral(", \"compositionBounds\" : ");
+        data.AppendPrintf("{ \"x\" : %d", aFrameMetrics.mCompositionBounds.x);
+        data.AppendPrintf(", \"y\" : %d", aFrameMetrics.mCompositionBounds.y);
+        data.AppendPrintf(", \"width\" : %d", aFrameMetrics.mCompositionBounds.width);
+        data.AppendPrintf(", \"height\" : %d", aFrameMetrics.mCompositionBounds.height);
+        data.AppendLiteral(" }");
+    data.AppendLiteral(", \"cssPageRect\" : ");
+        data.AppendLiteral("{ \"x\" : ");
+        data.AppendFloat(aFrameMetrics.mScrollableRect.x);
+        data.AppendLiteral(", \"y\" : ");
+        data.AppendFloat(aFrameMetrics.mScrollableRect.y);
+        data.AppendLiteral(", \"width\" : ");
+        data.AppendFloat(aFrameMetrics.mScrollableRect.width);
+        data.AppendLiteral(", \"height\" : ");
+        data.AppendFloat(aFrameMetrics.mScrollableRect.height);
+        data.AppendLiteral(" }");
+    data.AppendLiteral(", \"cssCompositedRect\" : ");
+        data.AppendLiteral("{ \"width\" : ");
+        data.AppendFloat(cssCompositedRect.width);
+        data.AppendLiteral(", \"height\" : ");
+        data.AppendFloat(cssCompositedRect.height);
+        data.AppendLiteral(" }");
+    data.AppendLiteral(" }");
 
     DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
 
     nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
 
     APZCCallbackHelper::UpdateRootFrame(utils, aFrameMetrics);
 
     mLastMetrics = aFrameMetrics;
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -220,20 +220,16 @@ function RTCPeerConnection() {
    * has finished, we will check the queue for the next operation and execute
    * if neccesary. The _pending flag indicates whether an operation is currently
    * in progress.
    */
   this._pending = false;
 
   // States
   this._iceGatheringState = this._iceConnectionState = "new";
-
-  // Deprecated callbacks
-  this._ongatheringchange = null;
-  this._onicechange = null;
 }
 RTCPeerConnection.prototype = {
   classDescription: "mozRTCPeerConnection",
   classID: PC_CID,
   contractID: PC_CONTRACT,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
   init: function(win) { this._win = win; },
@@ -482,54 +478,32 @@ RTCPeerConnection.prototype = {
   makeGetterSetterEH: function(name) {
     Object.defineProperty(this, name,
                           {
                             get:function()  { return this.getEH(name); },
                             set:function(h) { return this.setEH(name, h); }
                           });
   },
 
-  get onicechange()       { return this._onicechange; },
-  get ongatheringchange() { return this._ongatheringchange; },
-
-  set onicechange(cb) {
-    this.deprecated("onicechange");
-    this._onicechange = cb;
-  },
-  set ongatheringchange(cb) {
-    this.deprecated("ongatheringchange");
-    this._ongatheringchange = cb;
-  },
-
-  deprecated: function(name) {
-    this.reportWarning(name + " is deprecated!", null, 0);
-  },
-
   createOffer: function(onSuccess, onError, constraints) {
     if (!constraints) {
       constraints = {};
     }
-    if (!onError) {
-      this.deprecated("calling createOffer without failureCallback");
-    }
     this._mustValidateConstraints(constraints, "createOffer passed invalid constraints");
     this._onCreateOfferSuccess = onSuccess;
     this._onCreateOfferFailure = onError;
 
     this._queueOrRun({ func: this._createOffer, args: [constraints], wait: true });
   },
 
   _createOffer: function(constraints) {
     this._getPC().createOffer(constraints);
   },
 
   _createAnswer: function(onSuccess, onError, constraints, provisional) {
-    if (!onError) {
-      this.deprecated("calling createAnswer without failureCallback");
-    }
     this._onCreateAnswerSuccess = onSuccess;
     this._onCreateAnswerFailure = onError;
 
     if (!this.remoteDescription) {
 
       this._observer.onCreateAnswerError(Ci.IPeerConnection.kInvalidState,
                                          "setRemoteDescription not called");
       return;
@@ -690,26 +664,16 @@ RTCPeerConnection.prototype = {
     return this._getPC().getLocalStreams();
   },
 
   getRemoteStreams: function() {
     this._checkClosed();
     return this._getPC().getRemoteStreams();
   },
 
-  // Backwards-compatible attributes
-  get localStreams() {
-    this.deprecated("localStreams");
-    return this.getLocalStreams();
-  },
-  get remoteStreams() {
-    this.deprecated("remoteStreams");
-    return this.getRemoteStreams();
-  },
-
   get localDescription() {
     this._checkClosed();
     let sdp = this._getPC().localDescription;
     if (sdp.length == 0) {
       return null;
     }
     return new this._win.mozRTCSessionDescription({ type: this._localType,
                                                     sdp: sdp });
@@ -749,45 +713,16 @@ RTCPeerConnection.prototype = {
     this._iceGatheringState = state;
   },
 
   changeIceConnectionState: function(state) {
     this._iceConnectionState = state;
     this.dispatchEvent(new this._win.Event("iceconnectionstatechange"));
   },
 
-  get readyState() {
-    this.deprecated("readyState");
-    // checking for our local pc closed indication
-    // before invoking the pc methods.
-    if(this._closed) {
-      return "closed";
-    }
-
-    var state="undefined";
-    switch (this._getPC().readyState) {
-      case Ci.IPeerConnection.kNew:
-        state = "new";
-        break;
-      case Ci.IPeerConnection.kNegotiating:
-        state = "negotiating";
-        break;
-      case Ci.IPeerConnection.kActive:
-        state = "active";
-        break;
-      case Ci.IPeerConnection.kClosing:
-        state = "closing";
-        break;
-      case Ci.IPeerConnection.kClosed:
-        state = "closed";
-        break;
-    }
-    return state;
-  },
-
   getStats: function(selector, onSuccess, onError) {
     this._onGetStatsSuccess = onSuccess;
     this._onGetStatsFailure = onError;
 
     this._queueOrRun({
       func: this._getStats,
       args: [selector],
       wait: true
@@ -1054,39 +989,33 @@ PeerConnectionObserver.prototype = {
 
   handleIceStateChanges: function(iceState) {
     var histogram = Services.telemetry.getHistogramById("WEBRTC_ICE_SUCCESS_RATE");
 
     const STATE_MAP = {
       IceGathering:
         { gathering: "gathering" },
       IceWaiting:
-        { connection: "new",  gathering: "complete", legacy: "starting" },
+        { connection: "new",  gathering: "complete" },
       IceChecking:
-        { connection: "checking", legacy: "checking" },
+        { connection: "checking" },
       IceConnected:
-        { connection: "connected", legacy: "connected", success: true },
+        { connection: "connected", success: true },
       IceFailed:
-        { connection: "failed", legacy: "failed", success: false }
+        { connection: "failed", success: false }
     };
     // These are all the allowed inputs.
 
     let transitions = STATE_MAP[iceState];
 
     if ("connection" in transitions) {
         this._dompc.changeIceConnectionState(transitions.connection);
     }
     if ("gathering" in transitions) {
       this._dompc.changeIceGatheringState(transitions.gathering);
-      // Handle (old, deprecated) "ongatheringchange" callback
-      this.callCB(this._dompc.ongatheringchange, transitions.gathering);
-    }
-    // Handle deprecated "onicechange" callback
-    if ("legacy" in transitions) {
-      this.callCB(this._onicechange, transitions.legacy);
     }
     if ("success" in transitions) {
       histogram.add(transitions.success);
     }
 
     if (iceState == "IceWaiting") {
       if (!this._dompc._trickleIce) {
         // If we are not trickling, then the queue is in a pending state
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -1308,21 +1308,21 @@ PeerConnectionWrapper.prototype = {
 
   /**
    * Checks that we are getting the media streams we expect.
    *
    * @param {object} constraintsRemote
    *        The media constraints of the remote peer connection object
    */
   checkMediaStreams : function PCW_checkMediaStreams(constraintsRemote) {
-    is(this._pc.localStreams.length, this.constraints.length,
+    is(this._pc.getLocalStreams().length, this.constraints.length,
        this + ' has ' + this.constraints.length + ' local streams');
 
     // TODO: change this when multiple incoming streams are supported (bug 834835)
-    is(this._pc.remoteStreams.length, 1,
+    is(this._pc.getRemoteStreams().length, 1,
        this + ' has ' + 1 + ' remote streams');
   },
 
   /**
    * Check that media flow is present on all media elements involved in this
    * test by waiting for confirmation that media flow is present.
    *
    * @param {Function} onSuccess the success callback when media flow
--- a/dom/mobilemessage/src/MobileMessageService.cpp
+++ b/dom/mobilemessage/src/MobileMessageService.cpp
@@ -2,17 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SmsMessage.h"
 #include "MmsMessage.h"
 #include "MobileMessageThread.h"
 #include "MobileMessageService.h"
 #include "SmsSegmentInfo.h"
-#include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
 NS_IMPL_ISUPPORTS1(MobileMessageService, nsIMobileMessageService)
 
 /* static */ StaticRefPtr<MobileMessageService> MobileMessageService::sSingleton;
--- a/dom/mobilemessage/src/android/MmsService.cpp
+++ b/dom/mobilemessage/src/android/MmsService.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MobileMessageCallback.h"
 #include "MmsService.h"
 #include "AndroidBridge.h"
-#include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
 NS_IMPL_ISUPPORTS1(MmsService, nsIMmsService)
 
 NS_IMETHODIMP
--- a/dom/mobilemessage/src/android/SmsService.cpp
+++ b/dom/mobilemessage/src/android/SmsService.cpp
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SmsMessage.h"
 #include "SmsService.h"
 #include "SmsSegmentInfo.h"
 #include "AndroidBridge.h"
-#include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
 NS_IMPL_ISUPPORTS1(SmsService, nsISmsService)
 
 NS_IMETHODIMP
--- a/dom/mobilemessage/src/fallback/MmsService.cpp
+++ b/dom/mobilemessage/src/fallback/MmsService.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MobileMessageCallback.h"
 #include "MmsService.h"
-#include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
 NS_IMPL_ISUPPORTS1(MmsService, nsIMmsService)
 
 NS_IMETHODIMP
--- a/dom/mobilemessage/src/fallback/SmsService.cpp
+++ b/dom/mobilemessage/src/fallback/SmsService.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SmsMessage.h"
 #include "SmsSegmentInfo.h"
 #include "SmsService.h"
-#include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
 NS_IMPL_ISUPPORTS1(SmsService, nsISmsService)
 
 NS_IMETHODIMP
--- a/dom/mobilemessage/src/gonk/SmsService.cpp
+++ b/dom/mobilemessage/src/gonk/SmsService.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SmsMessage.h"
 #include "SmsService.h"
-#include "jsapi.h"
 #include "SmsSegmentInfo.h"
 #include "mozilla/Preferences.h"
 #include "nsServiceManagerUtils.h"
 
 namespace {
 
 const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
 #define kPrefDefaultServiceId "dom.sms.defaultServiceId"
--- a/dom/mobilemessage/src/ipc/SmsIPCService.cpp
+++ b/dom/mobilemessage/src/ipc/SmsIPCService.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/ContentChild.h"
 #include "SmsIPCService.h"
 #include "nsXULAppAPI.h"
-#include "jsapi.h"
 #include "mozilla/dom/mobilemessage/SmsChild.h"
 #include "SmsMessage.h"
 #include "SmsFilter.h"
 #include "SmsSegmentInfo.h"
 #include "DictionaryHelpers.h"
 #include "nsJSUtils.h"
 #include "nsCxPusher.h"
 #include "mozilla/dom/MobileMessageManagerBinding.h"
--- a/dom/network/src/MobileConnection.cpp
+++ b/dom/network/src/MobileConnection.cpp
@@ -12,17 +12,16 @@
 #include "nsIDOMDataErrorEvent.h"
 #include "nsIDOMMozEmergencyCbModeEvent.h"
 #include "nsIDOMMozOtaStatusEvent.h"
 #include "nsIDOMUSSDReceivedEvent.h"
 #include "nsIPermissionManager.h"
 
 #include "nsJSUtils.h"
 #include "nsJSON.h"
-#include "jsapi.h"
 #include "mozilla/Services.h"
 
 #define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
 
 using namespace mozilla::dom::network;
 
 class MobileConnection::Listener : public nsIMobileConnectionListener
 {
--- a/dom/network/src/TCPServerSocketChild.cpp
+++ b/dom/network/src/TCPServerSocketChild.cpp
@@ -4,17 +4,16 @@
 
 #include "TCPServerSocketChild.h"
 #include "TCPSocketChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "nsIDOMTCPSocket.h"
 #include "nsJSUtils.h"
-#include "jsapi.h"
 #include "jsfriendapi.h"
 
 using mozilla::net::gNeckoChild;
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_1(TCPServerSocketChildBase, mServerSocket)
--- a/dom/network/src/TCPServerSocketParent.cpp
+++ b/dom/network/src/TCPServerSocketParent.cpp
@@ -1,15 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TCPServerSocketParent.h"
-#include "jsapi.h"
-#include "jsfriendapi.h"
 #include "nsJSUtils.h"
 #include "TCPSocketParent.h"
 #include "mozilla/unused.h"
 #include "mozilla/AppProcessChecker.h"
 
 namespace mozilla {
 namespace dom {
 
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
-#include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jswrapper.h"
 
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsJSNPRuntime.h"
 #include "nsNPAPIPlugin.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsIScriptGlobalObject.h"
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -1,13 +1,14 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=4 sw=4 et tw=78: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "jsapi.h"
 #include "jswrapper.h"
 #include "nsCRT.h"
 #include "nsError.h"
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
--- a/dom/webidl/RTCPeerConnection.webidl
+++ b/dom/webidl/RTCPeerConnection.webidl
@@ -82,20 +82,20 @@ interface RTCDataChannel;
 
 [Pref="media.peerconnection.enabled",
  JSImplementation="@mozilla.org/dom/peerconnection;1",
  Constructor (optional RTCConfiguration configuration,
               optional object? constraints)]
 // moz-prefixed until sufficiently standardized.
 interface mozRTCPeerConnection : EventTarget  {
   void createOffer (RTCSessionDescriptionCallback successCallback,
-                    RTCPeerConnectionErrorCallback? failureCallback, // for apprtc
+                    RTCPeerConnectionErrorCallback failureCallback,
                     optional MediaConstraints constraints);
   void createAnswer (RTCSessionDescriptionCallback successCallback,
-                     RTCPeerConnectionErrorCallback? failureCallback, // for apprtc
+                     RTCPeerConnectionErrorCallback failureCallback,
                      optional MediaConstraints constraints);
   void setLocalDescription (mozRTCSessionDescription description,
                             optional VoidFunction successCallback,
                             optional RTCPeerConnectionErrorCallback failureCallback);
   void setRemoteDescription (mozRTCSessionDescription description,
                              optional VoidFunction successCallback,
                              optional RTCPeerConnectionErrorCallback failureCallback);
   readonly attribute mozRTCSessionDescription? localDescription;
@@ -119,28 +119,16 @@ interface mozRTCPeerConnection : EventTa
   attribute EventHandler onsignalingstatechange;
   attribute EventHandler onaddstream;
   attribute EventHandler onremovestream;
   attribute EventHandler oniceconnectionstatechange;
 
   void getStats (MediaStreamTrack? selector,
                  RTCStatsCallback successCallback,
                  RTCPeerConnectionErrorCallback failureCallback);
-};
-
-// Mozilla extensions.
-partial interface mozRTCPeerConnection {
-  // Deprecated callbacks (use causes warning)
-  attribute RTCPeerConnectionErrorCallback onicechange;
-  attribute RTCPeerConnectionErrorCallback ongatheringchange;
-
-  // Deprecated attributes (use causes warning)
-  readonly attribute object localStreams;
-  readonly attribute object remoteStreams;
-  readonly attribute DOMString readyState;
 
   // Data channel.
   RTCDataChannel createDataChannel (DOMString label,
                                     optional RTCDataChannelInit dataChannelDict);
   attribute EventHandler ondatachannel;
   attribute EventHandler onconnection;
   attribute EventHandler onclosedconnection;
 };
--- a/dom/wifi/WifiCommand.jsm
+++ b/dom/wifi/WifiCommand.jsm
@@ -10,17 +10,17 @@ this.EXPORTED_SYMBOLS = ["WifiCommand"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/systemlibs.js");
 
 const SUPP_PROP = "init.svc.wpa_supplicant";
 const WPA_SUPPLICANT = "wpa_supplicant";
 
-this.WifiCommand = function(controlMessage) {
+this.WifiCommand = function(aControlMessage, aInterface) {
   var command = {};
 
   //-------------------------------------------------
   // General commands.
   //-------------------------------------------------
 
   command.loadDriver = function (callback) {
     voidControlMessage("load_driver", function(status) {
@@ -332,26 +332,27 @@ this.WifiCommand = function(controlMessa
     });
   };
 
   //--------------------------------------------------
   // Helper functions.
   //--------------------------------------------------
 
   function voidControlMessage(cmd, callback) {
-    controlMessage({ cmd: cmd }, function (data) {
+    aControlMessage({ cmd: cmd, iface: aInterface }, function (data) {
       callback(data.status);
     });
   }
 
   function doCommand(request, callback) {
     var msg = { cmd:     "command",
-                request: request };
+                request: request,
+                iface:   aInterface };
 
-    controlMessage(msg, callback);
+    aControlMessage(msg, callback);
   }
 
   function doIntCommand(request, callback) {
     doCommand(request, function(data) {
       callback(data.status ? -1 : (data.reply|0));
     });
   }
 
--- a/dom/wifi/WifiProxyService.cpp
+++ b/dom/wifi/WifiProxyService.cpp
@@ -3,80 +3,87 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WifiProxyService.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/ModuleUtils.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "nsXULAppAPI.h"
 #include "WifiUtils.h"
-#include "jsapi.h"
 #include "nsCxPusher.h"
 
 #define NS_WIFIPROXYSERVICE_CID \
   { 0xc6c9be7e, 0x744f, 0x4222, {0xb2, 0x03, 0xcd, 0x55, 0xdf, 0xc8, 0xbc, 0x12} }
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 // The singleton Wifi service, to be used on the main thread.
-StaticRefPtr<WifiProxyService> gWifiProxyService;
+static StaticRefPtr<WifiProxyService> gWifiProxyService;
 
 // The singleton supplicant class, that can be used on any thread.
 static nsAutoPtr<WpaSupplicant> gWpaSupplicant;
 
 // Runnable used dispatch the WaitForEvent result on the main thread.
 class WifiEventDispatcher : public nsRunnable
 {
 public:
-  WifiEventDispatcher(nsAString& aEvent): mEvent(aEvent)
+  WifiEventDispatcher(const nsAString& aEvent, const nsACString& aInterface)
+    : mEvent(aEvent)
+    , mInterface(aInterface)
   {
     MOZ_ASSERT(!NS_IsMainThread());
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
-    gWifiProxyService->DispatchWifiEvent(mEvent);
+    gWifiProxyService->DispatchWifiEvent(mEvent, mInterface);
     return NS_OK;
   }
 
 private:
   nsString mEvent;
+  nsCString mInterface;
 };
 
 // Runnable used to call WaitForEvent on the event thread.
 class EventRunnable : public nsRunnable
 {
 public:
-  EventRunnable()
+  EventRunnable(const nsACString& aInterface)
+    : mInterface(aInterface)
   {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(!NS_IsMainThread());
     nsAutoString event;
-    gWpaSupplicant->WaitForEvent(event);
+    gWpaSupplicant->WaitForEvent(event, mInterface);
     if (!event.IsEmpty()) {
-      nsCOMPtr<nsIRunnable> runnable = new WifiEventDispatcher(event);
+      nsCOMPtr<nsIRunnable> runnable = new WifiEventDispatcher(event, mInterface);
       NS_DispatchToMainThread(runnable);
     }
     return NS_OK;
   }
+
+private:
+  nsCString mInterface;
 };
 
 // Runnable used dispatch the Command result on the main thread.
 class WifiResultDispatcher : public nsRunnable
 {
 public:
-  WifiResultDispatcher(WifiResultOptions& aResult)
+  WifiResultDispatcher(WifiResultOptions& aResult, const nsACString& aInterface)
+    : mInterface(aInterface)
   {
     MOZ_ASSERT(!NS_IsMainThread());
 
     // XXX: is there a better way to copy webidl dictionnaries?
     // the copy constructor is private.
 #define COPY_FIELD(prop) mResult.prop = aResult.prop;
 
     COPY_FIELD(mId)
@@ -102,43 +109,48 @@ public:
     COPY_FIELD(mServer)
 
 #undef COPY_FIELD
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
-    gWifiProxyService->DispatchWifiResult(mResult);
+    gWifiProxyService->DispatchWifiResult(mResult, mInterface);
     return NS_OK;
   }
 
 private:
   WifiResultOptions mResult;
+  nsCString mInterface;
 };
 
 // Runnable used to call SendCommand on the control thread.
 class ControlRunnable : public nsRunnable
 {
 public:
-  ControlRunnable(CommandOptions aOptions) : mOptions(aOptions) {
+  ControlRunnable(CommandOptions aOptions, const nsACString& aInterface)
+    : mOptions(aOptions)
+    , mInterface(aInterface)
+  {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
   NS_IMETHOD Run()
   {
     WifiResultOptions result;
-    if (gWpaSupplicant->ExecuteCommand(mOptions, result)) {
-      nsCOMPtr<nsIRunnable> runnable = new WifiResultDispatcher(result);
+    if (gWpaSupplicant->ExecuteCommand(mOptions, result, mInterface)) {
+      nsCOMPtr<nsIRunnable> runnable = new WifiResultDispatcher(result, mInterface);
       NS_DispatchToMainThread(runnable);
     }
     return NS_OK;
   }
 private:
    CommandOptions mOptions;
+   nsCString mInterface;
 };
 
 NS_IMPL_ISUPPORTS1(WifiProxyService, nsIWifiProxyService)
 
 WifiProxyService::WifiProxyService()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!gWifiProxyService);
@@ -166,102 +178,128 @@ WifiProxyService::FactoryCreate()
     ClearOnShutdown(&gWpaSupplicant);
   }
 
   nsRefPtr<WifiProxyService> service = gWifiProxyService.get();
   return service.forget();
 }
 
 NS_IMETHODIMP
-WifiProxyService::Start(nsIWifiEventListener* aListener)
+WifiProxyService::Start(nsIWifiEventListener* aListener,
+                        const char ** aInterfaces,
+                        uint32_t aNumOfInterfaces)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aListener);
 
-  nsresult rv = NS_NewThread(getter_AddRefs(mEventThread));
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Can't create wifi event thread");
-    return NS_ERROR_FAILURE;
+  nsresult rv;
+
+  // Since EventRunnable runs in the manner of blocking, we have to
+  // spin a thread for each interface.
+  // (See the WpaSupplicant::WaitForEvent)
+  mEventThreadList.SetLength(aNumOfInterfaces);
+  for (uint32_t i = 0; i < aNumOfInterfaces; i++) {
+    mEventThreadList[i].mInterface = aInterfaces[i];
+    rv = NS_NewThread(getter_AddRefs(mEventThreadList[i].mThread));
+    if (NS_FAILED(rv)) {
+      NS_WARNING("Can't create wifi event thread");
+      Shutdown();
+      return NS_ERROR_FAILURE;
+    }
   }
 
   rv = NS_NewThread(getter_AddRefs(mControlThread));
   if (NS_FAILED(rv)) {
     NS_WARNING("Can't create wifi control thread");
-    // Shutdown the event thread.
-    mEventThread->Shutdown();
-    mEventThread = nullptr;
+    Shutdown();
     return NS_ERROR_FAILURE;
   }
 
   mListener = aListener;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WifiProxyService::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  mEventThread->Shutdown();
-  mEventThread = nullptr;
-  mControlThread->Shutdown();
-  mControlThread = nullptr;
+  for (size_t i = 0; i < mEventThreadList.Length(); i++) {
+    if (mEventThreadList[i].mThread) {
+      mEventThreadList[i].mThread->Shutdown();
+      mEventThreadList[i].mThread = nullptr;
+    }
+  }
+  mEventThreadList.Clear();
+  if (mControlThread) {
+    mControlThread->Shutdown();
+    mControlThread = nullptr;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-WifiProxyService::SendCommand(const JS::Value& aOptions, JSContext* aCx)
+WifiProxyService::SendCommand(const JS::Value& aOptions, const nsACString& aInterface,
+                              JSContext* aCx)
 {
   MOZ_ASSERT(NS_IsMainThread());
   WifiCommandOptions options;
 
   if (!options.Init(aCx,
                     JS::Handle<JS::Value>::fromMarkedLocation(&aOptions))) {
     NS_WARNING("Bad dictionary passed to WifiProxyService::SendCommand");
     return NS_ERROR_FAILURE;
   }
 
   // Dispatch the command to the control thread.
   CommandOptions commandOptions(options);
-  nsCOMPtr<nsIRunnable> runnable = new ControlRunnable(commandOptions);
+  nsCOMPtr<nsIRunnable> runnable = new ControlRunnable(commandOptions, aInterface);
   mControlThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-WifiProxyService::WaitForEvent()
+WifiProxyService::WaitForEvent(const nsACString& aInterface)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  nsCOMPtr<nsIRunnable> runnable = new EventRunnable();
-  mEventThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
-  return NS_OK;
+
+  // Dispatch to the event thread which has the given interface name
+  for (size_t i = 0; i < mEventThreadList.Length(); i++) {
+    if (mEventThreadList[i].mInterface.Equals(aInterface)) {
+      nsCOMPtr<nsIRunnable> runnable = new EventRunnable(aInterface);
+      mEventThreadList[i].mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
+      return NS_OK;
+    }
+  }
+
+  return NS_ERROR_FAILURE;
 }
 
 void
-WifiProxyService::DispatchWifiResult(const WifiResultOptions& aOptions)
+WifiProxyService::DispatchWifiResult(const WifiResultOptions& aOptions, const nsACString& aInterface)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mozilla::AutoSafeJSContext cx;
   JS::RootedValue val(cx);
 
   if (!aOptions.ToObject(cx, JS::NullPtr(), &val)) {
     return;
   }
 
   // Call the listener with a JS value.
-  mListener->OnCommand(val);
+  mListener->OnCommand(val, aInterface);
 }
 
 void
-WifiProxyService::DispatchWifiEvent(const nsAString& aEvent)
+WifiProxyService::DispatchWifiEvent(const nsAString& aEvent, const nsACString& aInterface)
 {
   MOZ_ASSERT(NS_IsMainThread());
   // Call the listener.
-  mListener->OnWaitEvent(aEvent);
+  mListener->OnWaitEvent(aEvent, aInterface);
 }
 
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WifiProxyService,
                                          WifiProxyService::FactoryCreate)
 
 NS_DEFINE_NAMED_CID(NS_WIFIPROXYSERVICE_CID);
 
 static const mozilla::Module::CIDEntry kWifiProxyServiceCIDs[] = {
--- a/dom/wifi/WifiProxyService.h
+++ b/dom/wifi/WifiProxyService.h
@@ -4,35 +4,44 @@
 
 #ifndef WifiProxyService_h
 #define WifiProxyService_h
 
 #include "nsIWifiService.h"
 #include "nsCOMPtr.h"
 #include "nsThread.h"
 #include "mozilla/dom/WifiOptionsBinding.h"
+#include "nsTArray.h"
 
 namespace mozilla {
 
 class WifiProxyService MOZ_FINAL : public nsIWifiProxyService
 {
+private:
+  struct EventThreadListEntry
+  {
+    nsCOMPtr<nsIThread> mThread;
+    nsCString mInterface;
+  };
+
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIWIFIPROXYSERVICE
 
   static already_AddRefed<WifiProxyService>
   FactoryCreate();
 
-  void DispatchWifiEvent(const nsAString& aEvent);
-  void DispatchWifiResult(const mozilla::dom::WifiResultOptions& aOptions);
+  void DispatchWifiEvent(const nsAString& aEvent, const nsACString& aInterface);
+  void DispatchWifiResult(const mozilla::dom::WifiResultOptions& aOptions,
+                          const nsACString& aInterface);
 
 private:
   WifiProxyService();
   ~WifiProxyService();
 
-  nsCOMPtr<nsIThread> mEventThread;
+  nsTArray<EventThreadListEntry> mEventThreadList;
   nsCOMPtr<nsIThread> mControlThread;
   nsCOMPtr<nsIWifiEventListener> mListener;
 };
 
 } // namespace mozilla
 
 #endif // WifiProxyService_h
--- a/dom/wifi/WifiUtils.cpp
+++ b/dom/wifi/WifiUtils.cpp
@@ -216,22 +216,22 @@ WpaSupplicant::WpaSupplicant()
   if (NetUtils::SdkVersion() < 16) {
     mImpl = new ICSWpaSupplicantImpl();
   } else {
     mImpl = new JBWpaSupplicantImpl();
   }
   mNetUtils = new NetUtils();
 };
 
-void WpaSupplicant::WaitForEvent(nsAString& aEvent)
+void WpaSupplicant::WaitForEvent(nsAString& aEvent, const nsCString& aInterface)
 {
   CHECK_HWLIB()
 
   char buffer[BUFFER_SIZE];
-  int32_t ret = mImpl->do_wifi_wait_for_event("wlan0", buffer, BUFFER_SIZE);
+  int32_t ret = mImpl->do_wifi_wait_for_event(aInterface.get(), buffer, BUFFER_SIZE);
   CheckBuffer(buffer, ret, aEvent);
 }
 
 #define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aOptions.prop).get()
 
 /**
  * Make a subnet mask.
  */
@@ -239,52 +239,53 @@ uint32_t WpaSupplicant::MakeMask(uint32_
   uint32_t mask = 0;
   for (uint32_t i = 0; i < len; ++i) {
     mask |= (0x80000000 >> i);
   }
   return ntohl(mask);
 }
 
 bool WpaSupplicant::ExecuteCommand(CommandOptions aOptions,
-                                   WifiResultOptions& aResult)
+                                   WifiResultOptions& aResult,
+                                   const nsCString& aInterface)
 {
   CHECK_HWLIB(false)
   if (!mNetUtils->GetSharedLibrary()) {
     return false;
   }
 
   // Always correlate the opaque ids.
   aResult.mId = aOptions.mId;
 
   if (aOptions.mCmd.EqualsLiteral("command")) {
     size_t len = BUFFER_SIZE - 1;
     char buffer[BUFFER_SIZE];
     NS_ConvertUTF16toUTF8 request(aOptions.mRequest);
-    aResult.mStatus = mImpl->do_wifi_command("wlan0", request.get(), buffer, &len);
+    aResult.mStatus = mImpl->do_wifi_command(aInterface.get(), request.get(), buffer, &len);
     nsString value;
     if (aResult.mStatus == 0) {
       if (buffer[len - 1] == '\n') { // remove trailing new lines.
         len--;
       }
       buffer[len] = '\0';
       CheckBuffer(buffer, len, value);
     }
     aResult.mReply = value;
   } else if (aOptions.mCmd.EqualsLiteral("close_supplicant_connection")) {
-    mImpl->do_wifi_close_supplicant_connection("wlan0");
+    mImpl->do_wifi_close_supplicant_connection(aInterface.get());
   } else if (aOptions.mCmd.EqualsLiteral("load_driver")) {
     aResult.mStatus = mImpl->do_wifi_load_driver();
   } else if (aOptions.mCmd.EqualsLiteral("unload_driver")) {
     aResult.mStatus = mImpl->do_wifi_unload_driver();
   } else if (aOptions.mCmd.EqualsLiteral("start_supplicant")) {
     aResult.mStatus = mImpl->do_wifi_start_supplicant(0);
   } else if (aOptions.mCmd.EqualsLiteral("stop_supplicant")) {
     aResult.mStatus = mImpl->do_wifi_stop_supplicant();
   } else if (aOptions.mCmd.EqualsLiteral("connect_to_supplicant")) {
-    aResult.mStatus = mImpl->do_wifi_connect_to_supplicant("wlan0");
+    aResult.mStatus = mImpl->do_wifi_connect_to_supplicant(aInterface.get());
   } else if (aOptions.mCmd.EqualsLiteral("ifc_enable")) {
     aResult.mStatus = mNetUtils->do_ifc_enable(GET_CHAR(mIfname));
   } else if (aOptions.mCmd.EqualsLiteral("ifc_disable")) {
     aResult.mStatus = mNetUtils->do_ifc_disable(GET_CHAR(mIfname));
   } else if (aOptions.mCmd.EqualsLiteral("ifc_configure")) {
     aResult.mStatus = mNetUtils->do_ifc_configure(
       GET_CHAR(mIfname), aOptions.mIpaddr, aOptions.mMask,
       aOptions.mGateway, aOptions.mDns1, aOptions.mDns2
--- a/dom/wifi/WifiUtils.h
+++ b/dom/wifi/WifiUtils.h
@@ -81,16 +81,19 @@ public:
 };
 
 // Abstract class that exposes libhardware_legacy functions we need for
 // wifi management.
 // We use the ICS signatures here since they are likely more future-proof.
 class WpaSupplicantImpl
 {
 public:
+  // Suppress warning from nsAutoPtr
+  virtual ~WpaSupplicantImpl() {}
+
   virtual int32_t
   do_wifi_wait_for_event(const char *iface, char *buf, size_t len) = 0; // ICS != JB
 
   virtual int32_t
   do_wifi_command(const char* iface, const char* cmd, char* buff, size_t* len) = 0; // ICS != JB
 
   virtual int32_t
   do_wifi_load_driver() = 0;
@@ -112,19 +115,23 @@ public:
 };
 
 // Concrete class to use to access the wpa supplicant.
 class WpaSupplicant MOZ_FINAL
 {
 public:
   WpaSupplicant();
 
-  void WaitForEvent(nsAString& aEvent);
+  // Use nsCString as the type of aInterface to guarantee it's
+  // null-terminated so that we can pass it to c API without
+  // conversion
+  void WaitForEvent(nsAString& aEvent, const nsCString& aInterface);
   bool ExecuteCommand(CommandOptions aOptions,
-                      mozilla::dom::WifiResultOptions& result);
+                      mozilla::dom::WifiResultOptions& result,
+                      const nsCString& aInterface);
 
 private:
   nsAutoPtr<WpaSupplicantImpl> mImpl;
   nsAutoPtr<NetUtils> mNetUtils;
 
 protected:
   void CheckBuffer(char* buffer, int32_t length, nsAString& aEvent);
   uint32_t MakeMask(uint32_t len);
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -91,87 +91,90 @@ XPCOMUtils.defineLazyServiceGetter(this,
 // A note about errors and error handling in this file:
 // The libraries that we use in this file are intended for C code. For
 // C code, it is natural to return -1 for errors and 0 for success.
 // Therefore, the code that interacts directly with the worker uses this
 // convention (note: command functions do get boolean results since the
 // command always succeeds and we do a string/boolean check for the
 // expected results).
 var WifiManager = (function() {
+  var manager = {};
+
   function getStartupPrefs() {
     return {
       sdkVersion: parseInt(libcutils.property_get("ro.build.version.sdk"), 10),
       unloadDriverEnabled: libcutils.property_get("ro.moz.wifi.unloaddriver") === "1",
       schedScanRecovery: libcutils.property_get("ro.moz.wifi.sched_scan_recover") === "false" ? false : true,
       driverDelay: libcutils.property_get("ro.moz.wifi.driverDelay"),
       ifname: libcutils.property_get("wifi.interface")
     };
   }
 
   let {sdkVersion, unloadDriverEnabled, schedScanRecovery, driverDelay, ifname} = getStartupPrefs();
 
   let wifiListener = {
-    onWaitEvent: function(event) {
-      if (handleEvent(event)) {
-        waitForEvent();
+    onWaitEvent: function(event, iface) {
+      if (manager.ifname === iface && handleEvent(event)) {
+        waitForEvent(iface);
       }
     },
 
-    onCommand: function(event) {
-      onmessageresult(event);
+    onCommand: function(event, iface) {
+      onmessageresult(event, iface);
     }
   }
 
-  let wifiService = Cc["@mozilla.org/wifi/service;1"];
-  if (wifiService) {
-    wifiService = wifiService.getService(Ci.nsIWifiProxyService);
-    wifiService.start(wifiListener);
-  } else {
-    debug("No wifi service component available!");
-  }
-
-  var manager = {};
   manager.ifname = ifname;
   // Emulator build runs to here.
   // The debug() should only be used after WifiManager.
   if (!ifname) {
     manager.ifname = DEFAULT_WLAN_INTERFACE;
   }
   manager.schedScanRecovery = schedScanRecovery;
   manager.driverDelay = driverDelay ? parseInt(driverDelay, 10) : DRIVER_READY_WAIT;
 
-  var wifiCommand = WifiCommand(controlMessage);
+  let wifiService = Cc["@mozilla.org/wifi/service;1"];
+  if (wifiService) {
+    wifiService = wifiService.getService(Ci.nsIWifiProxyService);
+    let interfaces = [manager.ifname];
+    wifiService.start(wifiListener, interfaces, interfaces.length);
+  } else {
+    debug("No wifi service component available!");
+  }
+
+  var wifiCommand = WifiCommand(controlMessage, manager.ifname);
   var netUtil = WifiNetUtil(controlMessage);
 
   // Callbacks to invoke when a reply arrives from the wifi service.
   var controlCallbacks = Object.create(null);
   var idgen = 0;
 
   function controlMessage(obj, callback) {
     var id = idgen++;
     obj.id = id;
-    if (callback)
+    if (callback) {
       controlCallbacks[id] = callback;
-    wifiService.sendCommand(obj);
+    }
+    wifiService.sendCommand(obj, obj.iface);
   }
 
-  let onmessageresult = function(data) {
+  let onmessageresult = function(data, iface) {
     var id = data.id;
     var callback = controlCallbacks[id];
     if (callback) {
       callback(data);
       delete controlCallbacks[id];
     }
   }
 
   // Polling the status worker
   var recvErrors = 0;
 
-  function waitForEvent() {
-    wifiService.waitForEvent();
+  function waitForEvent(iface) {
+    wifiService.waitForEvent(iface);
   }
 
   // Commands to the control worker.
 
   var driverLoaded = false;
 
   function loadDriver(callback) {
     if (driverLoaded) {
@@ -750,17 +753,17 @@ var WifiManager = (function() {
       notifyStateChange({ state: "WPS_OVERLAP_DETECTED", BSSID: null, id: -1 });
       return true;
     }
     // Unknown event.
     return true;
   }
 
   function didConnectSupplicant(callback) {
-    waitForEvent();
+    waitForEvent(manager.ifname);
 
     // Load up the supplicant state.
     getDebugEnabled(function(ok) {
       syncDebug();
     });
     wifiCommand.status(function(status) {
       parseStatus(status);
       notify("supplicantconnection");
--- a/dom/wifi/nsIWifiService.idl
+++ b/dom/wifi/nsIWifiService.idl
@@ -1,20 +1,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/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(e3d54c8d-b1c7-4ed5-b760-e26d3075e3e5)]
+[scriptable, uuid(4d4389e0-1547-11e3-8ffd-0800200c9a66)]
 interface nsIWifiEventListener : nsISupports {
-  void onWaitEvent(in AString event);
-  void onCommand(in jsval result);
+  void onWaitEvent(in AString event, in ACString aInterface);
+  void onCommand(in jsval result, in ACString aInterface);
 };
 
-[scriptable, uuid(ac5ebae6-ec72-4212-89cb-cd25ed5a1b46)]
+[scriptable, uuid(5e2bd8c0-1547-11e3-8ffd-0800200c9a66)]
 interface nsIWifiProxyService : nsISupports {
-  void start(in nsIWifiEventListener listener);
+  void start(in nsIWifiEventListener listener,
+             [array, size_is(aNumOfInterface)] in string aInterfaces,
+             in unsigned long aNumOfInterface);
   void shutdown();
   [implicit_jscontext]
-  void sendCommand(in jsval parameters);
-  void waitForEvent();
+  void sendCommand(in jsval parameters, in ACString aInterface);
+  void waitForEvent(in ACString aInterface);
 };
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -370,17 +370,17 @@ class TenuredHeap : public js::HeapBase<
  * rooted. See "Move GC Stack Rooting" above.
  *
  * If you want to add additional methods to Handle for a specific
  * specialization, define a HandleBase<T> specialization containing them.
  */
 template <typename T>
 class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
 {
-    friend class MutableHandle<T>;
+    friend class JS::MutableHandle<T>;
 
   public:
     /* Creates a handle from a handle of a type convertible to T. */
     template <typename S>
     Handle(Handle<S> handle,
            typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0)
     {
         static_assert(sizeof(Handle<T>) == sizeof(T *),
--- a/js/src/TraceLogging.cpp
+++ b/js/src/TraceLogging.cpp
@@ -8,17 +8,16 @@
 
 #include <cstdarg>
 #include <cstdio>
 #include <cstdlib>
 #include <stdint.h>
 #include <string.h>
 #include <unistd.h>
 
-#include "jsapi.h"
 #include "jsscript.h"
 
 using namespace js;
 
 #ifndef TRACE_LOG_DIR
 # if defined(_WIN32)
 #  define TRACE_LOG_DIR ""
 # else
--- a/js/src/builtin/ParallelArray.cpp
+++ b/js/src/builtin/ParallelArray.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "builtin/ParallelArray.h"
 
-#include "jsapi.h"
 #include "jsobj.h"
 
 #include "vm/GlobalObject.h"
 #include "vm/String.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
--- a/js/src/devtools/Instruments.cpp
+++ b/js/src/devtools/Instruments.cpp
@@ -1,19 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Instruments.h"
 
 #ifdef __APPLE__
 
-#include "jsapi.h"
 #include <dlfcn.h>
 #include <CoreFoundation/CoreFoundation.h>
+#include <unistd.h>
 
 // There are now 2 paths to the DTPerformanceSession framework. We try to load
 // the one contained in /Applications/Xcode.app first, falling back to the one
 // contained in /Library/Developer/4.0/Instruments.
 #define DTPerformanceLibraryPath "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/DTPerformanceSession.framework/Versions/Current/DTPerformanceSession"
 #define OldDTPerformanceLibraryPath "/Library/Developer/4.0/Instruments/Frameworks/DTPerformanceSession.framework/Versions/Current/DTPerformanceSession"
 
 extern "C" {
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -10,17 +10,16 @@
 
 #include "mozilla/PodOperations.h"
 
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
 
-#include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsexn.h"
 #include "jsnum.h"
 #include "jsworkers.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "js/CharacterEncoding.h"
--- a/js/src/gc/Iteration.cpp
+++ b/js/src/gc/Iteration.cpp
@@ -1,15 +1,14 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "jsapi.h"
 #include "jscompartment.h"
 #include "jsgc.h"
 
 #include "gc/GCInternals.h"
 #include "js/HashTable.h"
 #include "vm/Runtime.h"
 
 #include "jsgcinlines.h"
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #ifdef MOZ_VALGRIND
 # include <valgrind/memcheck.h>
 #endif
 
-#include "jsapi.h"
 #include "jscntxt.h"
 #include "jsgc.h"
 #include "jsonparser.h"
 #include "jsprf.h"
 #include "jstypes.h"
 #include "jswatchpoint.h"
 
 #include "builtin/MapObject.h"
--- a/js/src/jit-test/tests/TypedObject/bug920463.js
+++ b/js/src/jit-test/tests/TypedObject/bug920463.js
@@ -1,10 +1,10 @@
 if (!this.hasOwnProperty("TypedObject"))
-  throw new TypeError();
+  quit();
 
 var StructType = TypedObject.StructType;
 var float64 = TypedObject.float64;
 
 var PointType3 = new StructType({ x: float64, y: float64});
 function xPlusY(p) {
   return p.x + p.y;
 }
--- a/js/src/jsapi-tests/testIntTypesABI.cpp
+++ b/js/src/jsapi-tests/testIntTypesABI.cpp
@@ -4,17 +4,16 @@
 
 /*
  * This test exercises the full, deliberately-exposed JSAPI interface to ensure
  * that no internal integer typedefs leak out.  Include every intentionally
  * public header file (and those headers included by them, for completeness),
  * even the ones tests.h itself included, to verify this.
  */
 
-#include "jsapi.h"
 #include "jscpucfg.h"
 #include "jspubtd.h"
 #include "jstypes.h"
 
 #include "js/Anchor.h"
 #include "js/CallArgs.h"
 #include "js/CharacterEncoding.h"
 #include "js/Class.h"
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -7,17 +7,16 @@
 /* JavaScript iterators. */
 
 #include "jsiter.h"
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Util.h"
 
-#include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsgc.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsproxy.h"
 #include "jsscript.h"
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -22,17 +22,16 @@
 
 #ifdef HAVE_LOCALECONV
 #include <locale.h>
 #endif
 #include <math.h>
 #include <string.h>
 
 #include "double-conversion.h"
-#include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsdtoa.h"
 #include "jsobj.h"
 #include "jsstr.h"
 #include "jstypes.h"
 
 #include "vm/GlobalObject.h"
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -3,17 +3,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "json.h"
 
 #include "mozilla/FloatingPoint.h"
 
-#include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsonparser.h"
 #include "jsstr.h"
 #include "jstypes.h"
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jswrapper.h"
 
-#include "jsapi.h"
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsexn.h"
 #include "jsgc.h"
 #include "jsiter.h"
 
 #include "vm/ErrorObject.h"
 #include "vm/WrapperObject.h"
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "vm/Debugger-inl.h"
 
-#include "jsapi.h"
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jswrapper.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "gc/Marking.h"
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -11,17 +11,16 @@
 #include "vm/Interpreter-inl.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/PodOperations.h"
 
 #include <string.h>
 
-#include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsautooplen.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsiter.h"
 #include "jslibmath.h"
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -87,18 +87,17 @@ InefficientNonFlatteningStringHashPolicy
         c2 = ownedChars2;
     }
 
     return PodEqual(c1, c2, k->length());
 }
 
 } // namespace js
 
-namespace JS
-{
+namespace JS {
 
 NotableStringInfo::NotableStringInfo()
     : bufferSize(0),
       buffer(0)
 {}
 
 NotableStringInfo::NotableStringInfo(JSString *str, const StringInfo &info)
     : StringInfo(info)
@@ -242,16 +241,22 @@ StatsArenaCallback(JSRuntime *rt, void *
 }
 
 static CompartmentStats *
 GetCompartmentStats(JSCompartment *comp)
 {
     return static_cast<CompartmentStats *>(comp->compartmentStats);
 }
 
+enum Granularity {
+    FineGrained,    // Corresponds to CollectRuntimeStats()
+    CoarseGrained   // Corresponds to AddSizeOfTab()
+};
+
+template <Granularity granularity>
 static void
 StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKind,
                   size_t thingSize)
 {
     StatsClosure *closure = static_cast<StatsClosure *>(data);
     RuntimeStats *rtStats = closure->rtStats;
     ZoneStats *zStats = rtStats->currZoneStats;
     switch (traceKind) {
@@ -278,26 +283,31 @@ StatsCellCallback(JSRuntime *rt, void *d
       }
 
       case JSTRACE_STRING: {
         JSString *str = static_cast<JSString *>(thing);
 
         size_t strCharsSize = str->sizeOfExcludingThis(rtStats->mallocSizeOf_);
         MOZ_ASSERT_IF(str->isShort(), strCharsSize == 0);
 
-        size_t shortStringThingSize = str->isShort() ? thingSize : 0;
+        size_t shortStringThingSize  =  str->isShort() ? thingSize : 0;
         size_t normalStringThingSize = !str->isShort() ? thingSize : 0;
 
-        ZoneStats::StringsHashMap::AddPtr p = zStats->strings.lookupForAdd(str);
-        if (!p) {
-            JS::StringInfo info(str->length(), shortStringThingSize,
-                                normalStringThingSize, strCharsSize);
-            zStats->strings.add(p, str, info);
-        } else {
-            p->value.add(shortStringThingSize, normalStringThingSize, strCharsSize);
+        // This string hashing is expensive.  Its results are unused when doing
+        // coarse-grained measurements, and skipping it more than doubles the
+        // profile speed for complex pages such as gmail.com.
+        if (granularity == FineGrained) {
+            ZoneStats::StringsHashMap::AddPtr p = zStats->strings.lookupForAdd(str);
+            if (!p) {
+                JS::StringInfo info(str->length(), shortStringThingSize,
+                                    normalStringThingSize, strCharsSize);
+                zStats->strings.add(p, str, info);
+            } else {
+                p->value.add(shortStringThingSize, normalStringThingSize, strCharsSize);
+            }
         }
 
         zStats->stringsShortGCHeap += shortStringThingSize;
         zStats->stringsNormalGCHeap += normalStringThingSize;
         zStats->stringsNormalMallocHeap += strCharsSize;
 
         break;
       }
@@ -439,17 +449,17 @@ JS::CollectRuntimeStats(JSRuntime *rt, R
     IterateChunks(rt, &rtStats->gcHeapDecommittedArenas,
                   DecommittedArenasChunkCallback);
 
     // Take the per-compartment measurements.
     StatsClosure closure(rtStats, opv);
     if (!closure.init())
         return false;
     IterateZonesCompartmentsArenasCells(rt, &closure, StatsZoneCallback, StatsCompartmentCallback,
-                                        StatsArenaCallback, StatsCellCallback);
+                                        StatsArenaCallback, StatsCellCallback<FineGrained>);
 
     // Take the "explicit/js/runtime/" measurements.
     rt->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &rtStats->runtime);
 
     for (size_t i = 0; i < rtStats->zoneStatsVector.length(); i++) {
         ZoneStats &zStats = rtStats->zoneStatsVector[i];
 
         rtStats->zTotals.add(zStats);
@@ -559,17 +569,17 @@ AddSizeOfTab(JSRuntime *rt, JSObject *ob
         return false;
 
     // Take the per-compartment measurements.
     StatsClosure closure(&rtStats, opv);
     if (!closure.init())
         return false;
     IterateZoneCompartmentsArenasCells(rt, zone, &closure, StatsZoneCallback,
                                        StatsCompartmentCallback, StatsArenaCallback,
-                                       StatsCellCallback);
+                                       StatsCellCallback<CoarseGrained>);
 
     JS_ASSERT(rtStats.zoneStatsVector.length() == 1);
     rtStats.zTotals.add(rtStats.zoneStatsVector[0]);
 
     for (size_t i = 0; i < rtStats.compartmentStatsVector.length(); i++) {
         CompartmentStats &cStats = rtStats.compartmentStatsVector[i];
         rtStats.cTotals.add(cStats);
     }
--- a/js/src/vm/OldDebugAPI.cpp
+++ b/js/src/vm/OldDebugAPI.cpp
@@ -7,17 +7,16 @@
 /*
  * JS debugging API.
  */
 
 #include "js/OldDebugAPI.h"
 
 #include <string.h>
 
-#include "jsapi.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsprf.h"
 #include "jsscript.h"
 #include "jsstr.h"
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -7,17 +7,16 @@
 /* JS symbol tables. */
 
 #include "vm/Shape-inl.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/PodOperations.h"
 
-#include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsobj.h"
 
 #include "js/HashTable.h"
 
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
--- a/js/xpconnect/public/xpc_map_end.h
+++ b/js/xpconnect/public/xpc_map_end.h
@@ -8,16 +8,18 @@
 #ifndef XPC_MAP_CLASSNAME
 #error "Must #define XPC_MAP_CLASSNAME before #including xpc_map_end.h"
 #endif
 
 #ifndef XPC_MAP_QUOTED_CLASSNAME
 #error "Must #define XPC_MAP_QUOTED_CLASSNAME before #including xpc_map_end.h"
 #endif
 
+#include "js/Id.h"
+
 /**************************************************************/
 
 NS_IMETHODIMP XPC_MAP_CLASSNAME::GetClassName(char * *aClassName)
 {
     static const char sName[] = XPC_MAP_QUOTED_CLASSNAME;
     *aClassName = (char*) nsMemory::Clone(sName, sizeof(sName));
     return NS_OK;
 }
@@ -103,77 +105,77 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::Create(
 NS_IMETHODIMP XPC_MAP_CLASSNAME::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 
 NS_IMETHODIMP XPC_MAP_CLASSNAME::PostTransplant(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_ADDPROPERTY
-NS_IMETHODIMP XPC_MAP_CLASSNAME::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, jsval * vp, bool *_retval)
+NS_IMETHODIMP XPC_MAP_CLASSNAME::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, JS::Value * vp, bool *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_DELPROPERTY
 NS_IMETHODIMP XPC_MAP_CLASSNAME::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, bool *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_GETPROPERTY
-NS_IMETHODIMP XPC_MAP_CLASSNAME::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, jsval * vp, bool *_retval)
+NS_IMETHODIMP XPC_MAP_CLASSNAME::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, JS::Value * vp, bool *_retval)
     {NS_WARNING("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_SETPROPERTY
-NS_IMETHODIMP XPC_MAP_CLASSNAME::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, jsval * vp, bool *_retval)
+NS_IMETHODIMP XPC_MAP_CLASSNAME::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, JS::Value * vp, bool *_retval)
     {NS_WARNING("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_NEWENUMERATE
-NS_IMETHODIMP XPC_MAP_CLASSNAME::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, uint32_t enum_op, jsval * statep, jsid * idp, bool *_retval)
+NS_IMETHODIMP XPC_MAP_CLASSNAME::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, uint32_t enum_op, JS::Value * statep, jsid * idp, bool *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_ENUMERATE
 NS_IMETHODIMP XPC_MAP_CLASSNAME::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, bool *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_NEWRESOLVE
 NS_IMETHODIMP XPC_MAP_CLASSNAME::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, uint32_t flags, JSObject * *objp, bool *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_CONVERT
-NS_IMETHODIMP XPC_MAP_CLASSNAME::Convert(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, uint32_t type, jsval * vp, bool *_retval)
+NS_IMETHODIMP XPC_MAP_CLASSNAME::Convert(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, uint32_t type, JS::Value * vp, bool *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_FINALIZE
 NS_IMETHODIMP XPC_MAP_CLASSNAME::Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp * fop, JSObject * obj)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_CHECKACCESS
-NS_IMETHODIMP XPC_MAP_CLASSNAME::CheckAccess(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, uint32_t mode, jsval * vp, bool *_retval)
+NS_IMETHODIMP XPC_MAP_CLASSNAME::CheckAccess(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, uint32_t mode, JS::Value * vp, bool *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_CALL
 NS_IMETHODIMP XPC_MAP_CLASSNAME::Call(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, const JS::CallArgs &args, bool *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_CONSTRUCT
 NS_IMETHODIMP XPC_MAP_CLASSNAME::Construct(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, const JS::CallArgs &args, bool *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_HASINSTANCE
-NS_IMETHODIMP XPC_MAP_CLASSNAME::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, const jsval &val, bool *bp, bool *_retval)
+NS_IMETHODIMP XPC_MAP_CLASSNAME::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, const JS::Value &val, bool *bp, bool *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_OUTER_OBJECT
 NS_IMETHODIMP XPC_MAP_CLASSNAME::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, JSObject * *_retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -91,16 +91,17 @@ using namespace mozilla::layout;
 
 using mozilla::image::Angle;
 using mozilla::image::Flip;
 using mozilla::image::ImageOps;
 using mozilla::image::Orientation;
 
 #define FLEXBOX_ENABLED_PREF_NAME "layout.css.flexbox.enabled"
 #define STICKY_ENABLED_PREF_NAME "layout.css.sticky.enabled"
+#define TEXT_ALIGN_TRUE_ENABLED_PREF_NAME "layout.css.text-align-true-value.enabled"
 
 #ifdef DEBUG
 // TODO: remove, see bug 598468.
 bool nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
 #endif // DEBUG
 
 typedef FrameMetrics::ViewID ViewID;
 
@@ -204,16 +205,55 @@ StickyEnabledPrefChangeCallback(const ch
   // OK -- now, stomp on or restore the "sticky" entry in kPositionKTable,
   // depending on whether the sticky pref is enabled vs. disabled.
   nsCSSProps::kPositionKTable[sIndexOfStickyInPositionTable] =
     isStickyEnabled ? eCSSKeyword_sticky : eCSSKeyword_UNKNOWN;
 
   return 0;
 }
 
+// When the pref "layout.css.text-align-true-value.enabled" changes, this
+// function is called to let us update kTextAlignKTable & kTextAlignLastKTable,
+// to selectively disable or restore the entries for "true" in those tables.
+static int
+TextAlignTrueEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
+{
+  NS_ASSERTION(strcmp(aPrefName, TEXT_ALIGN_TRUE_ENABLED_PREF_NAME) == 0,
+               "Did you misspell " TEXT_ALIGN_TRUE_ENABLED_PREF_NAME " ?");
+
+  static bool sIsInitialized;
+  static int32_t sIndexOfTrueInTextAlignTable;
+  static int32_t sIndexOfTrueInTextAlignLastTable;
+  bool isTextAlignTrueEnabled =
+    Preferences::GetBool(TEXT_ALIGN_TRUE_ENABLED_PREF_NAME, false);
+
+  if (!sIsInitialized) {
+    // First run: find the position of "true" in kTextAlignKTable.
+    sIndexOfTrueInTextAlignTable =
+      nsCSSProps::FindIndexOfKeyword(eCSSKeyword_true,
+                                     nsCSSProps::kTextAlignKTable);
+    // First run: find the position of "true" in kTextAlignLastKTable.
+    sIndexOfTrueInTextAlignLastTable =
+      nsCSSProps::FindIndexOfKeyword(eCSSKeyword_true,
+                                     nsCSSProps::kTextAlignLastKTable);
+    sIsInitialized = true;
+  }
+
+  // OK -- now, stomp on or restore the "true" entry in the keyword tables,
+  // depending on whether the pref is enabled vs. disabled.
+  MOZ_ASSERT(sIndexOfTrueInTextAlignTable >= 0);
+  nsCSSProps::kTextAlignKTable[sIndexOfTrueInTextAlignTable] =
+    isTextAlignTrueEnabled ? eCSSKeyword_true : eCSSKeyword_UNKNOWN;
+  MOZ_ASSERT(sIndexOfTrueInTextAlignLastTable >= 0);
+  nsCSSProps::kTextAlignLastKTable[sIndexOfTrueInTextAlignLastTable] =
+    isTextAlignTrueEnabled ? eCSSKeyword_true : eCSSKeyword_UNKNOWN;
+
+  return 0;
+}
+
 template <class AnimationsOrTransitions>
 static AnimationsOrTransitions*
 HasAnimationOrTransition(nsIContent* aContent,
                          nsIAtom* aAnimationProperty,
                          nsCSSProperty aProperty)
 {
   AnimationsOrTransitions* animations =
     static_cast<AnimationsOrTransitions*>(aContent->GetProperty(aAnimationProperty));
@@ -442,16 +482,32 @@ nsLayoutUtils::UnsetValueEnabled()
     Preferences::AddBoolVarCache(&sUnsetValueEnabled,
                                  "layout.css.unset-value.enabled",
                                  false);
   }
 
   return sUnsetValueEnabled;
 }
 
+bool
+nsLayoutUtils::IsTextAlignTrueValueEnabled()
+{
+  static bool sTextAlignTrueValueEnabled;
+  static bool sTextAlignTrueValueEnabledPrefCached = false;
+
+  if (!sTextAlignTrueValueEnabledPrefCached) {
+    sTextAlignTrueValueEnabledPrefCached = true;
+    Preferences::AddBoolVarCache(&sTextAlignTrueValueEnabled,
+                                 TEXT_ALIGN_TRUE_ENABLED_PREF_NAME,
+                                 false);
+  }
+
+  return sTextAlignTrueValueEnabled;
+}
+
 void
 nsLayoutUtils::UnionChildOverflow(nsIFrame* aFrame,
                                   nsOverflowAreas& aOverflowAreas)
 {
   // Iterate over all children except pop-ups.
   const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
                                     nsIFrame::kSelectPopupList);
   for (nsIFrame::ChildListIterator childLists(aFrame);
@@ -5119,16 +5175,20 @@ nsLayoutUtils::Initialize()
                                "nglayout.debug.invalidation");
 
   Preferences::RegisterCallback(FlexboxEnabledPrefChangeCallback,
                                 FLEXBOX_ENABLED_PREF_NAME);
   FlexboxEnabledPrefChangeCallback(FLEXBOX_ENABLED_PREF_NAME, nullptr);
   Preferences::RegisterCallback(StickyEnabledPrefChangeCallback,
                                 STICKY_ENABLED_PREF_NAME);
   StickyEnabledPrefChangeCallback(STICKY_ENABLED_PREF_NAME, nullptr);
+  Preferences::RegisterCallback(TextAlignTrueEnabledPrefChangeCallback,
+                                TEXT_ALIGN_TRUE_ENABLED_PREF_NAME);
+  TextAlignTrueEnabledPrefChangeCallback(TEXT_ALIGN_TRUE_ENABLED_PREF_NAME,
+                                         nullptr);
 
   nsComputedDOMStyle::RegisterPrefChangeCallbacks();
 }
 
 /* static */
 void
 nsLayoutUtils::Shutdown()
 {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1672,16 +1672,22 @@ public:
   static bool CSSFiltersEnabled();
 
   /**
    * Checks whether support for the CSS-wide "unset" value is enabled.
    */
   static bool UnsetValueEnabled();
 
   /**
+   * Checks whether support for the CSS text-align (and -moz-text-align-last)
+   * 'true' value is enabled.
+   */
+  static bool IsTextAlignTrueValueEnabled();
+
+  /**
    * Unions the overflow areas of all non-popup children of aFrame with
    * aOverflowAreas.
    */
   static void UnionChildOverflow(nsIFrame* aFrame,
                                  nsOverflowAreas& aOverflowAreas);
 
   /**
    * Return the font size inflation *ratio* for a given frame.  This is
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -2465,42 +2465,43 @@ nsLineLayout::HorizontalAlignFrames(nsRe
   PerSpanData* psd = mRootSpan;
   NS_WARN_IF_FALSE(psd->mRightEdge != NS_UNCONSTRAINEDSIZE,
                    "have unconstrained width; this should only result from "
                    "very large sizes, not attempts at intrinsic width "
                    "calculation");
   nscoord availWidth = psd->mRightEdge - psd->mLeftEdge;
   nscoord remainingWidth = availWidth - aLineBounds.width;
 #ifdef NOISY_HORIZONTAL_ALIGN
-    nsFrame::ListTag(stdout, mBlockReflowState->frame);
-    printf(": availWidth=%d lineWidth=%d delta=%d\n",
-           availWidth, aLineBounds.width, remainingWidth);
+  nsFrame::ListTag(stdout, mBlockReflowState->frame);
+  printf(": availWidth=%d lineWidth=%d delta=%d\n",
+         availWidth, aLineBounds.width, remainingWidth);
 #endif
-  nscoord dx = 0;
-
-  if (remainingWidth > 0 &&
-      !(mBlockReflowState->frame->IsSVGText())) {
-    uint8_t textAlign = mStyleText->mTextAlign;
 
-    /* 
-     * 'text-align-last: auto' is equivalent to the value of the 'text-align'
-     * property except when 'text-align' is set to 'justify', in which case it
-     * is 'justify' when 'text-justify' is 'distribute' and 'start' otherwise.
-     *
-     * XXX: the code below will have to change when we implement text-justify
-     */
-    if (aIsLastLine) {
-      if (mStyleText->mTextAlignLast == NS_STYLE_TEXT_ALIGN_AUTO) {
-        if (textAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY) {
-          textAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
-        }
-      } else {
-        textAlign = mStyleText->mTextAlignLast;
+  // 'text-align-last: auto' is equivalent to the value of the 'text-align'
+  // property except when 'text-align' is set to 'justify', in which case it
+  // is 'justify' when 'text-justify' is 'distribute' and 'start' otherwise.
+  //
+  // XXX: the code below will have to change when we implement text-justify
+  //
+  nscoord dx = 0;
+  uint8_t textAlign = mStyleText->mTextAlign;
+  bool textAlignTrue = mStyleText->mTextAlignTrue;
+  if (aIsLastLine) {
+    textAlignTrue = mStyleText->mTextAlignLastTrue;
+    if (mStyleText->mTextAlignLast == NS_STYLE_TEXT_ALIGN_AUTO) {
+      if (textAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY) {
+        textAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
       }
+    } else {
+      textAlign = mStyleText->mTextAlignLast;
     }
+  }
+
+  if ((remainingWidth > 0 || textAlignTrue) &&
+      !(mBlockReflowState->frame->IsSVGText())) {
 
     switch (textAlign) {
       case NS_STYLE_TEXT_ALIGN_JUSTIFY:
         int32_t numSpaces;
         int32_t numLetters;
             
         ComputeJustificationWeights(psd, &numSpaces, &numLetters);
 
@@ -2544,17 +2545,17 @@ nsLineLayout::HorizontalAlignFrames(nsRe
         break;
 
       case NS_STYLE_TEXT_ALIGN_CENTER:
       case NS_STYLE_TEXT_ALIGN_MOZ_CENTER:
         dx = remainingWidth / 2;
         break;
     }
   }
-  else if (remainingWidth < 0) {
+  else if (remainingWidth < 0 || textAlignTrue) {
     if (NS_STYLE_DIRECTION_RTL == psd->mDirection) {
       dx = remainingWidth;
       psd->mX += dx;
       psd->mLeftEdge += dx;
     }
   }
 
   if (NS_STYLE_DIRECTION_RTL == psd->mDirection &&
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -276,8 +276,10 @@ pref(gfx.font_rendering.graphite.enabled
 != auto-hyphenation-sv-1.html auto-hyphenation-sv-1-notref.html # verify swedish != english
 == auto-hyphenation-tr-1.html auto-hyphenation-tr-1-ref.html
 == auto-hyphenation-uk-1.html auto-hyphenation-uk-1-ref.html
 
 # osx-font-smoothing - with and without subpixel AA, only under OSX
 fails-if(!cocoaWidget||OSX==10.6||OSX==10.7) != osx-font-smoothing.html osx-font-smoothing-ref.html
 fails-if(!cocoaWidget||OSX==10.6||OSX==10.7) != osx-font-smoothing-2.html osx-font-smoothing-2-notref.html
 == osx-font-smoothing-2.html osx-font-smoothing-2-ref.html
+
+pref(layout.css.text-align-true-value.enabled,true) == text-align-true.html text-align-true-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/text-align-true-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <title>text-align-true</title>
+  <meta charset="utf-8">
+  <style type="text/css">
+   p {
+     overflow:hidden;
+     width:8em;
+     white-space:nowrap;
+     margin:0;
+   }
+.test1 p {
+   text-align: end;
+}
+.test2 p {
+   text-align: right;
+}
+.test3 p {
+   text-align: end;
+}
+.test4 p {
+   text-align: left;
+}
+.test5 p {
+   text-align: right;
+}
+.r {
+   float:right;
+}
+.l {
+   float:left;
+}
+  </style>
+ </head>
+ <body>
+<div class=test1>
+ <p>Lorem ipsum dolor sit amet.</p>
+ <p dir="rtl">ישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
+</div>
+
+<div class=test2>
+ <p><span class="r">Lorem ipsum dolor sit amet.</span></p>
+ <p dir="rtl">ישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
+</div>
+
+<div class=test3>
+ <p><span class="r">Lorem ipsum dolor sit amet.</span></p>
+ <p dir="rtl"><span class="l">ישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</span></p>
+</div>
+
+<div class=test4>
+ <p>Lorem ipsum dolor sit amet.</p>
+ <p dir="rtl"><span class="l">ישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</span></p>
+</div>
+
+<div class=test5>
+ <p><span class="r">Lorem ipsum dolor sit amet.</span></p>
+</div>
+
+ left|true right</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/text-align-true.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+  <title>text-align-true</title>
+  <meta charset="utf-8">
+  <style type="text/css">
+   p {
+     overflow:hidden;
+     width:8em;
+     white-space:nowrap;
+     margin:0;
+   }
+.test1 p {
+   text-align: true right;
+   -moz-text-align-last: end;
+}
+.test2 p {
+   text-align: true right;
+}
+.test3 p {
+   text-align: end true;
+}
+.test4 p {
+   text-align: true left;
+}
+.test5 p {
+   text-align: left;
+   -moz-text-align-last: true right;
+}
+  </style>
+ </head>
+ <body>
+<div class=test1>
+ <p>Lorem ipsum dolor sit amet.</p>
+ <p dir="rtl">ישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
+</div>
+
+<div class=test2>
+ <p>Lorem ipsum dolor sit amet.</p>
+ <p dir="rtl">ישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
+</div>
+
+<div class=test3>
+ <p>Lorem ipsum dolor sit amet.</p>
+ <p dir="rtl">ישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
+</div>
+
+<div class=test4>
+ <p>Lorem ipsum dolor sit amet.</p>
+ <p dir="rtl">ישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
+</div>
+
+<div class=test5>
+ <p>Lorem ipsum dolor sit amet.</p>
+</div>
+
+<script>
+  var elem = document.querySelector('.test5 p');
+  var a = window.getComputedStyle(elem,null).getPropertyValue("text-align");
+  document.body.appendChild(document.createTextNode(a +"|"));
+  a = window.getComputedStyle(elem,null).getPropertyValue("-moz-text-align-last");
+  document.body.appendChild(document.createTextNode(a));
+
+  document.documentElement.removeAttribute('class');
+</script>
+
+</body>
+</html>
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -524,16 +524,17 @@ CSS_KEY(top-outside, top_outside)
 CSS_KEY(traditional, traditional)
 CSS_KEY(translate, translate)
 CSS_KEY(translate3d, translate3d)
 CSS_KEY(translatex, translatex)
 CSS_KEY(translatey, translatey)
 CSS_KEY(translatez, translatez)
 CSS_KEY(transparent, transparent) // for nsComputedDOMStyle only
 CSS_KEY(tri-state, tri_state)
+CSS_KEY(true, true)
 CSS_KEY(ultra-condensed, ultra_condensed)
 CSS_KEY(ultra-expanded, ultra_expanded)
 CSS_KEY(underline, underline)
 CSS_KEY(unicase, unicase)
 CSS_KEY(unset, unset)
 CSS_KEY(upper-alpha, upper_alpha)
 CSS_KEY(upper-latin, upper_latin)
 CSS_KEY(upper-roman, upper_roman)
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -501,16 +501,19 @@ protected:
   bool ParseMargin();
   bool ParseMarks(nsCSSValue& aValue);
   bool ParseTransform(bool aIsPrefixed);
   bool ParseOutline();
   bool ParseOverflow();
   bool ParsePadding();
   bool ParseQuotes();
   bool ParseSize();
+  bool ParseTextAlign(nsCSSValue& aValue, const int32_t aTable[]);
+  bool ParseTextAlign(nsCSSValue& aValue);
+  bool ParseTextAlignLast(nsCSSValue& aValue);
   bool ParseTextDecoration();
   bool ParseTextDecorationLine(nsCSSValue& aValue);
   bool ParseTextCombineHorizontal(nsCSSValue& aValue);
   bool ParseTextOverflow(nsCSSValue& aValue);
 
   bool ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow);
   bool ParseShadowList(nsCSSProperty aProperty);
   bool ParseTransitionProperty();
@@ -6664,16 +6667,20 @@ CSSParserImpl::ParseSingleValueProperty(
       case eCSSProperty_font_feature_settings:
         return ParseFontFeatureSettings(aValue);
       case eCSSProperty_font_weight:
         return ParseFontWeight(aValue);
       case eCSSProperty_image_orientation:
         return ParseImageOrientation(aValue);
       case eCSSProperty_marks:
         return ParseMarks(aValue);
+      case eCSSProperty_text_align:
+        return ParseTextAlign(aValue);
+      case eCSSProperty_text_align_last:
+        return ParseTextAlignLast(aValue);
       case eCSSProperty_text_decoration_line:
         return ParseTextDecorationLine(aValue);
       case eCSSProperty_text_combine_horizontal:
         return ParseTextCombineHorizontal(aValue);
       case eCSSProperty_text_overflow:
         return ParseTextOverflow(aValue);
       default:
         NS_ABORT_IF_FALSE(false, "should not reach here");
@@ -9710,16 +9717,64 @@ CSSParserImpl::ParseTextDecoration()
   AppendValue(eCSSProperty_text_decoration_line, line);
   AppendValue(eCSSProperty_text_decoration_color, color);
   AppendValue(eCSSProperty_text_decoration_style, style);
 
   return true;
 }
 
 bool
+CSSParserImpl::ParseTextAlign(nsCSSValue& aValue, const int32_t aTable[])
+{
+  if (ParseVariant(aValue, VARIANT_INHERIT, nullptr)) {
+    // 'inherit', 'initial' and 'unset' must be alone
+    return true;
+  }
+
+  nsCSSValue left;
+  if (!ParseVariant(left, VARIANT_KEYWORD, aTable)) {
+    return false;
+  }
+
+  if (!nsLayoutUtils::IsTextAlignTrueValueEnabled()) {
+    aValue = left;
+    return true;
+  }
+
+  nsCSSValue right;
+  if (ParseVariant(right, VARIANT_KEYWORD, aTable)) {
+    // 'true' must be combined with some other value than 'true'.
+    if (left.GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE &&
+        right.GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
+      return false;
+    }
+    aValue.SetPairValue(left, right);
+  } else {
+    // Single value 'true' is not allowed.
+    if (left.GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
+      return false;
+    }
+    aValue = left;
+  }
+  return true;
+}
+
+bool
+CSSParserImpl::ParseTextAlign(nsCSSValue& aValue)
+{
+  return ParseTextAlign(aValue, nsCSSProps::kTextAlignKTable);
+}
+
+bool
+CSSParserImpl::ParseTextAlignLast(nsCSSValue& aValue)
+{
+  return ParseTextAlign(aValue, nsCSSProps::kTextAlignLastKTable);
+}
+
+bool
 CSSParserImpl::ParseTextDecorationLine(nsCSSValue& aValue)
 {
   if (ParseVariant(aValue, VARIANT_HK, nsCSSProps::kTextDecorationLineKTable)) {
     if (eCSSUnit_Enumerated == aValue.GetUnit()) {
       int32_t intValue = aValue.GetIntValue();
       if (intValue != NS_STYLE_TEXT_DECORATION_LINE_NONE) {
         // look for more keywords
         nsCSSValue  keyword;
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -2763,29 +2763,30 @@ CSS_PROP_TABLE(
     VARIANT_HK,
     kTableLayoutKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_TEXT(
     text-align,
     text_align,
     TextAlign,
-    CSS_PROPERTY_PARSE_VALUE | CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
+    CSS_PROPERTY_PARSE_VALUE | CSS_PROPERTY_VALUE_PARSER_FUNCTION |
+      CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
     "",
     // When we support aligning on a string, we can parse text-align
     // as a string....
     VARIANT_HK /* | VARIANT_STRING */,
     kTextAlignKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_TEXT(
     -moz-text-align-last,
     text_align_last,
     CSS_PROP_DOMPROP_PREFIXED(TextAlignLast),
-    CSS_PROPERTY_PARSE_VALUE,
+    CSS_PROPERTY_PARSE_VALUE | CSS_PROPERTY_VALUE_PARSER_FUNCTION,
     "",
     VARIANT_HK,
     kTextAlignLastKTable,
     offsetof(nsStyleText, mTextAlignLast),
     eStyleAnimType_None)
 CSS_PROP_SHORTHAND(
     text-decoration,
     text_decoration,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -955,19 +955,17 @@ int32_t nsCSSProps::kDisplayKTable[] = {
   eCSSKeyword__moz_grid_group,    NS_STYLE_DISPLAY_GRID_GROUP,
   eCSSKeyword__moz_grid_line,     NS_STYLE_DISPLAY_GRID_LINE,
   eCSSKeyword__moz_stack,         NS_STYLE_DISPLAY_STACK,
   eCSSKeyword__moz_inline_stack,  NS_STYLE_DISPLAY_INLINE_STACK,
   eCSSKeyword__moz_deck,          NS_STYLE_DISPLAY_DECK,
   eCSSKeyword__moz_popup,         NS_STYLE_DISPLAY_POPUP,
   eCSSKeyword__moz_groupbox,      NS_STYLE_DISPLAY_GROUPBOX,
 #endif
-  // XXXdholbert NOTE: These currently need to be the last entries in the
-  // table, because the "is flexbox enabled" pref that disables these will
-  // disable all the entries after them, too.
+  // The next two entries are controlled by the layout.css.flexbox.enabled pref.
   eCSSKeyword_flex,               NS_STYLE_DISPLAY_FLEX,
   eCSSKeyword_inline_flex,        NS_STYLE_DISPLAY_INLINE_FLEX,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const int32_t nsCSSProps::kEmptyCellsKTable[] = {
   eCSSKeyword_show,                 NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
   eCSSKeyword_hide,                 NS_STYLE_TABLE_EMPTY_CELLS_HIDE,
@@ -1375,19 +1373,17 @@ const int32_t nsCSSProps::kPointerEvents
   eCSSKeyword_UNKNOWN, -1
 };
 
 int32_t nsCSSProps::kPositionKTable[] = {
   eCSSKeyword_static, NS_STYLE_POSITION_STATIC,
   eCSSKeyword_relative, NS_STYLE_POSITION_RELATIVE,
   eCSSKeyword_absolute, NS_STYLE_POSITION_ABSOLUTE,
   eCSSKeyword_fixed, NS_STYLE_POSITION_FIXED,
-  // NOTE: This currently needs to be the last entry in the table,
-  // because the "layout.css.sticky.enabled" pref that disables
-  // this will disable all the entries after it, too.
+  // The next entry is controlled by the layout.css.sticky.enabled pref.
   eCSSKeyword_sticky, NS_STYLE_POSITION_STICKY,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const int32_t nsCSSProps::kRadialGradientShapeKTable[] = {
   eCSSKeyword_circle,  NS_STYLE_GRADIENT_SHAPE_CIRCULAR,
   eCSSKeyword_ellipse, NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL,
   eCSSKeyword_UNKNOWN,-1
@@ -1427,37 +1423,39 @@ const int32_t nsCSSProps::kStackSizingKT
 };
 
 const int32_t nsCSSProps::kTableLayoutKTable[] = {
   eCSSKeyword_auto, NS_STYLE_TABLE_LAYOUT_AUTO,
   eCSSKeyword_fixed, NS_STYLE_TABLE_LAYOUT_FIXED,
   eCSSKeyword_UNKNOWN,-1
 };
 
-const int32_t nsCSSProps::kTextAlignKTable[] = {
+int32_t nsCSSProps::kTextAlignKTable[] = {
   eCSSKeyword_left, NS_STYLE_TEXT_ALIGN_LEFT,
   eCSSKeyword_right, NS_STYLE_TEXT_ALIGN_RIGHT,
   eCSSKeyword_center, NS_STYLE_TEXT_ALIGN_CENTER,
   eCSSKeyword_justify, NS_STYLE_TEXT_ALIGN_JUSTIFY,
   eCSSKeyword__moz_center, NS_STYLE_TEXT_ALIGN_MOZ_CENTER,
   eCSSKeyword__moz_right, NS_STYLE_TEXT_ALIGN_MOZ_RIGHT,
   eCSSKeyword__moz_left, NS_STYLE_TEXT_ALIGN_MOZ_LEFT,
   eCSSKeyword_start, NS_STYLE_TEXT_ALIGN_DEFAULT,
   eCSSKeyword_end, NS_STYLE_TEXT_ALIGN_END,
+  eCSSKeyword_true, NS_STYLE_TEXT_ALIGN_TRUE,
   eCSSKeyword_UNKNOWN,-1
 };
 
-const int32_t nsCSSProps::kTextAlignLastKTable[] = {
+int32_t nsCSSProps::kTextAlignLastKTable[] = {
   eCSSKeyword_auto, NS_STYLE_TEXT_ALIGN_AUTO,
   eCSSKeyword_left, NS_STYLE_TEXT_ALIGN_LEFT,
   eCSSKeyword_right, NS_STYLE_TEXT_ALIGN_RIGHT,
   eCSSKeyword_center, NS_STYLE_TEXT_ALIGN_CENTER,
   eCSSKeyword_justify, NS_STYLE_TEXT_ALIGN_JUSTIFY,
   eCSSKeyword_start, NS_STYLE_TEXT_ALIGN_DEFAULT,
   eCSSKeyword_end, NS_STYLE_TEXT_ALIGN_END,
+  eCSSKeyword_true, NS_STYLE_TEXT_ALIGN_TRUE,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const int32_t nsCSSProps::kTextCombineHorizontalKTable[] = {
   eCSSKeyword_none, NS_STYLE_TEXT_COMBINE_HORIZ_NONE,
   eCSSKeyword_all, NS_STYLE_TEXT_COMBINE_HORIZ_ALL,
   eCSSKeyword_digits, NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_2,  // w/o number ==> 2
   eCSSKeyword_UNKNOWN,-1
@@ -1783,25 +1781,43 @@ const int32_t nsCSSProps::kColorInterpol
 };
 
 const int32_t nsCSSProps::kColumnFillKTable[] = {
   eCSSKeyword_auto, NS_STYLE_COLUMN_FILL_AUTO,
   eCSSKeyword_balance, NS_STYLE_COLUMN_FILL_BALANCE,
   eCSSKeyword_UNKNOWN, -1
 };
 
+static bool IsKeyValSentinel(nsCSSKeyword aKey, int32_t aValue)
+{
+  return aKey == eCSSKeyword_UNKNOWN && aValue == -1;
+}
+
 int32_t
 nsCSSProps::FindIndexOfKeyword(nsCSSKeyword aKeyword, const int32_t aTable[])
 {
-  int32_t index = 0;
-  while (eCSSKeyword_UNKNOWN != nsCSSKeyword(aTable[index])) {
-    if (aKeyword == nsCSSKeyword(aTable[index])) {
-      return index;
+  if (eCSSKeyword_UNKNOWN == aKeyword) {
+    // NOTE: we can have keyword tables where eCSSKeyword_UNKNOWN is used
+    // not only for the sentinel, but also in the middle of the table to
+    // knock out values that have been disabled by prefs, e.g. kDisplayKTable.
+    // So we deal with eCSSKeyword_UNKNOWN up front to avoid returning a valid
+    // index in the loop below.
+    return -1;
+  }
+  int32_t i = 0;
+  for (;;) {
+    nsCSSKeyword key = nsCSSKeyword(aTable[i]);
+    int32_t val = aTable[i + 1];
+    if (::IsKeyValSentinel(key, val)) {
+      break;
     }
-    index += 2;
+    if (aKeyword == key) {
+      return i;
+    }
+    i += 2;
   }
   return -1;
 }
 
 bool
 nsCSSProps::FindKeyword(nsCSSKeyword aKeyword, const int32_t aTable[],
                         int32_t& aResult)
 {
@@ -1813,21 +1829,23 @@ nsCSSProps::FindKeyword(nsCSSKeyword aKe
   return false;
 }
 
 nsCSSKeyword
 nsCSSProps::ValueToKeywordEnum(int32_t aValue, const int32_t aTable[])
 {
   int32_t i = 1;
   for (;;) {
-    if (aTable[i] == -1 && aTable[i-1] == eCSSKeyword_UNKNOWN) {
+    int32_t val = aTable[i];
+    nsCSSKeyword key = nsCSSKeyword(aTable[i - 1]);
+    if (::IsKeyValSentinel(key, val)) {
       break;
     }
-    if (aValue == aTable[i]) {
-      return nsCSSKeyword(aTable[i-1]);
+    if (aValue == val) {
+      return key;
     }
     i += 2;
   }
   return eCSSKeyword_UNKNOWN;
 }
 
 const nsAFlatCString&
 nsCSSProps::ValueToKeyword(int32_t aValue, const int32_t aTable[])
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -532,18 +532,20 @@ public:
   static const int32_t kResizeKTable[];
   static const int32_t kSpeakKTable[];
   static const int32_t kSpeakHeaderKTable[];
   static const int32_t kSpeakNumeralKTable[];
   static const int32_t kSpeakPunctuationKTable[];
   static const int32_t kSpeechRateKTable[];
   static const int32_t kStackSizingKTable[];
   static const int32_t kTableLayoutKTable[];
-  static const int32_t kTextAlignKTable[];
-  static const int32_t kTextAlignLastKTable[];
+  // Not const because we modify its entries when the pref
+  // "layout.css.text-align-true-value.enabled" changes:
+  static int32_t kTextAlignKTable[];
+  static int32_t kTextAlignLastKTable[];
   static const int32_t kTextCombineHorizontalKTable[];
   static const int32_t kTextDecorationLineKTable[];
   static const int32_t kTextDecorationStyleKTable[];
   static const int32_t kTextOrientationKTable[];
   static const int32_t kTextOverflowKTable[];
   static const int32_t kTextTransformKTable[];
   static const int32_t kTransitionTimingFunctionKTable[];
   static const int32_t kUnicodeBidiKTable[];
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -2755,33 +2755,48 @@ nsComputedDOMStyle::DoGetVerticalAlign()
   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StyleTextReset()->mVerticalAlign, false,
                   &nsComputedDOMStyle::GetLineHeightCoord,
                   nsCSSProps::kVerticalAlignKTable);
   return val;
 }
 
 CSSValue*
-nsComputedDOMStyle::DoGetTextAlign()
+nsComputedDOMStyle::CreateTextAlignValue(uint8_t aAlign, bool aAlignTrue,
+                                         const int32_t aTable[])
 {
   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
-  val->SetIdent(
-    nsCSSProps::ValueToKeywordEnum(StyleText()->mTextAlign,
-                                   nsCSSProps::kTextAlignKTable));
-  return val;
+  val->SetIdent(nsCSSProps::ValueToKeywordEnum(aAlign, aTable));
+  if (!aAlignTrue) {
+    return val;
+  }
+
+  nsROCSSPrimitiveValue* first = new nsROCSSPrimitiveValue;
+  first->SetIdent(eCSSKeyword_true);
+
+  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  valueList->AppendCSSValue(first);
+  valueList->AppendCSSValue(val);
+  return valueList;
+}
+
+CSSValue*
+nsComputedDOMStyle::DoGetTextAlign()
+{
+  const nsStyleText* style = StyleText();
+  return CreateTextAlignValue(style->mTextAlign, style->mTextAlignTrue,
+                              nsCSSProps::kTextAlignKTable);
 }
 
 CSSValue*
 nsComputedDOMStyle::DoGetTextAlignLast()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
-  val->SetIdent(
-    nsCSSProps::ValueToKeywordEnum(StyleText()->mTextAlignLast,
-                                   nsCSSProps::kTextAlignLastKTable));
-  return val;
+  const nsStyleText* style = StyleText();
+  return CreateTextAlignValue(style->mTextAlignLast, style->mTextAlignLastTrue,
+                              nsCSSProps::kTextAlignLastKTable);
 }
 
 CSSValue*
 nsComputedDOMStyle::DoGetTextCombineHorizontal()
 {
   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   uint8_t tch = StyleText()->mTextCombineHorizontal;
 
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -135,16 +135,21 @@ public:
 private:
   void AssertFlushedPendingReflows() {
     NS_ASSERTION(mFlushedPendingReflows,
                  "property getter should have been marked layout-dependent");
   }
 
   nsMargin GetAdjustedValuesForBoxSizing();
 
+  // Helper method for DoGetTextAlign[Last].
+  mozilla::dom::CSSValue* CreateTextAlignValue(uint8_t aAlign,
+                                               bool aAlignTrue,
+                                               const int32_t aTable[]);
+
 #define STYLE_STRUCT(name_, checkdata_cb_)                              \
   const nsStyle##name_ * Style##name_() {                               \
     return mStyleContextHolder->Style##name_();                         \
   }
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 
   // All of the property getters below return a pointer to a refcounted object
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -3963,35 +3963,70 @@ nsRuleNode::ComputeTextData(void* aStart
           lh = minimumFontSize;
         }
       }
       text->mLineHeight.SetCoordValue(lh);
     }
   }
 
 
-  // text-align: enum, string, inherit, initial
+  // text-align: enum, string, pair(enum|string), inherit, initial
+  // NOTE: string is not implemented yet.
   const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
+  text->mTextAlignTrue = false;
   if (eCSSUnit_String == textAlignValue->GetUnit()) {
     NS_NOTYETIMPLEMENTED("align string");
   } else if (eCSSUnit_Enumerated == textAlignValue->GetUnit() &&
              NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT ==
                textAlignValue->GetIntValue()) {
     canStoreInRuleTree = false;
     uint8_t parentAlign = parentText->mTextAlign;
     text->mTextAlign = (NS_STYLE_TEXT_ALIGN_DEFAULT == parentAlign) ?
       NS_STYLE_TEXT_ALIGN_CENTER : parentAlign;
-  } else
+  } else {
+    if (eCSSUnit_Pair == textAlignValue->GetUnit()) {
+      // Two values were specified, one must be 'true'.
+      text->mTextAlignTrue = true;
+      const nsCSSValuePair& textAlignValuePair = textAlignValue->GetPairValue();
+      textAlignValue = &textAlignValuePair.mXValue;
+      if (eCSSUnit_Enumerated == textAlignValue->GetUnit()) {
+        if (textAlignValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
+          textAlignValue = &textAlignValuePair.mYValue;
+        }
+      } else if (eCSSUnit_String == textAlignValue->GetUnit()) {
+        NS_NOTYETIMPLEMENTED("align string");
+      }
+    } else if (eCSSUnit_Inherit == textAlignValue->GetUnit() ||
+               eCSSUnit_Unset == textAlignValue->GetUnit()) {
+      text->mTextAlignTrue = parentText->mTextAlignTrue;
+    }
     SetDiscrete(*textAlignValue, text->mTextAlign, canStoreInRuleTree,
                 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
                 parentText->mTextAlign,
                 NS_STYLE_TEXT_ALIGN_DEFAULT, 0, 0, 0, 0);
-
-  // text-align-last: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForTextAlignLast(), text->mTextAlignLast,
+  }
+
+  // text-align-last: enum, pair(enum), inherit, initial
+  const nsCSSValue* textAlignLastValue = aRuleData->ValueForTextAlignLast();
+  text->mTextAlignLastTrue = false;
+  if (eCSSUnit_Pair == textAlignLastValue->GetUnit()) {
+    // Two values were specified, one must be 'true'.
+    text->mTextAlignLastTrue = true;
+    const nsCSSValuePair& textAlignLastValuePair = textAlignLastValue->GetPairValue();
+    textAlignLastValue = &textAlignLastValuePair.mXValue;
+    if (eCSSUnit_Enumerated == textAlignLastValue->GetUnit()) {
+      if (textAlignLastValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
+        textAlignLastValue = &textAlignLastValuePair.mYValue;
+      }
+    }
+  } else if (eCSSUnit_Inherit == textAlignLastValue->GetUnit() ||
+             eCSSUnit_Unset == textAlignLastValue->GetUnit()) {
+    text->mTextAlignLastTrue = parentText->mTextAlignLastTrue;
+  }
+  SetDiscrete(*textAlignLastValue, text->mTextAlignLast,
               canStoreInRuleTree,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mTextAlignLast,
               NS_STYLE_TEXT_ALIGN_AUTO, 0, 0, 0, 0);
 
   // text-indent: length, percent, calc, inherit, initial
   SetCoord(*aRuleData->ValueForTextIndent(), text->mTextIndent, parentText->mTextIndent,
            SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -656,16 +656,17 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_TEXT_ALIGN_END                   6
 #define NS_STYLE_TEXT_ALIGN_AUTO                  7
 #define NS_STYLE_TEXT_ALIGN_MOZ_CENTER            8
 #define NS_STYLE_TEXT_ALIGN_MOZ_RIGHT             9
 #define NS_STYLE_TEXT_ALIGN_MOZ_LEFT             10
 // NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT is only used in data structs; it
 // is never present in stylesheets or computed data.
 #define NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT 11
+#define NS_STYLE_TEXT_ALIGN_TRUE                  12
 // Note: make sure that the largest NS_STYLE_TEXT_ALIGN_* value is smaller than
 // the smallest NS_STYLE_VERTICAL_ALIGN_* value below!
 
 // See nsStyleText, nsStyleFont
 #define NS_STYLE_TEXT_DECORATION_LINE_NONE         0
 #define NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE    NS_FONT_DECORATION_UNDERLINE
 #define NS_STYLE_TEXT_DECORATION_LINE_OVERLINE     NS_FONT_DECORATION_OVERLINE
 #define NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH NS_FONT_DECORATION_LINE_THROUGH
@@ -705,25 +706,25 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT  4
 #define NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START   5
 #define NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END     6
 
 // See nsStyleText
 // Note: these values pickup after the text-align values because there
 // are a few html cases where an object can have both types of
 // alignment applied with a single attribute
-#define NS_STYLE_VERTICAL_ALIGN_BASELINE             12
-#define NS_STYLE_VERTICAL_ALIGN_SUB                  13
-#define NS_STYLE_VERTICAL_ALIGN_SUPER                14
-#define NS_STYLE_VERTICAL_ALIGN_TOP                  15
-#define NS_STYLE_VERTICAL_ALIGN_TEXT_TOP             16
-#define NS_STYLE_VERTICAL_ALIGN_MIDDLE               17
-#define NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM          18
-#define NS_STYLE_VERTICAL_ALIGN_BOTTOM               19
-#define NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE 20
+#define NS_STYLE_VERTICAL_ALIGN_BASELINE             13
+#define NS_STYLE_VERTICAL_ALIGN_SUB                  14
+#define NS_STYLE_VERTICAL_ALIGN_SUPER                15
+#define NS_STYLE_VERTICAL_ALIGN_TOP                  16
+#define NS_STYLE_VERTICAL_ALIGN_TEXT_TOP             17
+#define NS_STYLE_VERTICAL_ALIGN_MIDDLE               18
+#define NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM          19
+#define NS_STYLE_VERTICAL_ALIGN_BOTTOM               20
+#define NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE 21
 
 // See nsStyleVisibility
 #define NS_STYLE_VISIBILITY_HIDDEN              0
 #define NS_STYLE_VISIBILITY_VISIBLE             1
 #define NS_STYLE_VISIBILITY_COLLAPSE            2
 
 // See nsStyleText
 #define NS_STYLE_TABSIZE_INITIAL                8
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2919,16 +2919,18 @@ CalcShadowDifference(nsCSSShadowArray* l
 // nsStyleText
 //
 
 nsStyleText::nsStyleText(void)
 { 
   MOZ_COUNT_CTOR(nsStyleText);
   mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
   mTextAlignLast = NS_STYLE_TEXT_ALIGN_AUTO;
+  mTextAlignTrue = false;
+  mTextAlignLastTrue = false;
   mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE;
   mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL;
   mWordBreak = NS_STYLE_WORDBREAK_NORMAL;
   mWordWrap = NS_STYLE_WORDWRAP_NORMAL;
   mHyphens = NS_STYLE_HYPHENS_MANUAL;
   mTextSizeAdjust = NS_STYLE_TEXT_SIZE_ADJUST_AUTO;
   mTextOrientation = NS_STYLE_TEXT_ORIENTATION_AUTO;
   mTextCombineHorizontal = NS_STYLE_TEXT_COMBINE_HORIZ_NONE;
@@ -2940,16 +2942,18 @@ nsStyleText::nsStyleText(void)
 
   mTextShadow = nullptr;
   mTabSize = NS_STYLE_TABSIZE_INITIAL;
 }
 
 nsStyleText::nsStyleText(const nsStyleText& aSource)
   : mTextAlign(aSource.mTextAlign),
     mTextAlignLast(aSource.mTextAlignLast),
+    mTextAlignTrue(false),
+    mTextAlignLastTrue(false),
     mTextTransform(aSource.mTextTransform),
     mWhiteSpace(aSource.mWhiteSpace),
     mWordBreak(aSource.mWordBreak),
     mWordWrap(aSource.mWordWrap),
     mHyphens(aSource.mHyphens),
     mTextSizeAdjust(aSource.mTextSizeAdjust),
     mTextOrientation(aSource.mTextOrientation),
     mTextCombineHorizontal(aSource.mTextCombineHorizontal),
@@ -2977,16 +2981,18 @@ nsChangeHint nsStyleText::CalcDifference
   }
 
   if (mTextCombineHorizontal != aOther.mTextCombineHorizontal) {
     return nsChangeHint_ReconstructFrame;
   }
 
   if ((mTextAlign != aOther.mTextAlign) ||
       (mTextAlignLast != aOther.mTextAlignLast) ||
+      (mTextAlignTrue != aOther.mTextAlignTrue) ||
+      (mTextAlignLastTrue != aOther.mTextAlignLastTrue) ||
       (mTextTransform != aOther.mTextTransform) ||
       (mWhiteSpace != aOther.mWhiteSpace) ||
       (mWordBreak != aOther.mWordBreak) ||
       (mWordWrap != aOther.mWordWrap) ||
       (mHyphens != aOther.mHyphens) ||
       (mTextSizeAdjust != aOther.mTextSizeAdjust) ||
       (mTextOrientation != aOther.mTextOrientation) ||
       (mLetterSpacing != aOther.mLetterSpacing) ||
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1305,16 +1305,18 @@ struct nsStyleText {
 
   nsChangeHint CalcDifference(const nsStyleText& aOther) const;
   static nsChangeHint MaxDifference() {
     return NS_STYLE_HINT_FRAMECHANGE;
   }
 
   uint8_t mTextAlign;                   // [inherited] see nsStyleConsts.h
   uint8_t mTextAlignLast;               // [inherited] see nsStyleConsts.h
+  bool mTextAlignTrue : 1;              // [inherited] see nsStyleConsts.h
+  bool mTextAlignLastTrue : 1;          // [inherited] see nsStyleConsts.h
   uint8_t mTextTransform;               // [inherited] see nsStyleConsts.h
   uint8_t mWhiteSpace;                  // [inherited] see nsStyleConsts.h
   uint8_t mWordBreak;                   // [inherited] see nsStyleConsts.h
   uint8_t mWordWrap;                    // [inherited] see nsStyleConsts.h
   uint8_t mHyphens;                     // [inherited] see nsStyleConsts.h
   uint8_t mTextSizeAdjust;              // [inherited] see nsStyleConsts.h
   uint8_t mTextOrientation;             // [inherited] see nsStyleConsts.h
   uint8_t mTextCombineHorizontal;       // [inherited] see nsStyleConsts.h
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -3074,17 +3074,17 @@ var gCSSProperties = {
 	},
 	"text-align": {
 		domProp: "textAlign",
 		inherited: true,
 		type: CSS_TYPE_LONGHAND,
 		// don't know whether left and right are same as start
 		initial_values: [ "start" ],
 		other_values: [ "center", "justify", "end" ],
-		invalid_values: []
+		invalid_values: [ "true", "true true" ]
 	},
 	"-moz-text-align-last": {
 		domProp: "MozTextAlignLast",
 		inherited: true,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "auto" ],
 		other_values: [ "center", "justify", "start", "end", "left", "right" ],
 		invalid_values: []
@@ -4788,9 +4788,14 @@ if (SpecialPowers.getBoolPref("layout.cs
   gCSSProperties["-moz-transition"].invalid_values.push("2s unset");
   gCSSProperties["-moz-transition-property"].invalid_values.push("unset, color", "color, unset");
   gCSSProperties["-moz-animation"].invalid_values.push("2s unset");
   gCSSProperties["-moz-animation-direction"].invalid_values.push("unset, normal");
   gCSSProperties["-moz-animation-name"].invalid_values.push("bounce, unset", "unset, bounce");
   if (SpecialPowers.getBoolPref("layout.css.filters.enabled")) {
     gCSSProperties["filter"].invalid_values.push("drop-shadow(unset, 2px 2px)", "drop-shadow(2px 2px, unset)");
   }
+  if (SpecialPowers.getBoolPref("layout.css.text-align-true-value.enabled")) {
+    gCSSProperties["text-align"].other_values.push("true left");
+  } else {
+    gCSSProperties["text-align"].invalid_values.push("true left");
+  }
 }
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -55,17 +55,16 @@
 #include "mozilla/dom/RTCConfigurationBinding.h"
 #include "mozilla/dom/RTCStatsReportBinding.h"
 #include "mozilla/dom/RTCPeerConnectionBinding.h"
 #include "mozilla/dom/PeerConnectionImplBinding.h"
 #include "mozilla/dom/DataChannelBinding.h"
 #include "MediaStreamList.h"
 #include "MediaStreamTrack.h"
 #include "nsIScriptGlobalObject.h"
-#include "jsapi.h"
 #include "DOMMediaStream.h"
 #endif
 
 #ifndef USE_FAKE_MEDIA_STREAMS
 #include "MediaSegment.h"
 #endif
 
 #ifdef USE_FAKE_PCOBSERVER
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -15,17 +15,16 @@
 #include "AudioConduit.h"
 #include "VideoConduit.h"
 #include "runnable_utils.h"
 
 #ifdef MOZILLA_INTERNAL_API
 #include "MediaStreamList.h"
 #include "nsIScriptGlobalObject.h"
 #include "mozilla/Preferences.h"
-#include "jsapi.h"
 #endif
 
 using namespace mozilla;
 
 namespace sipcc {
 
 static const char* logTag = "PeerConnectionMedia";
 static const mozilla::TrackID TRACK_AUDIO = 0;
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1881,16 +1881,19 @@ pref("layout.css.flexbox.enabled", true)
 
 // Is support for CSS sticky positioning enabled?
 #ifdef RELEASE_BUILD
 pref("layout.css.sticky.enabled", false);
 #else
 pref("layout.css.sticky.enabled", true);
 #endif
 
+// Is support for CSS "text-align: true X" enabled?
+pref("layout.css.text-align-true-value.enabled", false);
+
 // Is support for the CSS4 image-orientation property enabled?
 pref("layout.css.image-orientation.enabled", true);
 
 // Is support for CSS3 Fonts features enabled?
 // (includes font-variant-*, font-kerning, font-synthesis
 // and the @font-feature-values rule)
 // Note: with this enabled, font-feature-settings is aliased
 // to -moz-font-feature-settings.  When unprefixing, this should
--- a/storage/src/mozStoragePrivateHelpers.cpp
+++ b/storage/src/mozStoragePrivateHelpers.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "sqlite3.h"
 
-#include "jsapi.h"
 #include "jsfriendapi.h"
 
 #include "nsPrintfCString.h"
 #include "nsString.h"
 #include "nsError.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
 #include "nsThreadUtils.h"
--- a/toolkit/components/ctypes/tests/jsctypes-test-finalizer.cpp
+++ b/toolkit/components/ctypes/tests/jsctypes-test-finalizer.cpp
@@ -1,13 +1,12 @@
 #include "errno.h"
 
 #include "jsctypes-test.h"
 #include "jsctypes-test-finalizer.h"
-#include "jsapi.h"
 
 #if defined(XP_WIN)
 #define snprintf _snprintf
 #endif // defined(XP_WIN)
 
 /**
  * Shared infrastructure
  */
--- a/toolkit/components/ctypes/tests/jsctypes-test.cpp
+++ b/toolkit/components/ctypes/tests/jsctypes-test.cpp
@@ -1,15 +1,14 @@
 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsctypes-test.h"
-#include "jsapi.h"
 #include "nsCRTGlue.h"
 #include <math.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 #if defined(XP_WIN)
 #define snprintf _snprintf
 #endif // defined(XP_WIN)
--- a/toolkit/devtools/server/nsJSInspector.cpp
+++ b/toolkit/devtools/server/nsJSInspector.cpp
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsJSInspector.h"
 #include "nsIXPConnect.h"
 #include "nsThreadUtils.h"
 #include "nsCxPusher.h"
-#include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/OldDebugAPI.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsMemory.h"
 #include "nsArray.h"
 #include "nsTArray.h"
 
--- a/tools/profiler/nsProfiler.cpp
+++ b/tools/profiler/nsProfiler.cpp
@@ -14,17 +14,17 @@
 #include "nsString.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsILoadContext.h"
 #include "nsIWebNavigation.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "shared-libraries.h"
-#include "jsapi.h"
+#include "js/Value.h"
 
 using std::string;
 
 NS_IMPL_ISUPPORTS1(nsProfiler, nsIProfiler)
 
 nsProfiler::nsProfiler()
   : mLockedForPrivateBrowsing(false)
 {
--- a/widget/xpwidgets/GfxInfoCollector.cpp
+++ b/widget/xpwidgets/GfxInfoCollector.cpp
@@ -45,9 +45,9 @@ InfoObject::DefineProperty(const char *n
   DefineProperty(name, string);
 }
 
 InfoObject::InfoObject(JSContext *aCx) : mCx(aCx), mObj(aCx), mOk(true)
 {
   mObj = JS_NewObject(mCx, NULL, NULL, NULL);
   if (!mObj)
     mOk = false;
-}
\ No newline at end of file
+}
--- a/xpcom/io/nsBinaryStream.cpp
+++ b/xpcom/io/nsBinaryStream.cpp
@@ -22,17 +22,16 @@
 #include "nsCRT.h"
 #include "nsString.h"
 #include "nsISerializable.h"
 #include "nsIClassInfo.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIURI.h" // for NS_IURI_IID
 #include "mozilla/Endian.h"
 
-#include "jsapi.h"
 #include "jsfriendapi.h"
 
 NS_IMPL_ISUPPORTS3(nsBinaryOutputStream, nsIObjectOutputStream, nsIBinaryOutputStream, nsIOutputStream)
 
 NS_IMETHODIMP
 nsBinaryOutputStream::Flush() 
 { 
     NS_ENSURE_STATE(mOutputStream);
--- a/xpfe/appshell/src/nsAppShellService.cpp
+++ b/xpfe/appshell/src/nsAppShellService.cpp
@@ -26,17 +26,16 @@
 #include "nsWidgetInitData.h"
 #include "nsWidgetsCID.h"
 #include "nsIWidget.h"
 #include "nsIRequestObserver.h"
 
 /* For implementing GetHiddenWindowAndJSContext */
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
-#include "jsapi.h"
 
 #include "nsAppShellService.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIPlatformCharset.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsIChromeRegistry.h"
 #include "nsILoadContext.h"