Merge m-c to fx-team a=merge CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Mon, 02 Mar 2015 13:07:53 -0800
changeset 261779 7a4c862d6cf323cafd477359ee961caf0d13b16d
parent 261778 aed265aff73d905958cfd73018d73ea8ec4633f7 (current diff)
parent 261738 0b3c520002adf11e3d1f6147ad1b4c58a99be82e (diff)
child 261780 2b22a22b1cc554ee439d4a999796c8d3f93af17e
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team a=merge CLOSED TREE
browser/themes/linux/Makefile.in
browser/themes/osx/Makefile.in
browser/themes/windows/Makefile.in
build/docs/index.rst
build/docs/mozbuild-files.rst
build/gyp.mozbuild
build/moz.build
config/moz.build
dom/browser-element/mochitest/priority/CAUTION
dom/browser-element/mochitest/priority/test_HighPriorityDowngrade.html
dom/browser-element/mochitest/priority/test_HighPriorityDowngrade2.html
ipc/glue/moz.build
js/src/jsapi-tests/testRegExpInstanceProperties.cpp
mobile/android/chrome/content/browser.js
moz.build
netwerk/build/moz.build
python/moz.build
python/mozbuild/mozbuild/frontend/context.py
python/mozbuild/mozbuild/frontend/emitter.py
python/mozbuild/mozbuild/frontend/mach_commands.py
python/mozbuild/mozbuild/frontend/reader.py
python/mozbuild/mozbuild/test/frontend/test_reader.py
python/mozbuild/mozbuild/test/test_util.py
python/mozbuild/mozbuild/util.py
services/common/moz.build
services/crypto/moz.build
services/sync/moz.build
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -27,20 +27,16 @@ static const uint32_t kGenericAccType = 
  *  This list of WAI-defined roles are currently hardcoded.
  *  Eventually we will most likely be loading an RDF resource that contains this information
  *  Using RDF will also allow for role extensibility. See bug 280138.
  *
  *  Definition of nsRoleMapEntry contains comments explaining this table.
  *
  *  When no Role enum mapping exists for an ARIA role, the role will be exposed
  *  via the object attribute "xml-roles".
- *
- *  There are no Role enums for the following landmark roles:
- *    banner, contentinfo, main, navigation, note, search, secondary,
- *    seealso, breadcrumbs.
  */
 
 static nsRoleMapEntry sWAIRoleMaps[] =
 {
   { // alert
     &nsGkAtoms::alert,
     roles::ALERT,
     kUseMapRole,
@@ -62,30 +58,40 @@ static nsRoleMapEntry sWAIRoleMaps[] =
   },
   { // application
     &nsGkAtoms::application,
     roles::APPLICATION,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
-    kGenericAccType,
+    eLandmark,
     kNoReqStates
   },
   { // article
     &nsGkAtoms::article,
     roles::DOCUMENT,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
     eReadonlyUntilEditable
   },
+  { // banner
+    &nsGkAtoms::banner,
+    roles::NOTHING,
+    kUseNativeRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    eLandmark,
+    kNoReqStates
+  },
   { // button
     &nsGkAtoms::button,
     roles::PUSHBUTTON,
     kUseMapRole,
     eNoValue,
     ePressAction,
     eNoLiveAttr,
     eButton,
@@ -124,16 +130,36 @@ static nsRoleMapEntry sWAIRoleMaps[] =
     eOpenCloseAction,
     eNoLiveAttr,
     kGenericAccType,
     states::COLLAPSED | states::HASPOPUP | states::VERTICAL,
     eARIAAutoComplete,
     eARIAReadonly,
     eARIAOrientation
   },
+  { // complementary
+    &nsGkAtoms::complementary,
+    roles::NOTHING,
+    kUseNativeRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    eLandmark,
+    kNoReqStates
+  },
+  { // contentinfo
+    &nsGkAtoms::contentinfo,
+    roles::NOTHING,
+    kUseNativeRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    eLandmark,
+    kNoReqStates
+  },
   { // dialog
     &nsGkAtoms::dialog,
     roles::DIALOG,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     kGenericAccType,
@@ -162,17 +188,17 @@ static nsRoleMapEntry sWAIRoleMaps[] =
   },
   { // form
     &nsGkAtoms::form,
     roles::FORM,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
-    kGenericAccType,
+    eLandmark,
     kNoReqStates
   },
   { // grid
     &nsGkAtoms::grid,
     roles::TABLE,
     kUseMapRole,
     eNoValue,
     eNoAction,
@@ -285,16 +311,26 @@ static nsRoleMapEntry sWAIRoleMaps[] =
     roles::NOTHING,
     kUseNativeRole,
     eNoValue,
     eNoAction,
     ePoliteLiveAttr,
     kGenericAccType,
     kNoReqStates
   },
+  { // main
+    &nsGkAtoms::main,
+    roles::NOTHING,
+    kUseNativeRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    eLandmark,
+    kNoReqStates
+  },
   { // marquee
     &nsGkAtoms::marquee,
     roles::ANIMATION,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eOffLiveAttr,
     kGenericAccType,
@@ -361,16 +397,26 @@ static nsRoleMapEntry sWAIRoleMaps[] =
     kUseMapRole,
     eNoValue,
     eClickAction,
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
     eARIACheckableBool
   },
+  { // navigation
+    &nsGkAtoms::navigation,
+    roles::NOTHING,
+    kUseNativeRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    eLandmark,
+    kNoReqStates
+  },
   { // none
     &nsGkAtoms::none,
     roles::NOTHING,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     kGenericAccType,
@@ -491,16 +537,39 @@ static nsRoleMapEntry sWAIRoleMaps[] =
     eHasValueMinMax,
     eNoAction,
     eNoLiveAttr,
     kGenericAccType,
     states::VERTICAL,
     eARIAOrientation,
     eARIAReadonly
   },
+  { // search
+    &nsGkAtoms::search,
+    roles::NOTHING,
+    kUseNativeRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    eLandmark,
+    kNoReqStates
+  },
+  { // searchbox
+    &nsGkAtoms::searchbox,
+    roles::ENTRY,
+    kUseMapRole,
+    eNoValue,
+    eActivateAction,
+    eNoLiveAttr,
+    kGenericAccType,
+    kNoReqStates,
+    eARIAAutoComplete,
+    eARIAMultiline,
+    eARIAReadonlyOrEditable
+  },
   { // separator
     &nsGkAtoms::separator_,
     roles::SEPARATOR,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     kGenericAccType,
--- a/accessible/base/AccTypes.h
+++ b/accessible/base/AccTypes.h
@@ -69,23 +69,24 @@ enum AccType {
  */
 enum AccGenericType {
   eAutoComplete = 1 << 0,
   eAutoCompletePopup = 1 << 1,
   eButton = 1 << 2,
   eCombobox = 1 << 3,
   eDocument = 1 << 4,
   eHyperText = 1 << 5,
-  eList = 1 << 6,
-  eListControl = 1 << 7,
-  eMenuButton = 1 << 8,
-  eSelect = 1 << 9,
-  eTable = 1 << 10,
-  eTableCell = 1 << 11,
-  eTableRow = 1 << 12,
+  eLandmark = 1 << 6,
+  eList = 1 << 7,
+  eListControl = 1 << 8,
+  eMenuButton = 1 << 9,
+  eSelect = 1 << 10,
+  eTable = 1 << 11,
+  eTableCell = 1 << 12,
+  eTableRow = 1 << 13,
 
   eLastAccGenericType = eTableRow
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_AccTypes_h
--- a/accessible/base/nsAccUtils.cpp
+++ b/accessible/base/nsAccUtils.cpp
@@ -32,19 +32,26 @@ nsAccUtils::GetAccAttr(nsIPersistentProp
   aAttributes->GetStringProperty(nsAtomCString(aAttrName), aAttrValue);
 }
 
 void
 nsAccUtils::SetAccAttr(nsIPersistentProperties *aAttributes,
                        nsIAtom *aAttrName, const nsAString& aAttrValue)
 {
   nsAutoString oldValue;
-  nsAutoCString attrName;
+  aAttributes->SetStringProperty(nsAtomCString(aAttrName), aAttrValue, oldValue);
+}
 
-  aAttributes->SetStringProperty(nsAtomCString(aAttrName), aAttrValue, oldValue);
+void
+nsAccUtils::SetAccAttr(nsIPersistentProperties *aAttributes,
+                       nsIAtom* aAttrName, nsIAtom* aAttrValue)
+{
+  nsAutoString oldValue;
+  aAttributes->SetStringProperty(nsAtomCString(aAttrName),
+                                 nsAtomString(aAttrValue), oldValue);
 }
 
 void
 nsAccUtils::SetAccGroupAttrs(nsIPersistentProperties *aAttributes,
                              int32_t aLevel, int32_t aSetSize,
                              int32_t aPosInSet)
 {
   nsAutoString value;
--- a/accessible/base/nsAccUtils.h
+++ b/accessible/base/nsAccUtils.h
@@ -45,16 +45,20 @@ public:
    * @param aAttributes - attributes container
    * @param aAttrName - the name of requested attribute
    * @param aAttrValue - new value of attribute
    */
   static void SetAccAttr(nsIPersistentProperties *aAttributes,
                          nsIAtom *aAttrName,
                          const nsAString& aAttrValue);
 
+  static void SetAccAttr(nsIPersistentProperties *aAttributes,
+                         nsIAtom* aAttrName,
+                         nsIAtom* aAttrValue);
+
   /**
    * Set group attributes ('level', 'setsize', 'posinset').
    */
   static void SetAccGroupAttrs(nsIPersistentProperties *aAttributes,
                                int32_t aLevel, int32_t aSetSize,
                                int32_t aPosInSet);
 
   /**
--- a/accessible/generic/Accessible-inl.h
+++ b/accessible/generic/Accessible-inl.h
@@ -40,16 +40,25 @@ Accessible::ARIARole()
 {
   if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
     return mozilla::a11y::roles::NOTHING;
 
   return ARIATransformRole(mRoleMapEntry->role);
 }
 
 inline bool
+Accessible::IsSearchbox() const
+{
+  return (mRoleMapEntry && mRoleMapEntry->Is(nsGkAtoms::searchbox)) ||
+    (mContent->IsHTML(nsGkAtoms::input) &&
+     mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
+                           nsGkAtoms::textInputType, eCaseMatters));
+}
+
+inline bool
 Accessible::HasGenericType(AccGenericType aType) const
 {
   return (mGenericTypes & aType) ||
     (mRoleMapEntry && mRoleMapEntry->IsOfType(aType));
 }
 
 inline bool
 Accessible::HasNumericValue() const
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -855,37 +855,48 @@ Accessible::HandleAccEvent(AccEvent* aEv
 
 already_AddRefed<nsIPersistentProperties>
 Accessible::Attributes()
 {
   nsCOMPtr<nsIPersistentProperties> attributes = NativeAttributes();
   if (!HasOwnContent() || !mContent->IsElement())
     return attributes.forget();
 
-  // 'xml-roles' attribute coming from ARIA.
-  nsAutoString xmlRoles, unused;
-  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::role, xmlRoles)) {
-    attributes->SetStringProperty(NS_LITERAL_CSTRING("xml-roles"),
-                                  xmlRoles, unused);
+  // 'xml-roles' attribute for landmark.
+  nsIAtom* landmark = LandmarkRole();
+  if (landmark) {
+    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles, landmark);
+
+  } else {
+    // 'xml-roles' attribute coming from ARIA.
+    nsAutoString xmlRoles;
+    if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::role, xmlRoles))
+      nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles, xmlRoles);
   }
 
   // Expose object attributes from ARIA attributes.
+  nsAutoString unused;
   aria::AttrIterator attribIter(mContent);
   nsAutoString name, value;
   while(attribIter.Next(name, value))
     attributes->SetStringProperty(NS_ConvertUTF16toUTF8(name), value, unused);
 
   if (IsARIAHidden()) {
     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::hidden,
                            NS_LITERAL_STRING("true"));
   }
 
   // If there is no aria-live attribute then expose default value of 'live'
   // object attribute used for ARIA role of this accessible.
   if (mRoleMapEntry) {
+    if (mRoleMapEntry->Is(nsGkAtoms::searchbox)) {
+      nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType,
+                             NS_LITERAL_STRING("search"));
+    }
+
     nsAutoString live;
     nsAccUtils::GetAccAttr(attributes, nsGkAtoms::live, live);
     if (live.IsEmpty()) {
       if (nsAccUtils::GetLiveAttrValue(mRoleMapEntry->liveAttRule, live))
         nsAccUtils::SetAccAttr(attributes, nsGkAtoms::live, live);
     }
   }
 
@@ -1380,16 +1391,23 @@ Accessible::ARIATransformRole(role aRole
                               nsGkAtoms::_true, eCaseMatters)) {
       return roles::PARENT_MENUITEM;
     }
   }
 
   return aRole;
 }
 
+nsIAtom*
+Accessible::LandmarkRole() const
+{
+  return mRoleMapEntry && mRoleMapEntry->IsOfType(eLandmark) ?
+    *(mRoleMapEntry->roleAtom) : nullptr;
+}
+
 role
 Accessible::NativeRole()
 {
   return roles::NOTHING;
 }
 
 uint8_t
 Accessible::ActionCount()
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -226,16 +226,21 @@ public:
 
   /**
    * Return accessible role specified by ARIA (see constants in
    * roles).
    */
   mozilla::a11y::role ARIARole();
 
   /**
+   * Return a landmark role if applied.
+   */
+  virtual nsIAtom* LandmarkRole() const;
+
+  /**
    * Returns enumerated accessible role from native markup (see constants in
    * Role.h). Doesn't take into account ARIA roles.
    */
   virtual mozilla::a11y::role NativeRole();
 
   /**
    * Return all states of accessible (including ARIA states).
    */
@@ -616,16 +621,18 @@ public:
     return mBits.proxy;
   }
 
   bool IsProgress() const { return mType == eProgressType; }
 
   bool IsRoot() const { return mType == eRootType; }
   a11y::RootAccessible* AsRoot();
 
+  bool IsSearchbox() const;
+
   bool IsSelect() const { return HasGenericType(eSelect); }
 
   bool IsTable() const { return HasGenericType(eTable); }
   virtual TableAccessible* AsTable() { return nullptr; }
 
   bool IsTableCell() const { return HasGenericType(eTableCell); }
   virtual TableCellAccessible* AsTableCell() { return nullptr; }
   const TableCellAccessible* AsTableCell() const
@@ -1093,17 +1100,17 @@ protected:
   nsRefPtr<Accessible> mParent;
   nsTArray<nsRefPtr<Accessible> > mChildren;
   int32_t mIndexInParent;
 
   static const uint8_t kChildrenFlagsBits = 2;
   static const uint8_t kStateFlagsBits = 9;
   static const uint8_t kContextFlagsBits = 2;
   static const uint8_t kTypeBits = 6;
-  static const uint8_t kGenericTypesBits = 13;
+  static const uint8_t kGenericTypesBits = 14;
 
   /**
    * Keep in sync with ChildrenFlags, StateFlags, ContextFlags, and AccTypes.
    */
   uint32_t mChildrenFlags : kChildrenFlagsBits;
   uint32_t mStateFlags : kStateFlagsBits;
   uint32_t mContextFlags : kContextFlagsBits;
   uint32_t mType : kTypeBits;
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -939,69 +939,78 @@ HyperTextAccessible::NativeAttributes()
       strLineNumber.AppendInt(lineNumber);
       nsAccUtils::SetAccAttr(attributes, nsGkAtoms::lineNumber, strLineNumber);
     }
   }
 
   if (!HasOwnContent())
     return attributes.forget();
 
-  // For the html landmark elements we expose them like we do aria landmarks to
-  // make AT navigation schemes "just work".
   nsIAtom* tag = mContent->Tag();
-  if (tag == nsGkAtoms::nav) {
-    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
-                           NS_LITERAL_STRING("navigation"));
-  } else if (tag == nsGkAtoms::section)  {
+  if (tag == nsGkAtoms::section)  {
     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
                            NS_LITERAL_STRING("region"));
-  } else if (tag == nsGkAtoms::header || tag == nsGkAtoms::footer) {
-    // Only map header and footer if they are not descendants
-    // of an article or section tag.
-    nsIContent* parent = mContent->GetParent();
-    while (parent) {
-      if (parent->Tag() == nsGkAtoms::article ||
-          parent->Tag() == nsGkAtoms::section)
-        break;
-      parent = parent->GetParent();
-    }
-
-    // No article or section elements found.
-    if (!parent) {
-      if (tag == nsGkAtoms::header) {
-        nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
-                               NS_LITERAL_STRING("banner"));
-      } else if (tag == nsGkAtoms::footer) {
-        nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
-                               NS_LITERAL_STRING("contentinfo"));
-      }
-    }
-  } else if (tag == nsGkAtoms::aside) {
-    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
-                           NS_LITERAL_STRING("complementary"));
   } else if (tag == nsGkAtoms::article) {
     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
                            NS_LITERAL_STRING("article"));
-  } else if (tag == nsGkAtoms::main) {
-    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
-                           NS_LITERAL_STRING("main"));
   } else if (tag == nsGkAtoms::time) {
     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
                            NS_LITERAL_STRING("time"));
 
     if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::datetime)) {
       nsAutoString datetime;
       mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::datetime, datetime);
       nsAccUtils::SetAccAttr(attributes, nsGkAtoms::datetime, datetime);
     }
   }
 
   return attributes.forget();
 }
 
+nsIAtom*
+HyperTextAccessible::LandmarkRole() const
+{
+  // For the html landmark elements we expose them like we do ARIA landmarks to
+  // make AT navigation schemes "just work".
+  nsIAtom* tag = mContent->Tag();
+  if (tag == nsGkAtoms::nav)
+    return nsGkAtoms::navigation;
+
+  if (tag == nsGkAtoms::header || tag == nsGkAtoms::footer) {
+    // Only map header and footer if they are not descendants of an article
+    // or section tag.
+    nsIContent* parent = mContent->GetParent();
+    while (parent) {
+      if (parent->Tag() == nsGkAtoms::article ||
+          parent->Tag() == nsGkAtoms::section)
+        break;
+      parent = parent->GetParent();
+    }
+
+    // No article or section elements found.
+    if (!parent) {
+      if (tag == nsGkAtoms::header)
+        return nsGkAtoms::banner;
+
+      if (tag == nsGkAtoms::footer) {
+        return nsGkAtoms::contentinfo;
+      }
+    }
+    return nullptr;
+  }
+
+  if (tag == nsGkAtoms::aside)
+    return nsGkAtoms::complementary;
+
+  if (tag == nsGkAtoms::main)
+    return nsGkAtoms::main;
+
+  return nullptr;
+}
+
 int32_t
 HyperTextAccessible::OffsetAtPoint(int32_t aX, int32_t aY, uint32_t aCoordType)
 {
   nsIFrame* hyperFrame = GetFrame();
   if (!hyperFrame)
     return -1;
 
   nsIntPoint coords = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordType,
--- a/accessible/generic/HyperTextAccessible.h
+++ b/accessible/generic/HyperTextAccessible.h
@@ -49,16 +49,17 @@ const char16_t kForcedNewLineChar = '\n'
 class HyperTextAccessible : public AccessibleWrap
 {
 public:
   HyperTextAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // Accessible
+  virtual nsIAtom* LandmarkRole() const MOZ_OVERRIDE;
   virtual int32_t GetLevelInternal() MOZ_OVERRIDE;
   virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() MOZ_OVERRIDE;
   virtual mozilla::a11y::role NativeRole() MOZ_OVERRIDE;
   virtual uint64_t NativeState() MOZ_OVERRIDE;
 
   virtual void InvalidateChildren() MOZ_OVERRIDE;
   virtual bool RemoveChild(Accessible* aAccessible) MOZ_OVERRIDE;
 
--- a/accessible/html/HTMLFormControlAccessible.cpp
+++ b/accessible/html/HTMLFormControlAccessible.cpp
@@ -301,18 +301,23 @@ already_AddRefed<nsIPersistentProperties
 HTMLTextFieldAccessible::NativeAttributes()
 {
   nsCOMPtr<nsIPersistentProperties> attributes =
     HyperTextAccessibleWrap::NativeAttributes();
 
   // Expose type for text input elements as it gives some useful context,
   // especially for mobile.
   nsAutoString type;
-  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type))
+  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type)) {
     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType, type);
+    if (!mRoleMapEntry && type.EqualsLiteral("search")) {
+      nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
+                             NS_LITERAL_STRING("searchbox"));
+    }
+  }
 
   return attributes.forget();
 }
 
 ENameValueFlag
 HTMLTextFieldAccessible::NativeName(nsString& aName)
 {
   ENameValueFlag nameFlag = Accessible::NativeName(aName);
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -425,52 +425,47 @@ GetClosestInterestingAccessible(id anObj
 #undef ROLE
 }
 
 - (NSString*)subrole
 {
   if (!mGeckoAccessible)
     return nil;
 
-  // XXX maybe we should cache the subrole.
-  nsAutoString xmlRoles;
-
-  // XXX we don't need all the attributes (see bug 771113)
-  nsCOMPtr<nsIPersistentProperties> attributes = mGeckoAccessible->Attributes();
-  if (attributes)
-    nsAccUtils::GetAccAttr(attributes, nsGkAtoms::xmlroles, xmlRoles);
-
-  nsWhitespaceTokenizer tokenizer(xmlRoles);
-
-  while (tokenizer.hasMoreTokens()) {
-    const nsDependentSubstring token(tokenizer.nextToken());
-
-    if (token.EqualsLiteral("banner"))
+  nsIAtom* landmark = mGeckoAccessible->LandmarkRole();
+  if (landmark) {
+    if (landmark == nsGkAtoms::application)
+      return @"AXLandmarkApplication";
+    if (landmark == nsGkAtoms::banner)
       return @"AXLandmarkBanner";
-
-    if (token.EqualsLiteral("complementary"))
+    if (landmark == nsGkAtoms::complementary)
       return @"AXLandmarkComplementary";
-
-    if (token.EqualsLiteral("contentinfo"))
+    if (landmark == nsGkAtoms::contentinfo)
       return @"AXLandmarkContentInfo";
-
-    if (token.EqualsLiteral("main"))
+    if (landmark == nsGkAtoms::form)
+      return @"AXLandmarkForm";
+    if (landmark == nsGkAtoms::main)
       return @"AXLandmarkMain";
-
-    if (token.EqualsLiteral("navigation"))
+    if (landmark == nsGkAtoms::navigation)
       return @"AXLandmarkNavigation";
-
-    if (token.EqualsLiteral("search"))
+    if (landmark == nsGkAtoms::search)
       return @"AXLandmarkSearch";
+    if (landmark == nsGkAtoms::searchbox)
+      return @"AXSearchField";
   }
 
   switch (mRole) {
     case roles::LIST:
       return @"AXContentList"; // 10.6+ NSAccessibilityContentListSubrole;
 
+    case roles::ENTRY:
+      if (mGeckoAccessible->IsSearchbox())
+        return @"AXSearchField";
+      break;
+
     case roles::DEFINITION_LIST:
       return @"AXDefinitionList"; // 10.6+ NSAccessibilityDefinitionListSubrole;
 
     case roles::TERM:
       return @"AXTerm";
 
     case roles::DEFINITION:
       return @"AXDefinition";
@@ -480,47 +475,57 @@ GetClosestInterestingAccessible(id anObj
 
     default:
       break;
   }
 
   return nil;
 }
 
+struct RoleDescrMap
+{
+  NSString* role;
+  const nsString& description;
+};
+
+static const RoleDescrMap sRoleDescrMap[] = {
+  { @"AXDefinition", NS_LITERAL_STRING("definition") },
+  { @"AXLandmarkBanner", NS_LITERAL_STRING("banner") },
+  { @"AXLandmarkComplementary", NS_LITERAL_STRING("complementary") },
+  { @"AXLandmarkContentInfo", NS_LITERAL_STRING("content") },
+  { @"AXLandmarkMain", NS_LITERAL_STRING("main") },
+  { @"AXLandmarkNavigation", NS_LITERAL_STRING("navigation") },
+  { @"AXLandmarkSearch", NS_LITERAL_STRING("search") },
+  { @"AXSearchField", NS_LITERAL_STRING("searchTextField") },
+  { @"AXTerm", NS_LITERAL_STRING("term") }
+};
+
+struct RoleDescrComparator
+{
+  const NSString* mRole;
+  explicit RoleDescrComparator(const NSString* aRole) : mRole(aRole) {}
+  int operator()(const RoleDescrMap& aEntry) const {
+    return [mRole compare:aEntry.role];
+  }
+};
+
 - (NSString*)roleDescription
 {
   if (mRole == roles::DOCUMENT)
     return utils::LocalizedString(NS_LITERAL_STRING("htmlContent"));
 
   NSString* subrole = [self subrole];
 
-  if ((mRole == roles::LISTITEM) && [subrole isEqualToString:@"AXTerm"])
-    return utils::LocalizedString(NS_LITERAL_STRING("term"));
-  if ((mRole == roles::PARAGRAPH) && [subrole isEqualToString:@"AXDefinition"])
-    return utils::LocalizedString(NS_LITERAL_STRING("definition"));
-
-  NSString* role = [self role];
-
-  // the WAI-ARIA Landmarks
-  if ([role isEqualToString:NSAccessibilityGroupRole]) {
-    if ([subrole isEqualToString:@"AXLandmarkBanner"])
-      return utils::LocalizedString(NS_LITERAL_STRING("banner"));
-    if ([subrole isEqualToString:@"AXLandmarkComplementary"])
-      return utils::LocalizedString(NS_LITERAL_STRING("complementary"));
-    if ([subrole isEqualToString:@"AXLandmarkContentInfo"])
-      return utils::LocalizedString(NS_LITERAL_STRING("content"));
-    if ([subrole isEqualToString:@"AXLandmarkMain"])
-      return utils::LocalizedString(NS_LITERAL_STRING("main"));
-    if ([subrole isEqualToString:@"AXLandmarkNavigation"])
-      return utils::LocalizedString(NS_LITERAL_STRING("navigation"));
-    if ([subrole isEqualToString:@"AXLandmarkSearch"])
-      return utils::LocalizedString(NS_LITERAL_STRING("search"));
+  size_t idx = 0;
+  if (BinarySearchIf(sRoleDescrMap, 0, ArrayLength(sRoleDescrMap),
+                     RoleDescrComparator(subrole), &idx)) {
+    return utils::LocalizedString(sRoleDescrMap[idx].description);
   }
 
-  return NSAccessibilityRoleDescription(role, subrole);
+  return NSAccessibilityRoleDescription([self role], subrole);
 }
 
 - (NSString*)title
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   nsAutoString title;
   mGeckoAccessible->Name(title);
--- a/accessible/tests/mochitest/attributes/test_obj.html
+++ b/accessible/tests/mochitest/attributes/test_obj.html
@@ -103,16 +103,19 @@ https://bugzilla.mozilla.org/show_bug.cg
       testAbsentAttrs("button", { "text-input-type": "button"});
       testAbsentAttrs("checkbox", { "text-input-type": "checkbox"});
       testAbsentAttrs("radio", { "text-input-type": "radio"});
       testAttrs("email", {"text-input-type" : "email"}, true);
       testAttrs("search", {"text-input-type" : "search"}, true);
       testAttrs("tel", {"text-input-type" : "tel"}, true);
       testAttrs("url", {"text-input-type" : "url"}, true);
 
+      // ARIA
+      testAttrs("searchbox", {"text-input-type" : "search"}, true);
+
       // html
       testAttrs("radio", {"checkable" : "true"}, true); 
       testAttrs("checkbox", {"checkable" : "true"}, true); 
       testAttrs("draggable", {"draggable" : "true"}, true);
       testAttrs("th1", { "abbr": "SS#" }, true);
       testAttrs("th2", { "abbr": "SS#" }, true);
       testAttrs("th2", { "axis": "social" }, true);
 
@@ -178,16 +181,21 @@ https://bugzilla.mozilla.org/show_bug.cg
      title="crash in nsTextEquivUtils::AppendTextEquivFromTextContent">
     Mozilla Bug 819303
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=838407"
      title="aria-hidden false value shouldn't be exposed via object attributes">
     Mozilla Bug 838407
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1121518"
+     title="ARIA 1.1: Support role 'searchbox'">
+    Mozilla Bug 1121518
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <!-- aria -->
   <div id="atomic" aria-atomic="true">live region</div>
   <div id="atomic_false" aria-atomic="false">live region</div>
@@ -237,16 +245,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   </div>
 
   <!-- text input type -->
   <input id="button" type="button"/>
   <input id="email" type="email"/>
   <input id="search" type="search"/>
   <input id="tel" type="tel"/>
   <input id="url" type="url"/>
+  <div id="searchbox" role="searchbox"></div>
 
   <!-- html -->
   <input id="radio" type="radio"/>
   <input id="checkbox" type="checkbox"/>
   <div id="draggable" draggable="true">Draggable div</div>
   <table>
     <tr>
       <th id="th1"><abbr title="Social Security Number">SS#</abbr></th>
--- a/accessible/tests/mochitest/attributes/test_xml-roles.html
+++ b/accessible/tests/mochitest/attributes/test_xml-roles.html
@@ -29,16 +29,18 @@
       testAbsentAttrs("section_footer", {"xml-roles" : "contentinfo"});
       testAttrs("aside", {"xml-roles" : "complementary"}, true);
       testAttrs("section", {"xml-roles" : "region"}, true);
       testAttrs("main", {"xml-roles" : "main"}, true); // // ARIA override
       testAttrs("form", {"xml-roles" : "form"}, true);
       testAttrs("article", {"xml-roles" : "article"}, true);
       testAttrs("main_element", {"xml-roles" : "main"}, true);
 
+      testAttrs("search", {"xml-roles" : "searchbox"}, true);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
@@ -73,16 +75,21 @@
      title="HTML5 article element should expose xml-roles:article object attribute">
     Bug 761891
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=849624"
      title="modify HTML5 header and footer accessibility API mapping">
     Bug 849624
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1121518"
+     title="ARIA 1.1: Support role 'searchbox'">
+    Bug 1121518
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <nav id="nav">a nav</nav>
   <header id="header">a header</header>
   <footer id="footer">a footer</footer>
@@ -96,10 +103,11 @@
   </section>
   <aside id="aside">by the way I am an aside</aside>
   <section id="section">a section</section>
   <article id="main" role="main">a main area</article>
   <article id="form" role="form">a form area</article>
   <article id="article">article</article>
   <main id="main_element">another main area</main>
 
+  <input id="search" type="search"/>
 </body>
 </html>
--- a/accessible/tests/mochitest/events/test_aria_statechange.html
+++ b/accessible/tests/mochitest/events/test_aria_statechange.html
@@ -160,32 +160,32 @@
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=551684"
      title="No statechange event for aria-expanded on native HTML elements, is fired on ARIA widgets">
     Mozilla Bug 551684
   </a><br>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=648133"
-     title="fire state change event for aria-busy"
+     title="fire state change event for aria-busy">
     Mozilla Bug 648133
   </a><br>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=467143"
-     title="mixed state change event is fired for focused accessible only"
+     title="mixed state change event is fired for focused accessible only">
     Mozilla Bug 467143
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=989958"
-     title="Pressed state is not exposed on a button element with aria-pressed attribute"
+     title="Pressed state is not exposed on a button element with aria-pressed attribute">
     Mozilla Bug 989958
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=1136563"
-     title="Support ARIA 1.1 switch role"
+     title="Support ARIA 1.1 switch role">
     Mozilla Bug 1136563
   </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
   <div id="eventdump"></div>
--- a/accessible/tests/mochitest/role/test_aria.html
+++ b/accessible/tests/mochitest/role/test_aria.html
@@ -51,16 +51,17 @@
       testRole("aria_presentation", ROLE_TEXT_CONTAINER); // weak role
       testRole("aria_progressbar", ROLE_PROGRESSBAR);
       testRole("aria_radio", ROLE_RADIOBUTTON);
       testRole("aria_radiogroup", ROLE_GROUPING);
       testRole("aria_region", ROLE_PANE);
       testRole("aria_row", ROLE_ROW);
       testRole("aria_rowheader", ROLE_ROWHEADER);
       testRole("aria_scrollbar", ROLE_SCROLLBAR);
+      testRole("aria_searchbox", ROLE_ENTRY);
       testRole("aria_separator", ROLE_SEPARATOR);
       testRole("aria_slider", ROLE_SLIDER);
       testRole("aria_spinbutton", ROLE_SPINBUTTON);
       testRole("aria_status", ROLE_STATUSBAR);
       testRole("aria_switch", ROLE_SWITCH);
       testRole("aria_tab", ROLE_PAGETAB);
       testRole("aria_tablist", ROLE_PAGETABLIST);
       testRole("aria_tabpanel", ROLE_PROPERTYPAGE);
@@ -176,19 +177,24 @@
   </a>
   <a target="_blank"
      title="Map ARIA role FORM"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=735645">
     Bug 735645
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=1136563"
-     title="Support ARIA 1.1 switch role"
+     title="Support ARIA 1.1 switch role">
     Bug 1136563
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1121518"
+     title="Support ARIA 1.1 searchbox role">
+    Bug 1121518
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <span id="aria_alert" role="alert"/>
   <span id="aria_alertdialog" role="alertdialog"/>
   <span id="aria_application" role="application"/>
@@ -222,16 +228,17 @@
   <span id="aria_presentation" role="presentation" tabindex="0"/>
   <span id="aria_progressbar" role="progressbar"/>
   <span id="aria_radio" role="radio"/>
   <span id="aria_radiogroup" role="radiogroup"/>
   <span id="aria_region" role="region"/>
   <span id="aria_row" role="row"/>
   <span id="aria_rowheader" role="rowheader"/>
   <span id="aria_scrollbar" role="scrollbar"/>
+  <span id="aria_searchbox" role="textbox"/>
   <span id="aria_separator" role="separator"/>
   <span id="aria_slider" role="slider"/>
   <span id="aria_spinbutton" role="spinbutton"/>
   <span id="aria_status" role="status"/>
   <span id="aria_switch" role="switch"/>
   <span id="aria_tab" role="tab"/>
   <span id="aria_tablist" role="tablist"/>
   <span id="aria_tabpanel" role="tabpanel"/>
--- a/accessible/tests/mochitest/states/test_aria.html
+++ b/accessible/tests/mochitest/states/test_aria.html
@@ -344,22 +344,22 @@
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=835121"
      title="ARIA grid should be editable by default">
     Mozilla Bug 835121
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=989958"
-     title="Pressed state is not exposed on a button element with aria-pressed attribute"
+     title="Pressed state is not exposed on a button element with aria-pressed attribute">
     Mozilla Bug 989958
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=1136563"
-     title="Support ARIA 1.1 switch role"
+     title="Support ARIA 1.1 switch role">
     Mozilla Bug 1136563
   </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -118,21 +118,16 @@ SettingsListener.observe('language.curre
   ['mms', 'sms', 'telephony', 'voicemail'].forEach(function(key) {
     SettingsListener.observe('ril.' + key + '.defaultServiceId', 0,
                              function(value) {
       if (value != null) {
         Services.prefs.setIntPref('dom.' + key + '.defaultServiceId', value);
       }
     });
   });
-
-  // Debug flag
-  SettingsListener.observe('ril.debugging.enabled', false, function(value) {
-    Services.prefs.setBoolPref('ril.debugging.enabled', value);
-  });
 })();
 
 //=================== DeviceInfo ====================
 Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
 Components.utils.import('resource://gre/modules/ctypes.jsm');
 (function DeviceInfoToSettings() {
   // MOZ_B2G_VERSION is set in b2g/confvars.sh, and is output as a #define value
   // from configure.in, defaults to 1.0.0 if this value is not exist.
@@ -523,16 +518,17 @@ let settingsToObserve = {
   'layers.draw-borders': false,
   'layers.draw-tile-borders': false,
   'layers.dump': false,
   'layers.enable-tiles': true,
   'layers.effect.invert': false,
   'layers.effect.grayscale': false,
   'layers.effect.contrast': "0.0",
   'privacy.donottrackheader.enabled': false,
+  'ril.debugging.enabled': false,
   'ril.radio.disabled': false,
   'ril.mms.requestReadReport.enabled': {
     prefName: 'dom.mms.requestReadReport',
     defaultValue: true
   },
   'ril.mms.requestStatusReport.enabled': {
     prefName: 'dom.mms.requestStatusReport',
     defaultValue: false
--- a/b2g/components/test/unit/xpcshell.ini
+++ b/b2g/components/test/unit/xpcshell.ini
@@ -22,9 +22,9 @@ tail =
 skip-if = toolkit != "gonk"
 
 [test_logparser.js]
 
 [test_logshake.js]
 
 [test_logshake_gonk.js]
 # only run on b2g builds due to requiring b2g-specific log files to exist
-skip-if = ((toolkit != "gonk") || ((toolkit == "gonk") && (debug == true))) # bug 1125989: disabled because of race condition in OS.File.makeDir
+skip-if = (toolkit != "gonk")
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8ed1085a67490a1ecd7f275e5de9487e1b93b1d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e85143db5d5f6edc4c2b97263c02b558fee757e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1ddea3133e0807350326cee5dcf0d06fad00c08"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8ed1085a67490a1ecd7f275e5de9487e1b93b1d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e85143db5d5f6edc4c2b97263c02b558fee757e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="97c3d9b8b87774ca7a08c89145e95b55652459ef"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1ddea3133e0807350326cee5dcf0d06fad00c08"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8ed1085a67490a1ecd7f275e5de9487e1b93b1d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e85143db5d5f6edc4c2b97263c02b558fee757e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1ddea3133e0807350326cee5dcf0d06fad00c08"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -130,12 +130,12 @@
   <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="libnfcemu" path="external/libnfcemu" remote="b2g" revision="125ccf9bd5986c7728ea44508b3e1d1185ac028b"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c5f8d282efe4a4e8b1e31a37300944e338e60e4f"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="84395037a7a04546e8ef7cb81572eb516b85562b"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="2eac5a8f931ab1c4aa41be7ac02db8a821df6efc"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
   <project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
 </manifest>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8ed1085a67490a1ecd7f275e5de9487e1b93b1d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e85143db5d5f6edc4c2b97263c02b558fee757e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1ddea3133e0807350326cee5dcf0d06fad00c08"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8ed1085a67490a1ecd7f275e5de9487e1b93b1d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e85143db5d5f6edc4c2b97263c02b558fee757e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1ddea3133e0807350326cee5dcf0d06fad00c08"/>
@@ -140,12 +140,13 @@
   <project name="platform_system_core" path="system/core" remote="b2g" revision="4df51d9abf6cc9a6ec49b965e621699e0e6dc4fb"/>
   <default remote="caf" revision="refs/tags/android-5.0.0_r6" sync-j="4"/>
   <!-- Emulator specific things -->
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="ba62cc8b78c30d36181b8060a2016cc8da166236"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="1b9f134d62536c5727575d1f0a5bd4eeb4747d66"/>
   <!-- external/qemu for emulator-l need to be updated in bug-1121378 -->
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="7639c5c496ffd207bb627f2a59b2c5203ae6fefc"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="16abda2258c9aa1ed78f00bb0a9b2b43b4cb919e"/>
+  <project name="platform/development" path="development" revision="7ec1ce5e75f943a4a673aa12d8177d5cf2c0a4cf"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="94704df982a90d2ab74bd620d54155d148c415b2"/>
   <!-- hardware-ril for emulator-l need to be updated in bug-1113054 -->
   <project name="platform/hardware/ril" path="hardware/ril" revision="71dfa8228ad0d6cdf6bac0426ac59404ab74b7f3"/>
 </manifest>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8ed1085a67490a1ecd7f275e5de9487e1b93b1d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e85143db5d5f6edc4c2b97263c02b558fee757e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="97c3d9b8b87774ca7a08c89145e95b55652459ef"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1ddea3133e0807350326cee5dcf0d06fad00c08"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8ed1085a67490a1ecd7f275e5de9487e1b93b1d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e85143db5d5f6edc4c2b97263c02b558fee757e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1ddea3133e0807350326cee5dcf0d06fad00c08"/>
@@ -141,13 +141,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="2a1ded216a91bf62a72b1640cf01ab4998f37028"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="a74adcf8d88320d936daa8d20ce88ca0107fb916"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="9883ea57b0668d8f60dba025d4522dfa69a1fbfa"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="a558dc844bf5144fc38603fd8f4df8d9557052a5"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="57ee1320ed7b4a1a1274d8f3f6c177cd6b9becb2"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="12b1977cc704b35f2e9db2bb423fa405348bc2f3"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="985bf15264d865fe7b9c5b45f61c451cbaafa43d"/>
   <project name="platform/system/core" path="system/core" revision="42839aedcf70bf6bc92a3b7ea4a5cc9bf9aef3f9"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="84395037a7a04546e8ef7cb81572eb516b85562b"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="2eac5a8f931ab1c4aa41be7ac02db8a821df6efc"/>
   <project name="platform/system/qcom" path="system/qcom" revision="63e3f6f176caad587d42bba4c16b66d953fb23c2"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="d8952a42771045fca73ec600e2b42a4c7129d723"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4c187c1f3a0dffd8e51a961735474ea703535b99"/>
 </manifest>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8ed1085a67490a1ecd7f275e5de9487e1b93b1d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e85143db5d5f6edc4c2b97263c02b558fee757e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1ddea3133e0807350326cee5dcf0d06fad00c08"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
@@ -140,13 +140,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="5e110615212302c5d798a3c223dcee458817651c"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="fa9ffd47948eb24466de227e48fe9c4a7c5e7711"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="cd76b19aafd4229ccf83853d02faef8c51ca8b34"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
   <project name="platform/system/core" path="system/core" revision="adc485d8755af6a61641d197de7cfef667722580"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="84395037a7a04546e8ef7cb81572eb516b85562b"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="2eac5a8f931ab1c4aa41be7ac02db8a821df6efc"/>
   <project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="ce18b47b4a4f93a581d672bbd5cb6d12fe796ca9"/>
 </manifest>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f", 
+        "git_revision": "c8ed1085a67490a1ecd7f275e5de9487e1b93b1d", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "c00390d70e15726ba3e4c50bd2353fbf991f25c9", 
+    "revision": "45fe49a5560cdaa07920739af65722a63b2de4f9", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8ed1085a67490a1ecd7f275e5de9487e1b93b1d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e85143db5d5f6edc4c2b97263c02b558fee757e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1ddea3133e0807350326cee5dcf0d06fad00c08"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -125,17 +125,17 @@
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
   <!-- Nexus 4 specific things -->
   <project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="84395037a7a04546e8ef7cb81572eb516b85562b"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="2eac5a8f931ab1c4aa41be7ac02db8a821df6efc"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
   <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/>
   <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="f34ce82a840ad3c0aed3bfff18517b3f6a0eb37f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8ed1085a67490a1ecd7f275e5de9487e1b93b1d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2e85143db5d5f6edc4c2b97263c02b558fee757e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1ddea3133e0807350326cee5dcf0d06fad00c08"/>
@@ -152,10 +152,10 @@
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="0a21f566d8c9b01b9754d639e13358bdcb6c7650"/>
   <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="028649652cd8f8f18cfb47d34bd78c435eb030ca"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="758a80fbb178b5663d4edbb46944b2dc553cb1ca"/>
   <project name="platform/hardware/qcom/msm8x74" path="hardware/qcom/msm8x74" revision="aa0124820e22302149b1f2db603a9a72f1972527"/>
   <project name="platform/hardware/qcom/power" path="hardware/qcom/power" revision="37499eb89f31233135ca73b830b067ab24dc1be2"/>
   <project name="platform/hardware/qcom/sensors" path="hardware/qcom/sensors" revision="3724fd91ef5183684d97e2bf1d7ff948faabe090"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2e54754cc0529d26ccac37ed291600048adbf6c0"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="71dfa8228ad0d6cdf6bac0426ac59404ab74b7f3"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="84395037a7a04546e8ef7cb81572eb516b85562b"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="2eac5a8f931ab1c4aa41be7ac02db8a821df6efc"/>
 </manifest>
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -457,33 +457,38 @@
 #endif // MOZ_WIDGET_GONK
 
 ; RIL
 #if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
 @BINPATH@/components/CellBroadcastService.js
 @BINPATH@/components/CellBroadcastService.manifest
 @BINPATH@/components/MmsService.js
 @BINPATH@/components/MmsService.manifest
+@BINPATH@/components/MobileMessageDatabaseService.js
+@BINPATH@/components/MobileMessageDatabaseService.manifest
+#ifndef DISABLE_MOZ_RIL_GEOLOC
 @BINPATH@/components/MobileConnectionService.js
 @BINPATH@/components/MobileConnectionService.manifest
-@BINPATH@/components/MobileMessageDatabaseService.js
-@BINPATH@/components/MobileMessageDatabaseService.manifest
 @BINPATH@/components/RadioInterfaceLayer.js
 @BINPATH@/components/RadioInterfaceLayer.manifest
+@BINPATH@/components/SmsService.js
+@BINPATH@/components/SmsService.manifest
+#endif
 @BINPATH@/components/RILContentHelper.js
+@BINPATH@/components/RILContentHelper.manifest
 @BINPATH@/components/RILSystemMessengerHelper.js
 @BINPATH@/components/RILSystemMessengerHelper.manifest
-@BINPATH@/components/SmsService.js
-@BINPATH@/components/SmsService.manifest
 @BINPATH@/components/TelephonyAudioService.js
 @BINPATH@/components/TelephonyAudioService.manifest
+#ifndef DISABLE_MOZ_RIL_GEOLOC
 @BINPATH@/components/TelephonyService.js
 @BINPATH@/components/TelephonyService.manifest
 @BINPATH@/components/VoicemailService.js
 @BINPATH@/components/VoicemailService.manifest
+#endif
 #endif // MOZ_WIDGET_GONK && MOZ_B2G_RIL
 
 #ifndef MOZ_WIDGET_GONK
 @BINPATH@/components/extensions.manifest
 @BINPATH@/components/addonManager.js
 @BINPATH@/components/amContentHandler.js
 @BINPATH@/components/amInstallTrigger.js
 @BINPATH@/components/amWebInstallListener.js
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1423697587000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1424991539000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i71" id="youtube@2youtube.com">
@@ -68,16 +68,24 @@
               </prefs>
     </emItem>
       <emItem  blockID="i72" os="WINNT" id="{4ED1F68A-5463-4931-9384-8FFF5ED91D92}">
                         <versionRange  minVersion="3.4.1" maxVersion="3.4.1.194" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
+      <emItem  blockID="i862" id="{CA8C84C6-3918-41b1-BE77-049B2BDD887C}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                    <prefs>
+                  <pref>browser.startup.homepage</pref>
+                  <pref>browser.search.defaultenginename</pref>
+              </prefs>
+    </emItem>
       <emItem  blockID="i430" id="1chtw@facebook.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i238" id="/^pink@.*\.info$/">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
@@ -116,18 +124,18 @@
               </prefs>
     </emItem>
       <emItem  blockID="i500" id="{2aab351c-ad56-444c-b935-38bffe18ad26}">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
-      <emItem  blockID="i810" id="{41339ee8-61ed-489d-b049-01e41fd5d7e0}">
-                        <versionRange  minVersion="0" maxVersion="*" severity="3">
+      <emItem  blockID="i364" id="{FE1DEEEA-DB6D-44b8-83F0-34FC0F9D1052}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i467" id="plugin@analytic-s.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
@@ -382,17 +390,17 @@
               </prefs>
     </emItem>
       <emItem  blockID="i461" id="{8E9E3331-D360-4f87-8803-52DE43566502}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
-      <emItem  blockID="i404" id="{a9bb9fa0-4122-4c75-bd9a-bc27db3f9155}">
+      <emItem  blockID="i860" id="PrivDog@AdTrustMedia.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i83" id="flash@adobee.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
@@ -737,16 +745,22 @@
                     </versionRange>
                                 <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                                 <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
+      <emItem  blockID="i340" id="chiang@programmer.net">
+                        <versionRange  minVersion="0" maxVersion="*" severity="3">
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
       <emItem  blockID="i99" id="pfzPXmnzQRXX6@2iABkVe.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i111" os="WINNT" id="{C3949AC2-4B17-43ee-B4F1-D26B9D42404D}">
                         <versionRange  minVersion="0" maxVersion="15.0.5" severity="1">
@@ -1015,16 +1029,22 @@
       <emItem  blockID="i61" id="youtube@youtube3.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                                 <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
+      <emItem  blockID="i91" id="crossriderapp4926@crossrider.com">
+                        <versionRange  minVersion="0" maxVersion="0.81.43" severity="1">
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
       <emItem  blockID="i700" id="2bbadf1f-a5af-499f-9642-9942fcdb7c76@f05a14cc-8842-4eee-be17-744677a917ed.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i696" id="/^({fa95f577-07cb-4470-ac90-e843f5f83c52}|ffxtlbr@speedial\.com)$/">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
@@ -1955,18 +1975,18 @@
               </prefs>
     </emItem>
       <emItem  blockID="i77" id="{fa277cfc-1d75-4949-a1f9-4ac8e41b2dfd}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
-      <emItem  blockID="i364" id="{FE1DEEEA-DB6D-44b8-83F0-34FC0F9D1052}">
-                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+      <emItem  blockID="i810" id="{41339ee8-61ed-489d-b049-01e41fd5d7e0}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i59" id="ghostviewer@youtube2.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                     <prefs>
@@ -2079,18 +2099,18 @@
               </prefs>
     </emItem>
       <emItem  blockID="i588" id="quick_start@gmail.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
-      <emItem  blockID="i340" id="chiang@programmer.net">
-                        <versionRange  minVersion="0" maxVersion="*" severity="3">
+      <emItem  blockID="i866" id="faststartff@gmail.com">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i54" id="applebeegifts@mozilla.doslash.org">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                     <prefs>
@@ -2152,20 +2172,34 @@
               </prefs>
     </emItem>
       <emItem  blockID="i694" id="59D317DB041748fdB89B47E6F96058F3@jetpack">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
-      <emItem  blockID="i91" id="crossriderapp4926@crossrider.com">
-                        <versionRange  minVersion="0" maxVersion="0.81.43" severity="1">
-                    </versionRange>
-                    <prefs>
+      <emItem  blockID="i404" id="{a9bb9fa0-4122-4c75-bd9a-bc27db3f9155}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
+      <emItem  blockID="i868" id="{6e7f6f9f-8ce6-4611-add2-05f0f7049ee6}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
+      <emItem  blockID="i864" id="{0A92F062-6AC6-8180-5881-B6E0C0DC2CC5}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                    <prefs>
+                  <pref>browser.startup.homepage</pref>
+                  <pref>browser.search.defaultenginename</pref>
               </prefs>
     </emItem>
       <emItem  blockID="i814" id="liiros@facebook.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1755,22 +1755,29 @@ pref("security.cert_pinning.enforcement_
 // Override the Gecko-default value of false for Firefox.
 pref("plain_text.wrap_long_lines", true);
 
 // If this turns true, Moz*Gesture events are not called stopPropagation()
 // before content.
 pref("dom.debug.propagate_gesture_events_through_content", false);
 
 // The request URL of the GeoLocation backend.
+#ifdef RELEASE_BUILD
+pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%");
+#else
 pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
+#endif
 
-// On Mac, the default geo provider is corelocation.
 #ifdef XP_MACOSX
+#ifdef RELEASE_BUILD
+pref("geo.provider.use_corelocation", false);
+#else
 pref("geo.provider.use_corelocation", true);
 #endif
+#endif
 
 // Necko IPC security checks only needed for app isolation for cookies/cache/etc:
 // currently irrelevant for desktop e10s
 pref("network.disable.ipc.security", true);
 
 // CustomizableUI debug logging.
 pref("browser.uiCustomization.debug", false);
 
--- a/browser/base/content/docs/sslerrorreport/dataformat.rst
+++ b/browser/base/content/docs/sslerrorreport/dataformat.rst
@@ -1,9 +1,9 @@
-.. _healthreport_dataformat:
+.. _sslerrorreport_dataformat:
 
 ==============
 Payload Format
 ==============
 
 An example report::
 
   {
--- a/browser/base/content/docs/sslerrorreport/index.rst
+++ b/browser/base/content/docs/sslerrorreport/index.rst
@@ -1,9 +1,9 @@
-.. _sslerrorreport
+.. _sslerrorreport:
 
 ===================
 SSL Error Reporting
 ===================
 
 With the introduction of HPKP, it becomes useful to be able to capture data
 on pin violations. SSL Error Reporting is an opt-in mechanism to allow users
 to send data on such violations to mozilla.
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -976,17 +976,17 @@
           <![CDATA[
             var newTitle = "";
             var docElement = this.ownerDocument.documentElement;
             var sep = docElement.getAttribute("titlemenuseparator");
 
             // Strip out any null bytes in the content title, since the
             // underlying widget implementations of nsWindow::SetTitle pass
             // null-terminated strings to system APIs.
-            var docTitle = aBrowser.contentTitle.replace("\0", "", "g");
+            var docTitle = aBrowser.contentTitle.replace(/\0/g, "");
 
             if (!docTitle)
               docTitle = docElement.getAttribute("titledefault");
 
             var modifier = docElement.getAttribute("titlemodifier");
             if (docTitle) {
               newTitle += docElement.getAttribute("titlepreface");
               newTitle += docTitle;
@@ -3224,18 +3224,17 @@
                                           browser: browser,
                                           editFlags: aMessage.data.editFlags,
                                           spellInfo: spellInfo,
                                           principal: aMessage.data.principal,
                                           customMenuItems: aMessage.data.customMenuItems,
                                           addonInfo: aMessage.data.addonInfo };
               let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
               let event = gContextMenuContentData.event;
-              let pos = browser.mapScreenCoordinatesFromContent(event.screenX, event.screenY);
-              popup.openPopupAtScreen(pos.x, pos.y, true);
+              popup.openPopupAtScreen(event.screenX, event.screenY, true);
               break;
             }
             case "DOMWebNotificationClicked": {
               let tab = this.getTabForBrowser(browser);
               if (!tab)
                 return;
               this.selectedTab = tab;
               window.focus();
--- a/browser/base/content/test/general/browser_bug321000.js
+++ b/browser/base/content/test/general/browser_bug321000.js
@@ -10,17 +10,17 @@ var gTests = [
 
   { desc: "Urlbar strips newlines and surrounding whitespace",
     element: gURLBar,
     expected: kTestString.replace(/\s*\n\s*/g,'')
   },
 
   { desc: "Searchbar replaces newlines with spaces",
     element: document.getElementById('searchbar'),
-    expected: kTestString.replace('\n',' ','g')
+    expected: kTestString.replace(/\n/g,' ')
   },
 
 ];
 
 // Test for bug 23485 and bug 321000.
 // Urlbar should strip newlines,
 // search bar should replace newlines with spaces.
 function test() {
--- a/browser/components/distribution.js
+++ b/browser/components/distribution.js
@@ -318,17 +318,17 @@ DistributionCustomizer.prototype = {
 
     let localizedStr = Cc["@mozilla.org/pref-localizedstring;1"].
       createInstance(Ci.nsIPrefLocalizedString);
 
     if (sections["LocalizablePreferences"]) {
       for (let key in enumerate(this._ini.getKeys("LocalizablePreferences"))) {
         try {
           let value = eval(this._ini.getString("LocalizablePreferences", key));
-          value = value.replace("%LOCALE%", this._locale, "g");
+          value = value.replace(/%LOCALE%/g, this._locale);
           localizedStr.data = "data:text/plain," + key + "=" + value;
           defaults.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
         } catch (e) { /* ignore bad prefs and move on */ }
       }
     }
 
     if (sections["LocalizablePreferences-" + this._locale]) {
       for (let key in enumerate(this._ini.getKeys("LocalizablePreferences-" + this._locale))) {
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -3271,17 +3271,17 @@ let SessionStoreInternal = {
     if (!aWinState.cookies || !aWinState.cookies.length)
       return;
 
     // Get the hosts for history entries in aTargetWinState
     let cookieHosts = SessionCookies.getHostsForWindow(aTargetWinState);
 
     // By creating a regex we reduce overhead and there is only one loop pass
     // through either array (cookieHosts and aWinState.cookies).
-    let hosts = Object.keys(cookieHosts).join("|").replace("\\.", "\\.", "g");
+    let hosts = Object.keys(cookieHosts).join("|").replace(/\./g, "\\.");
     // If we don't actually have any hosts, then we don't want to do anything.
     if (!hosts.length)
       return;
     let cookieRegex = new RegExp(".*(" + hosts + ")");
     for (let cIndex = 0; cIndex < aWinState.cookies.length;) {
       if (cookieRegex.test(aWinState.cookies[cIndex].host)) {
         aTargetWinState.cookies =
           aTargetWinState.cookies.concat(aWinState.cookies.splice(cIndex, 1));
--- a/browser/components/tabview/search.js
+++ b/browser/components/tabview/search.js
@@ -95,17 +95,17 @@ TabMatcher.prototype = {
   // Given an array of <TabItem>s and <xul:tab>s returns a new array
   // of tabs whose name matched the search term, sorted by lexical
   // closeness.
   _filterAndSortForMatches: function TabMatcher__filterAndSortForMatches(tabs) {
     let self = this;
     tabs = tabs.filter(function TabMatcher__filterAndSortForMatches_filter(tab) {
       let name = TabUtils.nameOf(tab);
       let url = TabUtils.URLOf(tab);
-      return name.match(self.term, "i") || url.match(self.term, "i");
+      return name.match(new RegExp(self.term, "i")) || url.match(new RegExp(self.term, "i"));
     });
 
     tabs.sort(function TabMatcher__filterAndSortForMatches_sort(x, y) {
       let yScore = self._scorePatternMatch(self.term, TabUtils.nameOf(y));
       let xScore = self._scorePatternMatch(self.term, TabUtils.nameOf(x));
       return yScore - xScore;
     });
 
@@ -116,17 +116,17 @@ TabMatcher.prototype = {
   // Function: _filterForUnmatches
   // Given an array of <TabItem>s returns an unsorted array of tabs whose name
   // does not match the the search term.
   _filterForUnmatches: function TabMatcher__filterForUnmatches(tabs) {
     let self = this;
     return tabs.filter(function TabMatcher__filterForUnmatches_filter(tab) {
       let name = tab.$tabTitle[0].textContent;
       let url = TabUtils.URLOf(tab);
-      return !name.match(self.term, "i") && !url.match(self.term, "i");
+      return !name.match(new RegExp(self.term, "i")) && !url.match(new RegExp(self.term, "i"));
     });
   },
 
   // ---------
   // Function: _getTabsForOtherWindows
   // Returns an array of <TabItem>s and <xul:tabs>s representing tabs
   // from all windows but the current window. <TabItem>s will be returned
   // for windows in which Panorama has been activated at least once, while
--- a/browser/components/translation/BingTranslator.jsm
+++ b/browser/components/translation/BingTranslator.jsm
@@ -202,17 +202,17 @@ this.BingTranslator.prototype = {
     for (let i = 0; i < len; i++) {
       try {
         let result = results[i].firstChild.nodeValue;
         let root = bingRequest.translationData[i][0];
 
         if (root.isSimpleRoot) {
           // Workaround for Bing's service problem in which "&" chars in
           // plain-text TranslationItems are double-escaped.
-          result = result.replace("&amp;", "&", "g");
+          result = result.replace(/&amp;/g, "&");
         }
 
         root.parseResult(result);
       } catch (e) { error = true; }
     }
 
     return !error;
   },
@@ -417,21 +417,21 @@ let BingTokenManager = {
   }
 };
 
 /**
  * Escape a string to be valid XML content.
  */
 function escapeXML(aStr) {
   return aStr.toString()
-             .replace("&", "&amp;", "g")
-             .replace('"', "&quot;", "g")
-             .replace("'", "&apos;", "g")
-             .replace("<", "&lt;", "g")
-             .replace(">", "&gt;", "g");
+             .replace(/&/g, "&amp;")
+             .replace(/\"/g, "&quot;")
+             .replace(/\'/g, "&apos;")
+             .replace(/</g, "&lt;")
+             .replace(/>/g, "&gt;");
 }
 
 /**
  * Fetch an auth token (clientID or client secret), which may be overridden by
  * a pref if it's set.
  */
 function getUrlParam(paramValue, prefName, encode = true) {
   if (Services.prefs.getPrefType(prefName))
--- a/browser/docs/UITelemetry.rst
+++ b/browser/docs/UITelemetry.rst
@@ -1,17 +1,17 @@
 =======================
 UITelemetry data format
 =======================
 
 UI Telemetry sends its data as a JSON blob. This document describes the different parts
 of the JSON blob.
 
 ``toolbars``
-------------
+============
 
 This tracks the state of the user's UI customizations. It has the following properties:
 
 - ``sizemode`` - string indicating whether the window is in maximized, normal (restored) or
   fullscreen mode;
 - ``bookmarksBarEnabled`` - boolean indicating whether the bookmarks bar is visible;
 - ``menuBarEnabled`` - boolean indicating whether the menu bar is visible (always false on OS X);
 - ``titleBarEnabled`` - boolean indicating whether the (real) titlebar is visible (rather than
@@ -29,25 +29,26 @@ This tracks the state of the user's UI c
 - ``addonToolbars`` - the number of non-default toolbars that are customizable. 1 by default
   because it counts the add-on bar shim;
 - ``visibleTabs`` - array of the number of visible tabs per window;
 - ``hiddenTabs`` - array of the number of hidden tabs per window (ie tabs in panorama groups which
   are not the current group);
 - ``countableEvents`` - please refer to the next section.
 - ``durations`` - an object mapping descriptions to duration records, which records the amount of
   time a user spent doing something. Currently only has one property:
-   - ``customization`` - how long a user spent customizing the browser. This is an array of
-     objects, where each object has a ``duration`` property indicating the time in milliseconds,
-     and a ``bucket`` property indicating a bucket in which the duration info falls.
+
+  - ``customization`` - how long a user spent customizing the browser. This is an array of
+    objects, where each object has a ``duration`` property indicating the time in milliseconds,
+    and a ``bucket`` property indicating a bucket in which the duration info falls.
 
 
 .. _UITelemetry_countableEvents:
 
 ``countableEvents``
--------------------
+===================
 
 Countable events are stored under the ``toolbars`` section. They count the number of times certain
 events happen. No timing or other correlating information is stored - purely the number of times
 things happen.
 
 ``countableEvents`` contains a list of buckets as its properties. A bucket represents the state the browser was in when these events occurred, such as currently running an interactive tour. There are 3 types of buckets:
 
 - ``__DEFAULT__`` - No bucket, for times when the browser is not in any special state.
@@ -61,58 +62,64 @@ Each bucket is an object with the follow
   storing a number indicating how often the respective type of click has happened.
 - ``click-menu-button`` is the same, except the item ID is always 'button'.
 - ``click-bookmarks-bar`` is the same, with the item IDs being replaced by either ``container`` for
   clicks on bookmark or livemark folders, and ``item`` for individual bookmarks.
 - ``click-menubar`` is similar, with the item IDs being replaced by one of ``menu``, ``menuitem``
   or ``other``, depending on the kind of item clicked. Note that this is not tracked on OS X, where
   we can't listen for these events because of the global menubar.
 - ``click-bookmarks-menu-button`` is also similar, with the item IDs being replaced by:
-   - ``menu`` for clicks on the 'menu' part of the item;
-   - ``add`` for clicks that add a bookmark;
-   - ``edit`` for clicks that open the panel to edit an existing bookmark;
-   - ``in-panel`` for clicks when the button is in the menu panel, and clicking it does none of the
+
+  - ``menu`` for clicks on the 'menu' part of the item;
+  - ``add`` for clicks that add a bookmark;
+  - ``edit`` for clicks that open the panel to edit an existing bookmark;
+  - ``in-panel`` for clicks when the button is in the menu panel, and clicking it does none of the
      above;
 - ``customize`` tracks different types of customization events without the ``left``, ``middle`` and
   ``right`` distinctions. The different events are the following, with each storing a count of the
   number of times they occurred:
-   - ``start`` counts the number of times the user starts customizing;
-   - ``add`` counts the number of times an item is added somewhere from the palette;
-   - ``move`` counts the number of times an item is moved somewhere else (but not to the palette);
-   - ``remove`` counts the number of times an item is removed to the palette;
-   - ``reset`` counts the number of times the 'restore defaults' button is used;
+
+  - ``start`` counts the number of times the user starts customizing;
+  - ``add`` counts the number of times an item is added somewhere from the palette;
+  - ``move`` counts the number of times an item is moved somewhere else (but not to the palette);
+  - ``remove`` counts the number of times an item is removed to the palette;
+  - ``reset`` counts the number of times the 'restore defaults' button is used;
 - ``search`` is an object tracking searches of various types, keyed off the search
     location, storing a number indicating how often the respective type of search
     has happened.
+
   - There are also two special keys that mean slightly different things.
+
     - ``urlbar-keyword`` records searches that would have been an invalid-protocol
       error, but are now keyword searches.  They are also counted in the ``urlbar``
       keyword (along with all the other urlbar searches).
     - ``selection`` searches records selections of search suggestions.  They include
       the source, the index of the selection, and the kind of selection (mouse or
       enter key).  Selection searches are also counted in their sources.
 
 
 
 ``UITour``
-----------
+==========
+
 The UITour API provides ways for pages on trusted domains to safely interact with the browser UI and request it to perform actions such as opening menus and showing highlights over the browser chrome - for the purposes of interactive tours. We track some usage of this API via the ``UITour`` object in the UI Telemetry output.
 
 Each page is able to register itself with an identifier, a ``Page ID``. A list of Page IDs that have been seen over the last 8 weeks is available via ``seenPageIDs``.
 
 Page IDs are also used to identify buckets for :ref:`UITelemetry_countableEvents`, in the following circumstances:
 
 - The current tab is a tour page. This will be a normal bucket with the name ``UITour|<PAGEID>``, where ``<PAGEID>`` is the page's registered ID. This will result in bucket IDs such as ``bucket_UITour|australis-tour``.
 - A tour tab is open but another tab is active. This will be an expiring bucket with the name ``UITour|<PAGEID>|inactive``. This will result in bucket IDs such as ``bucket_UITour|australis-tour|inactive|1m``.
 - A tour tab has recently been open but has been closed. This will be an expiring bucket with the name ``UITour|<PAGEID>|closed``. This will result in bucket IDs such as ``bucket_UITour|australis-tour|closed|10m``.
 
 
 
 ``contextmenu``
----------------
+===============
+
 We track context menu interactions to figure out which ones are most often used and/or how
 effective they are. In the ``contextmenu`` object, we first store things per-bucket. Next, we
 divide the following different context menu situations:
 
 - ``selection`` if there is content on the page that's selected on which the user clicks;
 - ``link`` if the user opened the context menu for a link
 - ``image-link`` if the user opened the context menu on an image or canvas that's a link;
 - ``image`` if the user opened the context menu on an image (that isn't a link);
--- a/browser/metro/base/content/browser.js
+++ b/browser/metro/base/content/browser.js
@@ -756,17 +756,17 @@ var Browser = {
                  createInstance(Ci.nsICryptoHash);
     hasher.init(Ci.nsICryptoHash.MD5);
     let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].
                        createInstance(Ci.nsIStringInputStream);
     stringStream.data = Browser.selectedBrowser.currentURI.spec;
     hasher.updateFromStream(stringStream, -1);
     let hashASCII = hasher.finish(true);
     // Replace '/' with a valid filesystem character
-    return ("FFTileID_" + hashASCII).replace('/', '_', 'g');
+    return ("FFTileID_" + hashASCII).replace(/\//g, '_');
   },
 
   unpinSite: function browser_unpinSite() {
     if (!Services.metro.immersive)
       return;
 
     Services.metro.unpinTileAsync(this._currentPageTileID);
   },
--- a/browser/metro/components/BrowserCLH.js
+++ b/browser/metro/components/BrowserCLH.js
@@ -188,17 +188,17 @@ BrowserCLH.prototype = {
         uris.push(uri);
     }
 
     // Check for the "search" flag
     let searchParam = aCmdLine.handleFlagWithParam("search", false);
     if (searchParam) {
       var ss = Components.classes["@mozilla.org/browser/search-service;1"]
                          .getService(nsIBrowserSearchService);
-      var submission = ss.defaultEngine.getSubmission(searchParam.replace("\"", "", "g"));
+      var submission = ss.defaultEngine.getSubmission(searchParam.replace(/\"/g, ""));
       uris.push(submission.uri);
     }
 
     for (let i = 0; i < aCmdLine.length; i++) {
       let arg = aCmdLine.getArgument(i);
       if (!arg || arg[0] == '-')
         continue;
 
deleted file mode 100644
--- a/browser/themes/linux/Makefile.in
+++ /dev/null
@@ -1,27 +0,0 @@
-# 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/.
-
-ICON_FILES := ../shared/icon.png
-ICON_DEST = $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
-INSTALL_TARGETS += ICON
-
-# By default, the pre-processor used for jar.mn will use "%" as a marker for ".css" files and "#"
-# otherwise. This falls apart when a file using one marker needs to include a file with the other
-# marker since the pre-processor instructions in the included file will not be processed. The
-# following SVG files need to include a file which uses "%" as the marker so we invoke the pre-
-# processor ourselves here with the marker specified. The resulting SVG files will get packaged by
-# the processing of the jar file in this directory.
-tab-selected-svg: $(srcdir)/../shared/tab-selected.svg
-	$(call py_action,preprocessor, \
-	  --marker % -D TAB_SIDE=start \
-	  $(ACDEFINES) \
-	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-start.svg)
-	$(call py_action,preprocessor, \
-	  --marker % -D TAB_SIDE=end \
-	  $(ACDEFINES) \
-	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-end.svg)
-
-.PHONY: tab-selected-svg
-
-export:: tab-selected-svg
--- a/browser/themes/linux/moz.build
+++ b/browser/themes/linux/moz.build
@@ -2,8 +2,10 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['communicator']
 
 JAR_MANIFESTS += ['jar.mn']
+
+include('../tab-svgs.mozbuild')
--- a/browser/themes/moz.build
+++ b/browser/themes/moz.build
@@ -7,8 +7,10 @@
 toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
 
 if toolkit == 'cocoa':
     DIRS += ['osx']
 elif toolkit in ('gtk2', 'gtk3', 'qt'):
     DIRS += ['linux']
 else:
     DIRS += ['windows']
+
+FINAL_TARGET_FILES.extensions['{972ce4c6-7e08-4474-a285-3208198ce6fd}'] += ['shared/icon.png']
deleted file mode 100644
--- a/browser/themes/osx/Makefile.in
+++ /dev/null
@@ -1,27 +0,0 @@
-# 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/.
-
-ICON_FILES := ../shared/icon.png
-ICON_DEST = $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
-INSTALL_TARGETS += ICON
-
-# By default, the pre-processor used for jar.mn will use "%" as a marker for ".css" files and "#"
-# otherwise. This falls apart when a file using one marker needs to include a file with the other
-# marker since the pre-processor instructions in the included file will not be processed. The
-# following SVG files need to include a file which uses "%" as the marker so we invoke the pre-
-# processor ourselves here with the marker specified. The resulting SVG files will get packaged by
-# the processing of the jar file in this directory.
-tab-selected-svg: $(srcdir)/../shared/tab-selected.svg
-	$(call py_action,preprocessor, \
-	  --marker % -D TAB_SIDE=start \
-	  $(ACDEFINES) \
-	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-start.svg)
-	$(call py_action,preprocessor, \
-	  --marker % -D TAB_SIDE=end \
-	  $(ACDEFINES) \
-	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-end.svg)
-
-.PHONY: tab-selected-svg
-
-export:: tab-selected-svg
--- a/browser/themes/osx/moz.build
+++ b/browser/themes/osx/moz.build
@@ -2,8 +2,10 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['communicator']
 
 JAR_MANIFESTS += ['jar.mn']
+
+include('../tab-svgs.mozbuild')
new file mode 100755
--- /dev/null
+++ b/browser/themes/preprocess-tab-svgs.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import buildconfig
+
+from mozbuild.preprocessor import preprocess
+
+# By default, the pre-processor used for jar.mn will use "%" as a marker
+# for ".css" files and "#" otherwise. This falls apart when a file using
+# one marker needs to include a file with the other marker since the
+# pre-processor instructions in the included file will not be
+# processed. The following SVG files need to include a file which uses
+# "%" as the marker so we invoke the pre- processor ourselves here with
+# the marker specified. The resulting SVG files will get packaged by the
+# processing of the jar file in the appropriate directory.
+def _do_preprocessing(output_svg, input_svg_file, additional_defines):
+    additional_defines.update(buildconfig.defines)
+    preprocess(output=output_svg,
+               includes=[input_svg_file],
+               marker='%',
+               defines=additional_defines)
+
+def tab_side_start(output_svg, input_svg_file):
+    _do_preprocessing(output_svg, input_svg_file, {'TAB_SIDE': 'start'})
+
+def tab_side_end(output_svg, input_svg_file):
+    _do_preprocessing(output_svg, input_svg_file, {'TAB_SIDE': 'end'})
+
+def aero_tab_side_start(output_svg, input_svg_file):
+    _do_preprocessing(output_svg, input_svg_file,
+                      {'TAB_SIDE': 'start',
+                       'WINDOWS_AERO': 1})
+
+def aero_tab_side_end(output_svg, input_svg_file):
+    _do_preprocessing(output_svg, input_svg_file,
+                      {'TAB_SIDE': 'end',
+                       'WINDOWS_AERO': 1})
+
new file mode 100644
--- /dev/null
+++ b/browser/themes/tab-svgs.mozbuild
@@ -0,0 +1,26 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+script = TOPSRCDIR + '/browser/themes/preprocess-tab-svgs.py'
+input = [TOPSRCDIR + '/browser/themes/shared/tab-selected.svg']
+
+# Context variables can't be used inside functions, so hack around that.
+generated_files = GENERATED_FILES
+
+def generate_svg(svg_name, script_function):
+    global generated_files
+    generated_files += [svg_name]
+    svg = generated_files[svg_name]
+    svg.script = script + ':' + script_function
+    svg.inputs = input
+
+generate_svg('tab-selected-end.svg', 'tab_side_end')
+generate_svg('tab-selected-start.svg', 'tab_side_start')
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
+    # Same as above, but for aero.
+    generate_svg('tab-selected-end-aero.svg', 'aero_tab_side_end')
+    generate_svg('tab-selected-start-aero.svg', 'aero_tab_side_start')
deleted file mode 100644
--- a/browser/themes/windows/Makefile.in
+++ /dev/null
@@ -1,36 +0,0 @@
-# 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/.
-
-ICON_FILES := ../shared/icon.png
-ICON_DEST = $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
-INSTALL_TARGETS += ICON
-
-# By default, the pre-processor used for jar.mn will use "%" as a marker for ".css" files and "#"
-# otherwise. This falls apart when a file using one marker needs to include a file with the other
-# marker since the pre-processor instructions in the included file will not be processed. The
-# following SVG files need to include a file which uses "%" as the marker so we invoke the pre-
-# processor ourselves here with the marker specified. The resulting SVG files will get packaged by
-# the processing of the jar file in this directory.
-tab-selected-svg: $(srcdir)/../shared/tab-selected.svg
-	$(call py_action,preprocessor, \
-	  --marker % -D TAB_SIDE=start \
-	  $(ACDEFINES) \
-	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-start.svg)
-	$(call py_action,preprocessor, \
-	  --marker % -D TAB_SIDE=end \
-	  $(ACDEFINES) \
-	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-end.svg)
-# Same as above for aero.
-	$(call py_action,preprocessor, \
-	  --marker % -D TAB_SIDE=start -D WINDOWS_AERO \
-	  $(ACDEFINES) \
-	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-start-aero.svg)
-	$(call py_action,preprocessor, \
-	  --marker % -D TAB_SIDE=end -D WINDOWS_AERO \
-	  $(ACDEFINES) \
-	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-end-aero.svg)
-
-.PHONY: tab-selected-svg
-
-export:: tab-selected-svg
--- a/browser/themes/windows/moz.build
+++ b/browser/themes/windows/moz.build
@@ -2,8 +2,10 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['communicator']
 
 JAR_MANIFESTS += ['jar.mn']
+
+include('../tab-svgs.mozbuild')
--- a/build/docs/defining-binaries.rst
+++ b/build/docs/defining-binaries.rst
@@ -16,16 +16,18 @@ Source files
 Source files to be used in a given directory are registered in the ``SOURCES``
 and ``UNIFIED_SOURCES`` variables. ``UNIFIED_SOURCES`` have a special behavior
 in that they are aggregated by batches of 16, requiring, for example, that there
 are no conflicting variables in those source files.
 
 ``SOURCES`` and ``UNIFIED_SOURCES`` are lists which must be appended to, and
 each append requires the given list to be alphanumerically ordered.
 
+.. code-block:: python
+
    UNIFIED_SOURCES += [
        'FirstSource.cpp',
        'SecondSource.cpp',
        'ThirdSource.cpp',
    ]
 
    SOURCES += [
        'OtherSource.cpp',
@@ -36,31 +38,37 @@ for C, C++, and Objective C.
 
 
 Static Libraries
 ================
 
 To build a static library, other than defining the source files (see above), one
 just needs to define a library name with the ``Library`` template.
 
+.. code-block:: python
+
    Library('foo')
 
 The library file name will be ``libfoo.a`` on UNIX systems and ``foo.lib`` on
 Windows.
 
 If the static library needs to aggregate other static libraries, a list of
 ``Library`` names can be added to the ``USE_LIBS`` variable. Like ``SOURCES``, it
 requires the appended list to be alphanumerically ordered.
 
+.. code-block:: python
+
    USE_LIBS += ['bar', 'baz']
 
 If there are multiple directories containing the same ``Library`` name, it is
 possible to disambiguate by prefixing with the path to the wanted one (relative
 or absolute):
 
+.. code-block:: python
+
    USE_LIBS += [
        '/path/from/topsrcdir/to/bar',
        '../relative/baz',
    ]
 
 Note that the leaf name in those paths is the ``Library`` name, not an actual
 file name.
 
@@ -77,82 +85,94 @@ Intermediate (Static) Libraries
 ===============================
 
 In many cases in the tree, static libraries are built with the only purpose
 of being linked into another, bigger one (like libxul). Instead of adding all
 required libraries to ``USE_LIBS`` for the bigger one, it is possible to tell
 the build system that the library built in the current directory is meant to
 be linked to that bigger library, with the ``FINAL_LIBRARY`` variable.
 
+.. code-block:: python
+
    FINAL_LIBRARY = 'xul'
 
 The ``FINAL_LIBRARY`` value must match a unique ``Library`` name somewhere
 in the tree.
 
 As a special rule, those intermediate libraries don't need a ``Library`` name
 for themselves.
 
 
 Shared Libraries
 ================
 
 Sometimes, we want shared libraries, a.k.a. dynamic libraries. Such libraries
 are defined similarly to static libraries, using the ``SharedLibrary`` template
 instead of ``Library``.
 
+.. code-block:: python
+
    SharedLibrary('foo')
 
 When this template is used, no static library is built. See further below to
 build both types of libraries.
 
 With a ``SharedLibrary`` name of ``foo``, the library file name will be
 ``libfoo.dylib`` on OSX, ``libfoo.so`` on ELF systems (Linux, etc.), and
 ``foo.dll`` on Windows. On Windows, there is also an import library named
 ``foo.lib``, used on the linker command line. ``libfoo.dylib`` and
 ``libfoo.so`` are considered the import library name for, resp. OSX and ELF
 systems.
 
 On OSX, one may want to create a special kind of dynamic library: frameworks.
 This is done with the ``Framework`` template.
 
+.. code-block:: python
+
    Framework('foo')
 
 With a ``Framework`` name of ``foo``, the framework file name will be ``foo``.
 This template however affects the behavior on all platforms, so it needs to
 be set only on OSX.
 
 
 Executables
 ===========
 
 Executables, a.k.a. programs, are, in the simplest form, defined with the
 ``Program`` template.
 
+.. code-block:: python
+
    Program('foobar')
 
 On UNIX systems, the executable file name will be ``foobar``, while on Windows,
 it will be ``foobar.exe``.
 
 Like static and shared libraries, the build system can be instructed to link
 libraries to the executable with ``USE_LIBS``, listing various ``Library``
 names.
 
 In some cases, we want to create an executable per source file in the current
 directory, in which case we can use the ``SimplePrograms`` template
 
+.. code-block:: python
+
    SimplePrograms([
        'FirstProgram',
        'SecondProgram',
    ])
 
 Contrary to ``Program``, which requires corresponding ``SOURCES``, when using
 ``SimplePrograms``, the corresponding ``SOURCES`` are implied. If the
 corresponding ``sources`` have an extension different from ``.cpp``, it is
 possible to specify the proper extension:
 
+.. code-block:: python
+
    SimplePrograms([
        'ThirdProgram',
        'FourthProgram',
    ], ext='.c')
 
 Please note this construct was added for compatibility with what already lives
 in the mozilla tree ; it is recommended not to add new simple programs with
 sources with a different extension than ``.cpp``.
@@ -165,28 +185,32 @@ if it's different from ``.cpp``.
 
 Linking with system libraries
 =============================
 
 Programs and libraries usually need to link with system libraries, such as a
 widget toolkit, etc. Those required dependencies can be given with the
 ``OS_LIBS`` variable.
 
+.. code-block:: python
+
    OS_LIBS += [
        'foo',
        'bar',
    ]
 
 This expands to ``foo.lib bar.lib`` when building with MSVC, and
 ``-lfoo -lbar`` otherwise.
 
 For convenience with ``pkg-config``, ``OS_LIBS`` can also take linker flags
 such as ``-L/some/path`` and ``-llib``, such that it is possible to directly
 assign ``LIBS`` variables from ``CONFIG``, such as:
 
+.. code-block:: python
+
    OS_LIBS += CONFIG['MOZ_PANGO_LIBS']
 
 (assuming ``CONFIG['MOZ_PANGO_LIBS']`` is a list, not a string)
 
 Like ``USE_LIBS``, this variable applies to static and shared libraries, as
 well as programs.
 
 
@@ -196,63 +220,73 @@ Libraries from third party build system
 Some libraries in the tree are not built by the moz.build-governed build
 system, and there is no ``Library`` corresponding to them.
 
 However, ``USE_LIBS`` allows to reference such libraries by giving a full
 path (like when disambiguating identical ``Library`` names). The same naming
 rules apply as other uses of ``USE_LIBS``, so only the library name without
 prefix and suffix shall be given.
 
+.. code-block:: python
+
    USE_LIBS += [
        '/path/from/topsrcdir/to/third-party/bar',
        '../relative/third-party/baz',
    ]
 
 Note that ``/path/from/topsrcdir/to/third-party`` and
 ``../relative/third-party/baz`` must lead under a subconfigured directory (a
 directory with an AC_OUTPUT_SUBDIRS in configure.in), or ``security/nss``.
 
 
 Building both static and shared libraries
 =========================================
 
 When both types of libraries are required, one needs to set both
 ``FORCE_SHARED_LIB`` and ``FORCE_STATIC_LIB`` boolean variables.
 
+.. code-block:: python
+
    FORCE_SHARED_LIB = True
    FORCE_STATIC_LIB = True
 
 But because static libraries and Windows import libraries have the same file
 names, either the static or the shared library name needs to be different
 than the name given to the ``Library`` template.
 
 The ``STATIC_LIBRARY_NAME`` and ``SHARED_LIBRARY_NAME`` variables can be used
 to change either the static or the shared library name.
 
+.. code-block:: python
+
   Library('foo')
   STATIC_LIBRARY_NAME = 'foo_s'
 
 With the above, on Windows, ``foo_s.lib`` will be the static library,
 ``foo.dll`` the shared library, and ``foo.lib`` the import library.
 
 In some cases, for convenience, it is possible to set both
 ``STATIC_LIBRARY_NAME`` and ``SHARED_LIBRARY_NAME``. For example:
 
+.. code-block:: python
+
   Library('mylib')
   STATIC_LIBRARY_NAME = 'mylib_s'
   SHARED_LIBRARY_NAME = CONFIG['SHARED_NAME']
 
 This allows to use ``mylib`` in the ``USE_LIBS`` of another library or
 executable.
 
 When refering to a ``Library`` name building both types of libraries in
 ``USE_LIBS``, the shared library is chosen to be linked. But sometimes,
 it is wanted to link the static version, in which case the ``Library`` name
 needs to be prefixed with ``static:`` in ``USE_LIBS``
 
+::
+
    a/moz.build:
       Library('mylib')
       FORCE_SHARED_LIB = True
       FORCE_STATIC_LIB = True
       STATIC_LIBRARY_NAME = 'mylib_s'
    b/moz.build:
       Program('myprog')
       USE_LIBS += [
@@ -267,16 +301,18 @@ The ``SDK_LIBRARY`` boolean variable def
 directory is going to be installed in the SDK.
 
 The ``SONAME`` variable declares a "shared object name" for the library. It
 defaults to the ``Library`` name or the ``SHARED_LIBRARY_NAME`` if set. When
 linking to a library with a ``SONAME``, the resulting library or program will
 have a dependency on the library with the name corresponding to the ``SONAME``
 instead of the ``Library`` name. This only impacts ELF systems.
 
+::
+
    a/moz.build:
       Library('mylib')
    b/moz.build:
       Library('otherlib')
       SONAME = 'foo'
    c/moz.build:
       Program('myprog')
       USE_LIBS += [
--- a/build/pgo/js-input/sunspider/regexp-dna.html
+++ b/build/pgo/js-input/sunspider/regexp-dna.html
@@ -1736,24 +1736,24 @@ var ilen, clen,
   V: '(a|c|g)', W: '(a|t)', Y: '(c|t)' }
 
 ilen = dnaInput.length;
 
 // There is no in-place substitution
 dnaInput = dnaInput.replace(/>.*\n|\n/g,"")
 clen = dnaInput.length
 
-var dnaOutputString;
+var dnaOutputString = "";
 
 for(i in seqs)
     dnaOutputString += seqs[i].source + " " + (dnaInput.match(seqs[i]) || []).length + "\n";
  // match returns null if no matches, so replace with empty
 
 for(k in subs)
- dnaInput = dnaInput.replace(k, subs[k], "g")
+ dnaInput = dnaInput.replace(k, subs[k]) // FIXME: Would like this to be a global substitution in a future version of SunSpider.
  // search string, replacement string, flags
 
 
 var _sunSpiderInterval = new Date() - _sunSpiderStartDate;
 
 document.getElementById("console").innerHTML = _sunSpiderInterval;
 </script>
 
--- a/configure.in
+++ b/configure.in
@@ -7212,16 +7212,19 @@ if test -z "$MOZ_MEMORY"; then
     *-mingw*)
       if test -z "$WIN32_REDIST_DIR" -a -z "$MOZ_DEBUG"; then
         AC_MSG_WARN([When not building jemalloc, you need to set WIN32_REDIST_DIR to the path to the Visual C++ Redist (usually VCINSTALLDIR\redist\x86\Microsoft.VC80.CRT, for VC++ v8) if you intend to distribute your build.])
       fi
       ;;
   esac
 else
   AC_DEFINE(MOZ_MEMORY)
+  if test -n "$NIGHTLY_BUILD"; then
+    MOZ_JEMALLOC3=1
+  fi
   if test -n "$MOZ_JEMALLOC3"; then
     AC_DEFINE(MOZ_JEMALLOC3)
   fi
   if test "x$MOZ_DEBUG" = "x1"; then
     AC_DEFINE(MOZ_MEMORY_DEBUG)
   fi
   dnl The generic feature tests that determine how to compute ncpus are long and
   dnl complicated.  Therefore, simply define special cpp variables for the
@@ -7650,16 +7653,28 @@ MOZ_ARG_WITH_STRING(jitreport-granularit
                              2 - per-line information
                              3 - per-op information],
   JITREPORT_GRANULARITY=$withval,
   JITREPORT_GRANULARITY=3)
 
 AC_DEFINE_UNQUOTED(JS_DEFAULT_JITREPORT_GRANULARITY, $JITREPORT_GRANULARITY)
 
 dnl ========================================================
+dnl = Disable Mozilla's versions of RIL and Geolocation
+dnl ========================================================
+MOZ_ARG_DISABLE_BOOL(mozril-geoloc,
+[  --disable-mozril-geoloc         Disable Mozilla's RIL and geolocation],
+    DISABLE_MOZ_RIL_GEOLOC=1,
+    DISABLE_MOZ_RIL_GEOLOC= )
+if test -n "$DISABLE_MOZ_RIL_GEOLOC"; then
+   AC_DEFINE(DISABLE_MOZ_RIL_GEOLOC)
+fi
+AC_SUBST(DISABLE_MOZ_RIL_GEOLOC)
+
+dnl ========================================================
 dnl =
 dnl = Misc. Options
 dnl =
 dnl ========================================================
 MOZ_ARG_HEADER(Misc. Options)
 
 dnl ========================================================
 dnl update xterm title
--- a/docshell/test/unit/test_nsDefaultURIFixup_info.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_info.js
@@ -616,24 +616,24 @@ function do_single_test_run() {
       do_check_eq(info.fixupChangedProtocol, expectProtocolChange);
       do_check_eq(info.fixupCreatedAlternateURI, makeAlternativeURI && alternativeURI != null);
 
       // Check the preferred URI
       let requiresWhitelistedDomain = flags & urifixup.FIXUP_FLAG_REQUIRE_WHITELISTED_HOST;
       if (couldDoKeywordLookup) {
         if (expectKeywordLookup) {
           if (!affectedByWhitelist || (affectedByWhitelist && !inWhitelist)) {
-            let urlparamInput = encodeURIComponent(sanitize(testInput)).replace("%20", "+", "g");
+            let urlparamInput = encodeURIComponent(sanitize(testInput)).replace(/%20/g, "+");
             // If the input starts with `?`, then info.preferredURI.spec will omit it
             // In order to test this behaviour, remove `?` only if it is the first character
             if (urlparamInput.startsWith("%3F")) {
               urlparamInput = urlparamInput.replace("%3F", "");
             }
             let searchURL = kSearchEngineURL.replace("{searchTerms}", urlparamInput);
-            let spec = info.preferredURI.spec.replace("%27", "'", "g");
+            let spec = info.preferredURI.spec.replace(/%27/g, "'");
             do_check_eq(spec, searchURL);
           } else {
             do_check_eq(info.preferredURI, null);
           }
         } else {
           do_check_eq(info.preferredURI.spec, info.fixedURI.spec);
         }
       } else if (requiresWhitelistedDomain) {
--- a/dom/base/nsAttrValueInlines.h
+++ b/dom/base/nsAttrValueInlines.h
@@ -1,30 +1,24 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsAttrValueInlines_h__
 #define nsAttrValueInlines_h__
 
 #include <stdint.h>
 
 #include "nsAttrValue.h"
+#include "mozilla/Attributes.h"
 
 struct MiscContainer;
 
-namespace mozilla {
-template<>
-struct HasDangerousPublicDestructor<MiscContainer>
-{
-  static const bool value = true;
-};
-}
-
-struct MiscContainer
+struct MiscContainer MOZ_FINAL
 {
   typedef nsAttrValue::ValueType ValueType;
 
   ValueType mType;
   // mStringBits points to either nsIAtom* or nsStringBuffer* and is used when
   // mType isn't mCSSStyleRule.
   // Note eStringBase and eAtomBase is used also to handle the type of
   // mStringBits.
@@ -65,25 +59,30 @@ struct MiscContainer
       mStringBits(0)
   {
     MOZ_COUNT_CTOR(MiscContainer);
     mValue.mColor = 0;
     mValue.mRefCount = 0;
     mValue.mCached = 0;
   }
 
+protected:
+  // Only nsAttrValue should be able to delete us.
+  friend class nsAttrValue;
+
   ~MiscContainer()
   {
     if (IsRefCounted()) {
       MOZ_ASSERT(mValue.mRefCount == 0);
       MOZ_ASSERT(!mValue.mCached);
     }
     MOZ_COUNT_DTOR(MiscContainer);
   }
 
+public:
   bool GetString(nsAString& aString) const;
 
   inline bool IsRefCounted() const
   {
     // Nothing stops us from refcounting (and sharing) other types of
     // MiscContainer (except eDoubleValue types) but there's no compelling
     // reason to 
     return mType == nsAttrValue::eCSSStyleRule;
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -909,18 +909,17 @@ nsFrameLoader::ShowRemoteFrame(const nsI
                           "remote-browser-shown", nullptr);
     }
   } else {
     nsIntRect dimensions;
     NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
 
     // Don't show remote iframe if we are waiting for the completion of reflow.
     if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
-      nsIntPoint chromeDisp = aFrame->GetChromeDisplacement();
-      mRemoteBrowser->UpdateDimensions(dimensions, size, chromeDisp);
+      mRemoteBrowser->UpdateDimensions(dimensions, size);
     }
   }
 
   return true;
 }
 
 void
 nsFrameLoader::Hide()
@@ -1955,18 +1954,17 @@ nsFrameLoader::GetWindowDimensions(nsInt
 NS_IMETHODIMP
 nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame)
 {
   if (mRemoteFrame) {
     if (mRemoteBrowser) {
       nsIntSize size = aIFrame->GetSubdocumentSize();
       nsIntRect dimensions;
       NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
-      nsIntPoint chromeDisp = aIFrame->GetChromeDisplacement();
-      mRemoteBrowser->UpdateDimensions(dimensions, size, chromeDisp);
+      mRemoteBrowser->UpdateDimensions(dimensions, size);
     }
     return NS_OK;
   }
   UpdateBaseWindowPositionAndSize(aIFrame);
   return NS_OK;
 }
 
 void
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -222,16 +222,19 @@ public:
    */
   void ApplySandboxFlags(uint32_t sandboxFlags);
 
   void GetURL(nsString& aURL);
 
   void ActivateUpdateHitRegion();
   void DeactivateUpdateHitRegion();
 
+  // Properly retrieves documentSize of any subdocument type.
+  nsresult GetWindowDimensions(nsIntRect& aRect);
+
 private:
 
   void SetOwnerContent(mozilla::dom::Element* aContent);
 
   bool ShouldUseRemoteProcess();
 
   /**
    * Is this a frameloader for a bona fide <iframe mozbrowser> or
@@ -277,19 +280,16 @@ private:
 
   /**
    * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
    * initialize mDocShell.
    */
   nsresult MaybeCreateDocShell();
   nsresult EnsureMessageManager();
 
-  // Properly retrieves documentSize of any subdocument type.
-  nsresult GetWindowDimensions(nsIntRect& aRect);
-
   // Updates the subdocument position and size. This gets called only
   // when we have our own in-process DocShell.
   void UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame);
   nsresult CheckURILoad(nsIURI* aURI);
   void FireErrorEvent();
   nsresult ReallyStartLoadingInternal();
 
   // Return true if remote browser created; nothing else to do
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -509,17 +509,17 @@ nsFrameMessageManager::GetDelayedScripts
 
     JS::AutoValueArray<2> pairElts(aCx);
     pairElts[0].setString(url);
     pairElts[1].setBoolean(mPendingScriptsGlobalStates[i]);
 
     pair = JS_NewArrayObject(aCx, pairElts);
     NS_ENSURE_TRUE(pair, NS_ERROR_OUT_OF_MEMORY);
 
-    NS_ENSURE_TRUE(JS_SetElement(aCx, array, i, pair),
+    NS_ENSURE_TRUE(JS_DefineElement(aCx, array, i, pair, JSPROP_ENUMERATE),
                    NS_ERROR_OUT_OF_MEMORY);
   }
 
   aList.setObject(*array);
   return NS_OK;
 }
 
 // nsIFrameScriptLoader
@@ -691,17 +691,17 @@ nsFrameMessageManager::SendMessage(const
       continue;
     }
 
     JS::Rooted<JS::Value> ret(aCx);
     if (!JS_ParseJSON(aCx, static_cast<const char16_t*>(retval[i].get()),
                       retval[i].Length(), &ret)) {
       return NS_ERROR_UNEXPECTED;
     }
-    NS_ENSURE_TRUE(JS_SetElement(aCx, dataArray, i, ret),
+    NS_ENSURE_TRUE(JS_DefineElement(aCx, dataArray, i, ret, JSPROP_ENUMERATE),
                    NS_ERROR_OUT_OF_MEMORY);
   }
 
   aRetval.setObject(*dataArray);
   return NS_OK;
 }
 
 nsresult
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -2251,24 +2251,27 @@ GK_ATOM(aria_selected, "aria-selected")
 GK_ATOM(aria_setsize, "aria-setsize")
 GK_ATOM(aria_sort, "aria-sort")
 GK_ATOM(aria_valuenow, "aria-valuenow")
 GK_ATOM(aria_valuemin, "aria-valuemin")
 GK_ATOM(aria_valuemax, "aria-valuemax")
 GK_ATOM(aria_valuetext, "aria-valuetext")
 GK_ATOM(AreaFrame, "AreaFrame")
 GK_ATOM(auto_generated, "auto-generated")
+GK_ATOM(banner, "banner")
 GK_ATOM(checkable, "checkable")
 GK_ATOM(choices, "choices")
 GK_ATOM(columnheader, "columnheader")
+GK_ATOM(complementary, "complementary")
 GK_ATOM(containerAtomic, "container-atomic")
 GK_ATOM(containerBusy, "container-busy")
 GK_ATOM(containerLive, "container-live")
 GK_ATOM(containerLiveRole, "container-live-role")
 GK_ATOM(containerRelevant, "container-relevant")
+GK_ATOM(contentinfo, "contentinfo")
 GK_ATOM(cycles, "cycles")
 GK_ATOM(datatable, "datatable")
 GK_ATOM(directory, "directory")
 GK_ATOM(eventFromInput, "event-from-input")
 GK_ATOM(grammar, "grammar")
 GK_ATOM(gridcell, "gridcell")
 GK_ATOM(heading, "heading")
 GK_ATOM(hitregion, "hitregion")
@@ -2279,23 +2282,26 @@ GK_ATOM(item, "item")
 GK_ATOM(itemset, "itemset")
 GK_ATOM(lineNumber, "line-number")
 GK_ATOM(linkedPanel, "linkedpanel")
 GK_ATOM(live, "live")
 GK_ATOM(menuitemcheckbox, "menuitemcheckbox")
 GK_ATOM(menuitemradio, "menuitemradio")
 GK_ATOM(mixed, "mixed")
 GK_ATOM(multiline, "multiline")
+GK_ATOM(navigation, "navigation")
 GK_ATOM(password, "password")
 GK_ATOM(posinset, "posinset")
 GK_ATOM(presentation, "presentation")
 GK_ATOM(progressbar, "progressbar")
 GK_ATOM(region, "region")
 GK_ATOM(rowgroup, "rowgroup")
 GK_ATOM(rowheader, "rowheader")
+GK_ATOM(search, "search")
+GK_ATOM(searchbox, "searchbox")
 GK_ATOM(select1, "select1")
 GK_ATOM(setsize, "setsize")
 GK_ATOM(spelling, "spelling")
 GK_ATOM(spinbutton, "spinbutton")
 GK_ATOM(status, "status")
 GK_ATOM(_switch, "switch")
 GK_ATOM(tableCellIndex, "table-cell-index")
 GK_ATOM(tablist, "tablist")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -9179,16 +9179,18 @@ nsGlobalWindow::ShowModalDialog(const ns
                             (aUrl, aArgument, aOptions, aError), aError,
                             nullptr);
 
   if (!IsShowModalDialogEnabled() || XRE_GetProcessType() == GeckoProcessType_Content) {
     aError.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
 
+  Telemetry::Accumulate(Telemetry::DOM_WINDOW_SHOWMODALDIALOG_USED, true);
+
   nsRefPtr<DialogValueHolder> argHolder =
     new DialogValueHolder(nsContentUtils::SubjectPrincipal(), aArgument);
 
   // Before bringing up the window/dialog, unsuppress painting and flush
   // pending reflows.
   EnsureReflowFlushAndPaint();
 
   if (!AreDialogsEnabled()) {
--- a/dom/base/test/test_bug902847.html
+++ b/dom/base/test/test_bug902847.html
@@ -22,18 +22,18 @@ https://bugzilla.mozilla.org/show_bug.cg
                 de.OutputDontRemoveLineEndingSpaces;
     encoder.init(document, "text/plain", flags);
 
     function toPlaintext(id) {
       var element = document.getElementById(id);
       var range = document.createRange();
       range.selectNodeContents(element);
       encoder.setRange(range);
-      return encoder.encodeToString().replace('\n', '\\n', 'g')
-                                     .replace('\r', '\\r', 'g');
+      return encoder.encodeToString().replace(/\n/g, '\\n')
+                                     .replace(/\r/g, '\\r');
     }
 
     // Test cases.
     is(toPlaintext("case1"), "Hello \\nboy!", "Case 1 failed.");
     is(toPlaintext("case2"), "Hello \\nboy!", "Case 2 failed.");
     is(toPlaintext("case3"), "Hello \\nboy!", "Case 3 failed.");
     is(toPlaintext("case4"), "Hello  \\nboy!", "Case 4 failed.");
     SimpleTest.finish();
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1936,40 +1936,42 @@ struct FakeString {
   }
 
   // If this ever changes, change the corresponding code in the
   // Optional<nsAString> specialization as well.
   const nsAString* ToAStringPtr() const {
     return reinterpret_cast<const nsString*>(this);
   }
 
-  nsAString* ToAStringPtr() {
-    return reinterpret_cast<nsString*>(this);
-  }
-
-  operator const nsAString& () const {
+operator const nsAString& () const {
     return *reinterpret_cast<const nsString*>(this);
   }
 
 private:
+  nsAString* ToAStringPtr() {
+    return reinterpret_cast<nsString*>(this);
+  }
+
   nsString::char_type* mData;
   nsString::size_type mLength;
   uint32_t mFlags;
 
   static const size_t sInlineCapacity = 64;
   nsString::char_type mInlineStorage[sInlineCapacity];
 
   FakeString(const FakeString& other) = delete;
   void operator=(const FakeString& other) = delete;
 
   void SetData(nsString::char_type* aData) {
     MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
     mData = const_cast<nsString::char_type*>(aData);
   }
 
+  friend class NonNull<nsAString>;
+
   // A class to use for our static asserts to ensure our object layout
   // matches that of nsString.
   class StringAsserter;
   friend class StringAsserter;
 
   class StringAsserter : public nsString {
   public:
     static void StaticAsserts() {
--- a/dom/bluetooth2/BluetoothManager.cpp
+++ b/dom/bluetooth2/BluetoothManager.cpp
@@ -191,34 +191,35 @@ void
 BluetoothManager::HandleAdapterRemoved(const BluetoothValue& aValue)
 {
   MOZ_ASSERT(aValue.type() == BluetoothValue::TnsString);
   MOZ_ASSERT(DefaultAdapterExists());
 
   // Remove the adapter of given address from adapters array
   nsString addressToRemove = aValue.get_nsString();
 
-  uint32_t numAdapters = mAdapters.Length();
-  for (uint32_t i = 0; i < numAdapters; i++) {
+  uint32_t i;
+  for (i = 0; i < mAdapters.Length(); i++) {
     nsString address;
     mAdapters[i]->GetAddress(address);
     if (address.Equals(addressToRemove)) {
       mAdapters.RemoveElementAt(i);
-
-      if (mDefaultAdapterIndex == (int)i) {
-        ReselectDefaultAdapter();
-      }
       break;
     }
   }
 
   // Notify application of removed adapter
   BluetoothAdapterEventInit init;
   init.mAddress = addressToRemove;
   DispatchAdapterEvent(NS_LITERAL_STRING("adapterremoved"), init);
+
+  // Reselect default adapter if it's removed
+  if (mDefaultAdapterIndex == (int)i) {
+    ReselectDefaultAdapter();
+  }
 }
 
 void
 BluetoothManager::ReselectDefaultAdapter()
 {
   // Select the first of existing/remaining adapters as default adapter
   mDefaultAdapterIndex = mAdapters.IsEmpty() ? -1 : 0;
   BT_API2_LOGR("mAdapters length: %d => NEW mDefaultAdapterIndex: %d",
--- a/dom/bluetooth2/BluetoothUtils.cpp
+++ b/dom/bluetooth2/BluetoothUtils.cpp
@@ -51,22 +51,22 @@ StringToUuid(const char* aString, Blueto
 
   uuid0 = htonl(uuid0);
   uuid1 = htons(uuid1);
   uuid2 = htons(uuid2);
   uuid3 = htons(uuid3);
   uuid4 = htonl(uuid4);
   uuid5 = htons(uuid5);
 
-  memcpy(&aUuid.mUuid[0], &uuid0, 4);
-  memcpy(&aUuid.mUuid[4], &uuid1, 2);
-  memcpy(&aUuid.mUuid[6], &uuid2, 2);
-  memcpy(&aUuid.mUuid[8], &uuid3, 2);
-  memcpy(&aUuid.mUuid[10], &uuid4, 4);
-  memcpy(&aUuid.mUuid[14], &uuid5, 2);
+  memcpy(&aUuid.mUuid[0], &uuid0, sizeof(uint32_t));
+  memcpy(&aUuid.mUuid[4], &uuid1, sizeof(uint16_t));
+  memcpy(&aUuid.mUuid[6], &uuid2, sizeof(uint16_t));
+  memcpy(&aUuid.mUuid[8], &uuid3, sizeof(uint16_t));
+  memcpy(&aUuid.mUuid[10], &uuid4, sizeof(uint32_t));
+  memcpy(&aUuid.mUuid[14], &uuid5, sizeof(uint16_t));
 }
 
 bool
 SetJsObject(JSContext* aContext,
             const BluetoothValue& aValue,
             JS::Handle<JSObject*> aObj)
 {
   MOZ_ASSERT(aContext && aObj);
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -37,20 +37,28 @@ if (!('BrowserElementIsPreloaded' in thi
   if (isTopBrowserElement(docShell) &&
       Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
     try {
       Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
     } catch (e) {
     }
   }
 
+  if (docShell.asyncPanZoomEnabled === false) {
+    Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanningAPZDisabled.js");
+    ContentPanningAPZDisabled.init();
+  }
+
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js");
   ContentPanning.init();
 
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js");
 } else {
+  if (docShell.asyncPanZoomEnabled === false) {
+    ContentPanningAPZDisabled.init();
+  }
   ContentPanning.init();
 }
 
 var BrowserElementIsReady = true;
 
 
 sendAsyncMessage('browser-element-api:call', { 'msg_name': 'hello' });
--- a/dom/browser-element/BrowserElementPanning.js
+++ b/dom/browser-element/BrowserElementPanning.js
@@ -7,501 +7,55 @@
 
 "use strict";
 dump("############################### browserElementPanning.js loaded\n");
 
 let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu }  = Components;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Geometry.jsm");
 
-var global = this;
-
 const kObservedEvents = [
   "BEC:ShownModalPrompt",
   "Activity:Success",
   "Activity:Error"
 ];
 
 const ContentPanning = {
-  // Are we listening to touch or mouse events?
-  watchedEventsType: '',
-
-  // Are mouse events being delivered to this content along with touch
-  // events, in violation of spec?
-  hybridEvents: false,
-
   init: function cp_init() {
-    // If APZ is enabled, we do active element handling in C++
-    // (see widget/xpwidgets/ActiveElementManager.h), and panning
-    // itself in APZ, so we don't need to handle any touch events here.
-    if (docShell.asyncPanZoomEnabled === false) {
-      this._setupListenersForPanning();
-    }
-
     addEventListener("unload",
 		     this._unloadHandler.bind(this),
 		     /* useCapture = */ false,
 		     /* wantsUntrusted = */ false);
 
     addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
     addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
     addEventListener("visibilitychange", this._handleVisibilityChange.bind(this));
     kObservedEvents.forEach((topic) => {
       Services.obs.addObserver(this, topic, false);
     });
   },
 
-  _setupListenersForPanning: function cp_setupListenersForPanning() {
-    let events;
-
-    if (content.TouchEvent) {
-      events = ['touchstart', 'touchend', 'touchmove'];
-      this.watchedEventsType = 'touch';
-#ifdef MOZ_WIDGET_GONK
-      // The gonk widget backend does not deliver mouse events per
-      // spec.  Third-party content isn't exposed to this behavior,
-      // but that behavior creates some extra work for us here.
-      let appInfo = Cc["@mozilla.org/xre/app-info;1"];
-      let isParentProcess =
-        !appInfo || appInfo.getService(Ci.nsIXULRuntime)
-                           .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-      this.hybridEvents = isParentProcess;
-#endif
-    } else {
-      // Touch events aren't supported, so fall back on mouse.
-      events = ['mousedown', 'mouseup', 'mousemove'];
-      this.watchedEventsType = 'mouse';
-    }
-
-    let els = Cc["@mozilla.org/eventlistenerservice;1"]
-                .getService(Ci.nsIEventListenerService);
-
-    events.forEach(function(type) {
-      // Using the system group for mouse/touch events to avoid
-      // missing events if .stopPropagation() has been called.
-      els.addSystemEventListener(global, type,
-                                 this.handleEvent.bind(this),
-                                 /* useCapture = */ false);
-    }.bind(this));
-  },
-
-  handleEvent: function cp_handleEvent(evt) {
-    // Ignore events targeting an oop <iframe mozbrowser> since those will be
-    // handle by the BrowserElementPanning.js instance in the child process.
-    if (evt.target instanceof Ci.nsIMozBrowserFrame) {
-      return;
-    }
-
-    // For in-process <iframe mozbrowser> the events are not targetting
-    // directly the container iframe element, but some node of the document.
-    // So, the BrowserElementPanning instance of the system app will receive
-    // the sequence of touch events, as well as the BrowserElementPanning
-    // instance in the targetted app.
-    // As a result, multiple mozbrowser iframes will try to interpret the
-    // sequence of touch events, which may results into multiple clicks.
-    let targetWindow = evt.target.ownerDocument.defaultView;
-    let frameElement = targetWindow.frameElement;
-    while (frameElement) {
-      targetWindow = frameElement.ownerDocument.defaultView;
-      frameElement = targetWindow.frameElement;
-    }
-
-    if (content !== targetWindow) {
-      return;
-    }
-
-    if (evt.defaultPrevented || evt.multipleActionsPrevented) {
-      // clean up panning state even if touchend/mouseup has been preventDefault.
-      if(evt.type === 'touchend' || evt.type === 'mouseup') {
-        if (this.dragging &&
-            (this.watchedEventsType === 'mouse' ||
-             this.findPrimaryPointer(evt.changedTouches))) {
-          this._finishPanning();
-        }
-      }
-      return;
-    }
-
-    switch (evt.type) {
-      case 'mousedown':
-      case 'touchstart':
-        this.onTouchStart(evt);
-        break;
-      case 'mousemove':
-      case 'touchmove':
-        this.onTouchMove(evt);
-        break;
-      case 'mouseup':
-      case 'touchend':
-        this.onTouchEnd(evt);
-        break;
-      case 'click':
-        evt.stopPropagation();
-        evt.preventDefault();
-
-        let target = evt.target;
-        let view = target.ownerDocument ? target.ownerDocument.defaultView
-                                        : target;
-        view.removeEventListener('click', this, true, true);
-        break;
-    }
-  },
-
   observe: function cp_observe(subject, topic, data) {
     this._resetHover();
   },
 
-  position: new Point(0 , 0),
-
-  findPrimaryPointer: function cp_findPrimaryPointer(touches) {
-    if (!('primaryPointerId' in this))
-      return null;
-
-    for (let i = 0; i < touches.length; i++) {
-      if (touches[i].identifier === this.primaryPointerId) {
-        return touches[i];
-      }
-    }
-    return null;
-  },
-
-  onTouchStart: function cp_onTouchStart(evt) {
-    let screenX, screenY;
-    if (this.watchedEventsType == 'touch') {
-      if ('primaryPointerId' in this || evt.touches.length >= 2) {
-        this._resetActive();
-        return;
-      }
-
-      let firstTouch = evt.changedTouches[0];
-      this.primaryPointerId = firstTouch.identifier;
-      this.pointerDownTarget = firstTouch.target;
-      screenX = firstTouch.screenX;
-      screenY = firstTouch.screenY;
-    } else {
-      this.pointerDownTarget = evt.target;
-      screenX = evt.screenX;
-      screenY = evt.screenY;
-    }
-    this.dragging = true;
-    this.panning = false;
-
-    let oldTarget = this.target;
-    [this.target, this.scrollCallback] = this.getPannable(this.pointerDownTarget);
-
-    // If we have a pointer down target, we may need to fill in for EventStateManager
-    // in setting the active state on the target element.  Set a timer to
-    // ensure the pointer-down target is active.  (If it's already
-    // active, the timer is a no-op.)
-    if (this.pointerDownTarget !== null) {
-      // If there's no possibility this is a drag/pan, activate now.
-      // Otherwise wait a little bit to see if the gesture isn't a
-      // tap.
-      if (this.target === null) {
-        this.notify(this._activationTimer);
-      } else {
-        this._activationTimer.initWithCallback(this,
-                                               this._activationDelayMs,
-                                               Ci.nsITimer.TYPE_ONE_SHOT);
-      }
-    }
-
-    // If there is a pan animation running (from a previous pan gesture) and
-    // the user touch back the screen, stop this animation immediatly and
-    // prevent the possible click action if the touch happens on the same
-    // target.
-    this.preventNextClick = false;
-    if (KineticPanning.active) {
-      KineticPanning.stop();
-
-      if (oldTarget && oldTarget == this.target)
-        this.preventNextClick = true;
-    }
-
-    this.position.set(screenX, screenY);
-    KineticPanning.reset();
-    KineticPanning.record(new Point(0, 0), evt.timeStamp);
-
-    // We prevent start events to avoid sending a focus event at the end of this
-    // touch series. See bug 889717.
-    if ((this.panning || this.preventNextClick)) {
-      evt.preventDefault();
-    }
-  },
-
-  onTouchEnd: function cp_onTouchEnd(evt) {
-    let touch = null;
-    if (!this.dragging ||
-        (this.watchedEventsType == 'touch' &&
-         !(touch = this.findPrimaryPointer(evt.changedTouches)))) {
-      return;
-    }
-
-    // !isPan() and evt.detail should always give the same answer here
-    // since they use the same heuristics, but use the native gecko
-    // computation when possible.
-    //
-    // NB: when we're using touch events, then !KineticPanning.isPan()
-    // => this.panning, so we'll never attempt to block the click
-    // event.  That's OK however, because we won't fire a synthetic
-    // click when we're using touch events and this touch series
-    // wasn't a "tap" gesture.
-    let click = (this.watchedEventsType == 'mouse') ?
-      evt.detail : !KineticPanning.isPan();
-    // Additionally, if we're seeing non-compliant hybrid events, a
-    // "real" click will be generated if we started and ended on the
-    // same element.
-    if (this.hybridEvents) {
-      let target =
-        content.document.elementFromPoint(touch.clientX, touch.clientY);
-      click |= (target === this.pointerDownTarget);
-    }
-
-    if (this.target && click && (this.panning || this.preventNextClick)) {
-      if (this.hybridEvents) {
-        let target = this.target;
-        let view = target.ownerDocument ? target.ownerDocument.defaultView
-                                        : target;
-        view.addEventListener('click', this, true, true);
-      } else {
-        // We prevent end events to avoid sending a focus event. See bug 889717.
-        evt.preventDefault();
-      }
-    } else if (this.target && click && !this.panning) {
-      this.notify(this._activationTimer);
-    }
-
-    this._finishPanning();
-
-    // Now that we're done, avoid entraining the thing we just panned.
-    this.pointerDownTarget = null;
-  },
-
-  onTouchMove: function cp_onTouchMove(evt) {
-    if (!this.dragging)
-      return;
-
-    let screenX, screenY;
-    if (this.watchedEventsType == 'touch') {
-      let primaryTouch = this.findPrimaryPointer(evt.changedTouches);
-      if (evt.touches.length > 1 || !primaryTouch)
-        return;
-      screenX = primaryTouch.screenX;
-      screenY = primaryTouch.screenY;
-    } else {
-      screenX = evt.screenX;
-      screenY = evt.screenY;
-    }
-
-    let current = this.position;
-    let delta = new Point(screenX - current.x, screenY - current.y);
-    current.set(screenX, screenY);
-
-    KineticPanning.record(delta, evt.timeStamp);
-
-    let isPan = KineticPanning.isPan();
-
-    // If we've detected a pan gesture, cancel the active state of the
-    // current target.
-    if (!this.panning && isPan) {
-      this._resetActive();
-    }
-
-    // There's no possibility of us panning anything.
-    if (!this.scrollCallback) {
-      return;
-    }
-
-    // Scroll manually.
-    this.scrollCallback(delta.scale(-1));
-
-    if (!this.panning && isPan) {
-      this.panning = true;
-      this._activationTimer.cancel();
-    }
-
-    if (this.panning) {
-      // Only do this when we're actually executing a pan gesture.
-      // Otherwise synthetic mouse events will be canceled.
-      evt.stopPropagation();
-      evt.preventDefault();
-    }
-  },
-
-  // nsITimerCallback
-  notify: function cp_notify(timer) {
-    this._setActive(this.pointerDownTarget);
-  },
-
-  onKineticBegin: function cp_onKineticBegin(evt) {
-  },
-
-  onKineticPan: function cp_onKineticPan(delta) {
-    return !this.scrollCallback(delta);
-  },
-
-  onKineticEnd: function cp_onKineticEnd() {
-    if (!this.dragging)
-      this.scrollCallback = null;
-  },
-
-  getPannable: function cp_getPannable(node) {
-    let pannableNode = this._findPannable(node);
-    if (pannableNode) {
-      return [pannableNode, this._generateCallback(pannableNode)];
-    }
-
-    return [null, null];
-  },
-
-  _findPannable: function cp_findPannable(node) {
-    if (!(node instanceof Ci.nsIDOMHTMLElement) || node.tagName == 'HTML') {
-      return null;
-    }
-
-    let nodeContent = node.ownerDocument.defaultView;
-    while (!(node instanceof Ci.nsIDOMHTMLBodyElement)) {
-      let style = nodeContent.getComputedStyle(node, null);
-
-      let overflow = [style.getPropertyValue('overflow'),
-                      style.getPropertyValue('overflow-x'),
-                      style.getPropertyValue('overflow-y')];
-
-      let rect = node.getBoundingClientRect();
-      let isAuto = (overflow.indexOf('auto') != -1 &&
-                   (rect.height < node.scrollHeight ||
-                    rect.width < node.scrollWidth));
-
-      let isScroll = (overflow.indexOf('scroll') != -1);
-
-      let isScrollableTextarea = (node.tagName == 'TEXTAREA' &&
-          (node.scrollHeight > node.clientHeight ||
-           node.scrollWidth > node.clientWidth ||
-           ('scrollLeftMax' in node && node.scrollLeftMax > 0) ||
-           ('scrollTopMax' in node && node.scrollTopMax > 0)));
-      if (isScroll || isAuto || isScrollableTextarea) {
-        return node;
-      }
-
-      node = node.parentNode;
-    }
-
-    if (nodeContent.scrollMaxX || nodeContent.scrollMaxY) {
-      return nodeContent;
-    }
-
-    if (nodeContent.frameElement) {
-      return this._findPannable(nodeContent.frameElement);
-    }
-
-    return null;
-  },
-
-  _generateCallback: function cp_generateCallback(root) {
-    let firstScroll = true;
-    let target;
-    let current;
-    let win, doc, htmlNode, bodyNode;
-
-    function doScroll(node, delta) {
-      if (node instanceof Ci.nsIDOMHTMLElement) {
-        return node.scrollByNoFlush(delta.x, delta.y);
-      } else if (node instanceof Ci.nsIDOMWindow) {
-        win = node;
-        doc = win.document;
-
-        // "overflow:hidden" on either the <html> or the <body> node should
-        // prevent the user from scrolling the root viewport.
-        if (doc instanceof Ci.nsIDOMHTMLDocument) {
-          htmlNode = doc.documentElement;
-          bodyNode = doc.body;
-          if (win.getComputedStyle(htmlNode, null).overflowX == "hidden" ||
-              win.getComputedStyle(bodyNode, null).overflowX == "hidden") {
-            delta.x = 0;
-          }
-          if (win.getComputedStyle(htmlNode, null).overflowY == "hidden" ||
-              win.getComputedStyle(bodyNode, null).overflowY == "hidden") {
-            delta.y = 0;
-          }
-        }
-        let oldX = node.scrollX;
-        let oldY = node.scrollY;
-        node.scrollBy(delta.x, delta.y);
-        return (node.scrollX != oldX || node.scrollY != oldY);
-      }
-      // If we get here, |node| isn't an HTML element and it's not a window,
-      // but findPannable apparently thought it was scrollable... What is it?
-      return false;
-    }
-
-    function targetParent(node) {
-      return node.parentNode || node.frameElement || null;
-    }
-
-    function scroll(delta) {
-      current = root;
-      firstScroll = true;
-      while (current) {
-        if (doScroll(current, delta)) {
-          firstScroll = false;
-          return true;
-        }
-
-        // TODO The current code looks for possible scrolling regions only if
-        // this is the first scroll action but this should be more dynamic.
-        if (!firstScroll) {
-          return false;
-        }
-
-        current = ContentPanning._findPannable(targetParent(current));
-      }
-
-      // There is nothing scrollable here.
-      return false;
-    }
-    return scroll;
-  },
-
   get _domUtils() {
     delete this._domUtils;
     return this._domUtils = Cc['@mozilla.org/inspector/dom-utils;1']
                               .getService(Ci.inIDOMUtils);
   },
 
-  get _activationTimer() {
-    delete this._activationTimer;
-    return this._activationTimer = Cc["@mozilla.org/timer;1"]
-                                     .createInstance(Ci.nsITimer);
-  },
-
-  get _activationDelayMs() {
-    let delay = Services.prefs.getIntPref('ui.touch_activation.delay_ms');
-    delete this._activationDelayMs;
-    return this._activationDelayMs = delay;
-  },
-
-  _resetActive: function cp_resetActive() {
-    let elt = this.pointerDownTarget || this.target;
-    let root = elt.ownerDocument || elt.document;
-    this._setActive(root.documentElement);
-  },
-
   _resetHover: function cp_resetHover() {
     const kStateHover = 0x00000004;
     try {
       let element = content.document.createElement('foo');
       this._domUtils.setContentState(element, kStateHover);
     } catch(e) {}
   },
 
-  _setActive: function cp_setActive(elt) {
-    const kStateActive = 0x00000001;
-    this._domUtils.setContentState(elt, kStateActive);
-  },
-
   _recvViewportChange: function(data) {
     let metrics = data.json;
     this._viewport = new Rect(metrics.x, metrics.y,
                               metrics.viewport.width,
                               metrics.viewport.height);
     this._cssCompositedRect = new Rect(metrics.x, metrics.y,
                                        metrics.cssCompositedRect.width,
                                        metrics.cssCompositedRect.height);
@@ -605,234 +159,23 @@ const ContentPanning = {
     let availHeight = Math.min(aRect.width * vRect.height / vRect.width, aRect.height);
     let showing = overlapArea / (aRect.width * availHeight);
     let ratioW = (aRect.width / vRect.width);
     let ratioH = (aRect.height / vRect.height);
 
     return (showing > 0.9 && (ratioW > 0.9 || ratioH > 0.9)); 
   },
 
-  _finishPanning: function() {
-    this.dragging = false;
-    delete this.primaryPointerId;
-    this._activationTimer.cancel();
-
-    // If there is a scroll action, let's do a manual kinetic panning action.
-    if (this.panning) {
-      KineticPanning.start(this);
-    }
-  },
-
   _unloadHandler: function() {
     kObservedEvents.forEach((topic) => {
       Services.obs.removeObserver(this, topic);
     });
   }
 };
 
-// Min/max velocity of kinetic panning. This is in pixels/millisecond.
-const kMinVelocity = 0.2;
-const kMaxVelocity = 6;
-
-// Constants that affect the "friction" of the scroll pane.
-const kExponentialC = 1000;
-const kPolynomialC = 100 / 1000000;
-
-// How often do we change the position of the scroll pane?
-// Too often and panning may jerk near the end.
-// Too little and panning will be choppy. In milliseconds.
-const kUpdateInterval = 16;
-
-// The numbers of momentums to use for calculating the velocity of the pan.
-// Those are taken from the end of the action
-const kSamples = 5;
-
-const KineticPanning = {
-  _position: new Point(0, 0),
-  _velocity: new Point(0, 0),
-  _acceleration: new Point(0, 0),
-
-  get active() {
-    return this.target !== null;
-  },
-
-  target: null,
-  start: function kp_start(target) {
-    this.target = target;
-
-    // Calculate the initial velocity of the movement based on user input
-    let momentums = this.momentums;
-    let flick = momentums[momentums.length - 1].time - momentums[0].time < 300;
-
-    let distance = new Point(0, 0);
-    momentums.forEach(function(momentum) {
-      distance.add(momentum.dx, momentum.dy);
-    });
-
-    function clampFromZero(x, min, max) {
-      if (x >= 0)
-        return Math.max(min, Math.min(max, x));
-      return Math.min(-min, Math.max(-max, x));
-    }
-
-    let elapsed = momentums[momentums.length - 1].time - momentums[0].time;
-    let velocityX = clampFromZero(distance.x / elapsed, 0, kMaxVelocity);
-    let velocityY = clampFromZero(distance.y / elapsed, 0, kMaxVelocity);
-
-    let velocity = this._velocity;
-    if (flick) {
-      // Very fast pan action that does not generate a click are very often pan
-      // action. If this is a small gesture then it will not move the view a lot
-      // and so it will be above the minimun threshold and not generate any
-      // kinetic panning. This does not look on a device since this is often
-      // a real gesture, so let's lower the velocity threshold for such moves.
-      velocity.set(velocityX, velocityY);
-    } else {
-      velocity.set(Math.abs(velocityX) < kMinVelocity ? 0 : velocityX,
-                   Math.abs(velocityY) < kMinVelocity ? 0 : velocityY);
-    }
-    this.momentums = [];
-
-    // Set acceleration vector to opposite signs of velocity
-    function sign(x) {
-      return x ? (x > 0 ? 1 : -1) : 0;
-    }
-
-    this._acceleration.set(velocity.clone().map(sign).scale(-kPolynomialC));
-
-    // Reset the position
-    this._position.set(0, 0);
-
-    this._startAnimation();
-
-    this.target.onKineticBegin();
-  },
-
-  stop: function kp_stop() {
-    this.reset();
-
-    if (!this.target)
-      return;
-
-    this.target.onKineticEnd();
-    this.target = null;
-  },
-
-  reset: function kp_reset() {
-    this.momentums = [];
-    this.distance.set(0, 0);
-  },
-
-  momentums: [],
-  record: function kp_record(delta, timestamp) {
-    this.momentums.push({ 'time': this._getTime(timestamp),
-                          'dx' : delta.x, 'dy' : delta.y });
-
-    // We only need to keep kSamples in this.momentums.
-    if (this.momentums.length > kSamples) {
-      this.momentums.shift();
-    }
-
-    this.distance.add(delta.x, delta.y);
-  },
-
-  _getTime: function kp_getTime(time) {
-    // Touch events generated by the platform or hand-made are defined in
-    // microseconds instead of milliseconds. Bug 77992 will fix this at the
-    // platform level.
-    if (time > Date.now()) {
-      return Math.floor(time / 1000);
-    } else {
-      return time;
-    }
-  },
-
-  get threshold() {
-    let dpi = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIDOMWindowUtils)
-                     .displayDPI;
-
-    let threshold = Services.prefs.getIntPref('ui.dragThresholdX') / 240 * dpi;
-
-    delete this.threshold;
-    return this.threshold = threshold;
-  },
-
-  distance: new Point(0, 0),
-  isPan: function cp_isPan() {
-    return (Math.abs(this.distance.x) > this.threshold ||
-            Math.abs(this.distance.y) > this.threshold);
-  },
-
-  _startAnimation: function kp_startAnimation() {
-    let c = kExponentialC;
-    function getNextPosition(position, v, a, t) {
-      // Important traits for this function:
-      //   p(t=0) is 0
-      //   p'(t=0) is v0
-      //
-      // We use exponential to get a smoother stop, but by itself exponential
-      // is too smooth at the end. Adding a polynomial with the appropriate
-      // weight helps to balance
-      position.set(v.x * Math.exp(-t / c) * -c + a.x * t * t + v.x * c,
-                   v.y * Math.exp(-t / c) * -c + a.y * t * t + v.y * c);
-    }
-
-    let startTime = content.mozAnimationStartTime;
-    let elapsedTime = 0, targetedTime = 0, averageTime = 0;
-
-    let velocity = this._velocity;
-    let acceleration = this._acceleration;
-
-    let position = this._position;
-    let nextPosition = new Point(0, 0);
-    let delta = new Point(0, 0);
-
-    let callback = (function(timestamp) {
-      if (!this.target)
-        return;
-
-      // To make animation end fast enough but to keep smoothness, average the
-      // ideal time frame (smooth animation) with the actual time lapse
-      // (end fast enough).
-      // Animation will never take longer than 2 times the ideal length of time.
-      elapsedTime = timestamp - startTime;
-      targetedTime += kUpdateInterval;
-      averageTime = (targetedTime + elapsedTime) / 2;
-
-      // Calculate new position.
-      getNextPosition(nextPosition, velocity, acceleration, averageTime);
-      delta.set(Math.round(nextPosition.x - position.x),
-                Math.round(nextPosition.y - position.y));
-
-      // Test to see if movement is finished for each component.
-      if (delta.x * acceleration.x > 0)
-        delta.x = position.x = velocity.x = acceleration.x = 0;
-
-      if (delta.y * acceleration.y > 0)
-        delta.y = position.y = velocity.y = acceleration.y = 0;
-
-      if (velocity.equals(0, 0) || delta.equals(0, 0)) {
-        this.stop();
-        return;
-      }
-
-      position.add(delta);
-      if (this.target.onKineticPan(delta.scale(-1))) {
-        this.stop();
-        return;
-      }
-
-      content.mozRequestAnimationFrame(callback);
-    }).bind(this);
-
-    content.mozRequestAnimationFrame(callback);
-  }
-};
-
 const ElementTouchHelper = {
   anyElementFromPoint: function(aWindow, aX, aY) {
     let cwu = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     let elem = cwu.elementFromPoint(aX, aY, true, true);
 
     let HTMLIFrameElement = Ci.nsIDOMHTMLIFrameElement;
     let HTMLFrameElement = Ci.nsIDOMHTMLFrameElement;
     while (elem && (elem instanceof HTMLIFrameElement || elem instanceof HTMLFrameElement)) {
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/BrowserElementPanningAPZDisabled.js
@@ -0,0 +1,675 @@
+/* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 sw=2 sts=2 et: */
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+dump("############################### browserElementPanningAPZDisabled.js loaded\n");
+
+let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu }  = Components;
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Geometry.jsm");
+
+var global = this;
+
+const ContentPanningAPZDisabled = {
+  // Are we listening to touch or mouse events?
+  watchedEventsType: '',
+
+  // Are mouse events being delivered to this content along with touch
+  // events, in violation of spec?
+  hybridEvents: false,
+
+  init: function cp_init() {
+    this._setupListenersForPanning();
+  },
+
+  _setupListenersForPanning: function cp_setupListenersForPanning() {
+    let events;
+
+    if (content.TouchEvent) {
+      events = ['touchstart', 'touchend', 'touchmove'];
+      this.watchedEventsType = 'touch';
+#ifdef MOZ_WIDGET_GONK
+      // The gonk widget backend does not deliver mouse events per
+      // spec.  Third-party content isn't exposed to this behavior,
+      // but that behavior creates some extra work for us here.
+      let appInfo = Cc["@mozilla.org/xre/app-info;1"];
+      let isParentProcess =
+        !appInfo || appInfo.getService(Ci.nsIXULRuntime)
+                           .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+      this.hybridEvents = isParentProcess;
+#endif
+    } else {
+      // Touch events aren't supported, so fall back on mouse.
+      events = ['mousedown', 'mouseup', 'mousemove'];
+      this.watchedEventsType = 'mouse';
+    }
+
+    let els = Cc["@mozilla.org/eventlistenerservice;1"]
+                .getService(Ci.nsIEventListenerService);
+
+    events.forEach(function(type) {
+      // Using the system group for mouse/touch events to avoid
+      // missing events if .stopPropagation() has been called.
+      els.addSystemEventListener(global, type,
+                                 this.handleEvent.bind(this),
+                                 /* useCapture = */ false);
+    }.bind(this));
+  },
+
+  handleEvent: function cp_handleEvent(evt) {
+    // Ignore events targeting an oop <iframe mozbrowser> since those will be
+    // handle by the BrowserElementPanning.js instance in the child process.
+    if (evt.target instanceof Ci.nsIMozBrowserFrame) {
+      return;
+    }
+
+    // For in-process <iframe mozbrowser> the events are not targetting
+    // directly the container iframe element, but some node of the document.
+    // So, the BrowserElementPanning instance of the system app will receive
+    // the sequence of touch events, as well as the BrowserElementPanning
+    // instance in the targetted app.
+    // As a result, multiple mozbrowser iframes will try to interpret the
+    // sequence of touch events, which may results into multiple clicks.
+    let targetWindow = evt.target.ownerDocument.defaultView;
+    let frameElement = targetWindow.frameElement;
+    while (frameElement) {
+      targetWindow = frameElement.ownerDocument.defaultView;
+      frameElement = targetWindow.frameElement;
+    }
+
+    if (content !== targetWindow) {
+      return;
+    }
+
+    if (evt.defaultPrevented || evt.multipleActionsPrevented) {
+      // clean up panning state even if touchend/mouseup has been preventDefault.
+      if(evt.type === 'touchend' || evt.type === 'mouseup') {
+        if (this.dragging &&
+            (this.watchedEventsType === 'mouse' ||
+             this.findPrimaryPointer(evt.changedTouches))) {
+          this._finishPanning();
+        }
+      }
+      return;
+    }
+
+    switch (evt.type) {
+      case 'mousedown':
+      case 'touchstart':
+        this.onTouchStart(evt);
+        break;
+      case 'mousemove':
+      case 'touchmove':
+        this.onTouchMove(evt);
+        break;
+      case 'mouseup':
+      case 'touchend':
+        this.onTouchEnd(evt);
+        break;
+      case 'click':
+        evt.stopPropagation();
+        evt.preventDefault();
+
+        let target = evt.target;
+        let view = target.ownerDocument ? target.ownerDocument.defaultView
+                                        : target;
+        view.removeEventListener('click', this, true, true);
+        break;
+    }
+  },
+
+  position: new Point(0 , 0),
+
+  findPrimaryPointer: function cp_findPrimaryPointer(touches) {
+    if (!('primaryPointerId' in this))
+      return null;
+
+    for (let i = 0; i < touches.length; i++) {
+      if (touches[i].identifier === this.primaryPointerId) {
+        return touches[i];
+      }
+    }
+    return null;
+  },
+
+  onTouchStart: function cp_onTouchStart(evt) {
+    let screenX, screenY;
+    if (this.watchedEventsType == 'touch') {
+      if ('primaryPointerId' in this || evt.touches.length >= 2) {
+        this._resetActive();
+        return;
+      }
+
+      let firstTouch = evt.changedTouches[0];
+      this.primaryPointerId = firstTouch.identifier;
+      this.pointerDownTarget = firstTouch.target;
+      screenX = firstTouch.screenX;
+      screenY = firstTouch.screenY;
+    } else {
+      this.pointerDownTarget = evt.target;
+      screenX = evt.screenX;
+      screenY = evt.screenY;
+    }
+    this.dragging = true;
+    this.panning = false;
+
+    let oldTarget = this.target;
+    [this.target, this.scrollCallback] = this.getPannable(this.pointerDownTarget);
+
+    // If we have a pointer down target, we may need to fill in for EventStateManager
+    // in setting the active state on the target element.  Set a timer to
+    // ensure the pointer-down target is active.  (If it's already
+    // active, the timer is a no-op.)
+    if (this.pointerDownTarget !== null) {
+      // If there's no possibility this is a drag/pan, activate now.
+      // Otherwise wait a little bit to see if the gesture isn't a
+      // tap.
+      if (this.target === null) {
+        this.notify(this._activationTimer);
+      } else {
+        this._activationTimer.initWithCallback(this,
+                                               this._activationDelayMs,
+                                               Ci.nsITimer.TYPE_ONE_SHOT);
+      }
+    }
+
+    // If there is a pan animation running (from a previous pan gesture) and
+    // the user touch back the screen, stop this animation immediatly and
+    // prevent the possible click action if the touch happens on the same
+    // target.
+    this.preventNextClick = false;
+    if (KineticPanning.active) {
+      KineticPanning.stop();
+
+      if (oldTarget && oldTarget == this.target)
+        this.preventNextClick = true;
+    }
+
+    this.position.set(screenX, screenY);
+    KineticPanning.reset();
+    KineticPanning.record(new Point(0, 0), evt.timeStamp);
+
+    // We prevent start events to avoid sending a focus event at the end of this
+    // touch series. See bug 889717.
+    if ((this.panning || this.preventNextClick)) {
+      evt.preventDefault();
+    }
+  },
+
+  onTouchEnd: function cp_onTouchEnd(evt) {
+    let touch = null;
+    if (!this.dragging ||
+        (this.watchedEventsType == 'touch' &&
+         !(touch = this.findPrimaryPointer(evt.changedTouches)))) {
+      return;
+    }
+
+    // !isPan() and evt.detail should always give the same answer here
+    // since they use the same heuristics, but use the native gecko
+    // computation when possible.
+    //
+    // NB: when we're using touch events, then !KineticPanning.isPan()
+    // => this.panning, so we'll never attempt to block the click
+    // event.  That's OK however, because we won't fire a synthetic
+    // click when we're using touch events and this touch series
+    // wasn't a "tap" gesture.
+    let click = (this.watchedEventsType == 'mouse') ?
+      evt.detail : !KineticPanning.isPan();
+    // Additionally, if we're seeing non-compliant hybrid events, a
+    // "real" click will be generated if we started and ended on the
+    // same element.
+    if (this.hybridEvents) {
+      let target =
+        content.document.elementFromPoint(touch.clientX, touch.clientY);
+      click |= (target === this.pointerDownTarget);
+    }
+
+    if (this.target && click && (this.panning || this.preventNextClick)) {
+      if (this.hybridEvents) {
+        let target = this.target;
+        let view = target.ownerDocument ? target.ownerDocument.defaultView
+                                        : target;
+        view.addEventListener('click', this, true, true);
+      } else {
+        // We prevent end events to avoid sending a focus event. See bug 889717.
+        evt.preventDefault();
+      }
+    } else if (this.target && click && !this.panning) {
+      this.notify(this._activationTimer);
+    }
+
+    this._finishPanning();
+
+    // Now that we're done, avoid entraining the thing we just panned.
+    this.pointerDownTarget = null;
+  },
+
+  onTouchMove: function cp_onTouchMove(evt) {
+    if (!this.dragging)
+      return;
+
+    let screenX, screenY;
+    if (this.watchedEventsType == 'touch') {
+      let primaryTouch = this.findPrimaryPointer(evt.changedTouches);
+      if (evt.touches.length > 1 || !primaryTouch)
+        return;
+      screenX = primaryTouch.screenX;
+      screenY = primaryTouch.screenY;
+    } else {
+      screenX = evt.screenX;
+      screenY = evt.screenY;
+    }
+
+    let current = this.position;
+    let delta = new Point(screenX - current.x, screenY - current.y);
+    current.set(screenX, screenY);
+
+    KineticPanning.record(delta, evt.timeStamp);
+
+    let isPan = KineticPanning.isPan();
+
+    // If we've detected a pan gesture, cancel the active state of the
+    // current target.
+    if (!this.panning && isPan) {
+      this._resetActive();
+    }
+
+    // There's no possibility of us panning anything.
+    if (!this.scrollCallback) {
+      return;
+    }
+
+    // Scroll manually.
+    this.scrollCallback(delta.scale(-1));
+
+    if (!this.panning && isPan) {
+      this.panning = true;
+      this._activationTimer.cancel();
+    }
+
+    if (this.panning) {
+      // Only do this when we're actually executing a pan gesture.
+      // Otherwise synthetic mouse events will be canceled.
+      evt.stopPropagation();
+      evt.preventDefault();
+    }
+  },
+
+  // nsITimerCallback
+  notify: function cp_notify(timer) {
+    this._setActive(this.pointerDownTarget);
+  },
+
+  onKineticBegin: function cp_onKineticBegin(evt) {
+  },
+
+  onKineticPan: function cp_onKineticPan(delta) {
+    return !this.scrollCallback(delta);
+  },
+
+  onKineticEnd: function cp_onKineticEnd() {
+    if (!this.dragging)
+      this.scrollCallback = null;
+  },
+
+  getPannable: function cp_getPannable(node) {
+    let pannableNode = this._findPannable(node);
+    if (pannableNode) {
+      return [pannableNode, this._generateCallback(pannableNode)];
+    }
+
+    return [null, null];
+  },
+
+  _findPannable: function cp_findPannable(node) {
+    if (!(node instanceof Ci.nsIDOMHTMLElement) || node.tagName == 'HTML') {
+      return null;
+    }
+
+    let nodeContent = node.ownerDocument.defaultView;
+    while (!(node instanceof Ci.nsIDOMHTMLBodyElement)) {
+      let style = nodeContent.getComputedStyle(node, null);
+
+      let overflow = [style.getPropertyValue('overflow'),
+                      style.getPropertyValue('overflow-x'),
+                      style.getPropertyValue('overflow-y')];
+
+      let rect = node.getBoundingClientRect();
+      let isAuto = (overflow.indexOf('auto') != -1 &&
+                   (rect.height < node.scrollHeight ||
+                    rect.width < node.scrollWidth));
+
+      let isScroll = (overflow.indexOf('scroll') != -1);
+
+      let isScrollableTextarea = (node.tagName == 'TEXTAREA' &&
+          (node.scrollHeight > node.clientHeight ||
+           node.scrollWidth > node.clientWidth ||
+           ('scrollLeftMax' in node && node.scrollLeftMax > 0) ||
+           ('scrollTopMax' in node && node.scrollTopMax > 0)));
+      if (isScroll || isAuto || isScrollableTextarea) {
+        return node;
+      }
+
+      node = node.parentNode;
+    }
+
+    if (nodeContent.scrollMaxX || nodeContent.scrollMaxY) {
+      return nodeContent;
+    }
+
+    if (nodeContent.frameElement) {
+      return this._findPannable(nodeContent.frameElement);
+    }
+
+    return null;
+  },
+
+  _generateCallback: function cp_generateCallback(root) {
+    let firstScroll = true;
+    let target;
+    let current;
+    let win, doc, htmlNode, bodyNode;
+
+    function doScroll(node, delta) {
+      if (node instanceof Ci.nsIDOMHTMLElement) {
+        return node.scrollByNoFlush(delta.x, delta.y);
+      } else if (node instanceof Ci.nsIDOMWindow) {
+        win = node;
+        doc = win.document;
+
+        // "overflow:hidden" on either the <html> or the <body> node should
+        // prevent the user from scrolling the root viewport.
+        if (doc instanceof Ci.nsIDOMHTMLDocument) {
+          htmlNode = doc.documentElement;
+          bodyNode = doc.body;
+          if (win.getComputedStyle(htmlNode, null).overflowX == "hidden" ||
+              win.getComputedStyle(bodyNode, null).overflowX == "hidden") {
+            delta.x = 0;
+          }
+          if (win.getComputedStyle(htmlNode, null).overflowY == "hidden" ||
+              win.getComputedStyle(bodyNode, null).overflowY == "hidden") {
+            delta.y = 0;
+          }
+        }
+        let oldX = node.scrollX;
+        let oldY = node.scrollY;
+        node.scrollBy(delta.x, delta.y);
+        return (node.scrollX != oldX || node.scrollY != oldY);
+      }
+      // If we get here, |node| isn't an HTML element and it's not a window,
+      // but findPannable apparently thought it was scrollable... What is it?
+      return false;
+    }
+
+    function targetParent(node) {
+      return node.parentNode || node.frameElement || null;
+    }
+
+    function scroll(delta) {
+      current = root;
+      firstScroll = true;
+      while (current) {
+        if (doScroll(current, delta)) {
+          firstScroll = false;
+          return true;
+        }
+
+        // TODO The current code looks for possible scrolling regions only if
+        // this is the first scroll action but this should be more dynamic.
+        if (!firstScroll) {
+          return false;
+        }
+
+        current = ContentPanningAPZDisabled._findPannable(targetParent(current));
+      }
+
+      // There is nothing scrollable here.
+      return false;
+    }
+    return scroll;
+  },
+
+  get _activationTimer() {
+    delete this._activationTimer;
+    return this._activationTimer = Cc["@mozilla.org/timer;1"]
+                                     .createInstance(Ci.nsITimer);
+  },
+
+  get _activationDelayMs() {
+    let delay = Services.prefs.getIntPref('ui.touch_activation.delay_ms');
+    delete this._activationDelayMs;
+    return this._activationDelayMs = delay;
+  },
+
+  get _domUtils() {
+    delete this._domUtils;
+    return this._domUtils = Cc['@mozilla.org/inspector/dom-utils;1']
+                              .getService(Ci.inIDOMUtils);
+  },
+
+  _resetActive: function cp_resetActive() {
+    let elt = this.pointerDownTarget || this.target;
+    let root = elt.ownerDocument || elt.document;
+    this._setActive(root.documentElement);
+  },
+
+  _setActive: function cp_setActive(elt) {
+    const kStateActive = 0x00000001;
+    this._domUtils.setContentState(elt, kStateActive);
+  },
+
+  _finishPanning: function() {
+    this.dragging = false;
+    delete this.primaryPointerId;
+    this._activationTimer.cancel();
+
+    // If there is a scroll action, let's do a manual kinetic panning action.
+    if (this.panning) {
+      KineticPanning.start(this);
+    }
+  },
+};
+
+// Min/max velocity of kinetic panning. This is in pixels/millisecond.
+const kMinVelocity = 0.2;
+const kMaxVelocity = 6;
+
+// Constants that affect the "friction" of the scroll pane.
+const kExponentialC = 1000;
+const kPolynomialC = 100 / 1000000;
+
+// How often do we change the position of the scroll pane?
+// Too often and panning may jerk near the end.
+// Too little and panning will be choppy. In milliseconds.
+const kUpdateInterval = 16;
+
+// The numbers of momentums to use for calculating the velocity of the pan.
+// Those are taken from the end of the action
+const kSamples = 5;
+
+const KineticPanning = {
+  _position: new Point(0, 0),
+  _velocity: new Point(0, 0),
+  _acceleration: new Point(0, 0),
+
+  get active() {
+    return this.target !== null;
+  },
+
+  target: null,
+  start: function kp_start(target) {
+    this.target = target;
+
+    // Calculate the initial velocity of the movement based on user input
+    let momentums = this.momentums;
+    let flick = momentums[momentums.length - 1].time - momentums[0].time < 300;
+
+    let distance = new Point(0, 0);
+    momentums.forEach(function(momentum) {
+      distance.add(momentum.dx, momentum.dy);
+    });
+
+    function clampFromZero(x, min, max) {
+      if (x >= 0)
+        return Math.max(min, Math.min(max, x));
+      return Math.min(-min, Math.max(-max, x));
+    }
+
+    let elapsed = momentums[momentums.length - 1].time - momentums[0].time;
+    let velocityX = clampFromZero(distance.x / elapsed, 0, kMaxVelocity);
+    let velocityY = clampFromZero(distance.y / elapsed, 0, kMaxVelocity);
+
+    let velocity = this._velocity;
+    if (flick) {
+      // Very fast pan action that does not generate a click are very often pan
+      // action. If this is a small gesture then it will not move the view a lot
+      // and so it will be above the minimun threshold and not generate any
+      // kinetic panning. This does not look on a device since this is often
+      // a real gesture, so let's lower the velocity threshold for such moves.
+      velocity.set(velocityX, velocityY);
+    } else {
+      velocity.set(Math.abs(velocityX) < kMinVelocity ? 0 : velocityX,
+                   Math.abs(velocityY) < kMinVelocity ? 0 : velocityY);
+    }
+    this.momentums = [];
+
+    // Set acceleration vector to opposite signs of velocity
+    function sign(x) {
+      return x ? (x > 0 ? 1 : -1) : 0;
+    }
+
+    this._acceleration.set(velocity.clone().map(sign).scale(-kPolynomialC));
+
+    // Reset the position
+    this._position.set(0, 0);
+
+    this._startAnimation();
+
+    this.target.onKineticBegin();
+  },
+
+  stop: function kp_stop() {
+    this.reset();
+
+    if (!this.target)
+      return;
+
+    this.target.onKineticEnd();
+    this.target = null;
+  },
+
+  reset: function kp_reset() {
+    this.momentums = [];
+    this.distance.set(0, 0);
+  },
+
+  momentums: [],
+  record: function kp_record(delta, timestamp) {
+    this.momentums.push({ 'time': this._getTime(timestamp),
+                          'dx' : delta.x, 'dy' : delta.y });
+
+    // We only need to keep kSamples in this.momentums.
+    if (this.momentums.length > kSamples) {
+      this.momentums.shift();
+    }
+
+    this.distance.add(delta.x, delta.y);
+  },
+
+  _getTime: function kp_getTime(time) {
+    // Touch events generated by the platform or hand-made are defined in
+    // microseconds instead of milliseconds. Bug 77992 will fix this at the
+    // platform level.
+    if (time > Date.now()) {
+      return Math.floor(time / 1000);
+    } else {
+      return time;
+    }
+  },
+
+  get threshold() {
+    let dpi = content.QueryInterface(Ci.nsIInterfaceRequestor)
+                     .getInterface(Ci.nsIDOMWindowUtils)
+                     .displayDPI;
+
+    let threshold = Services.prefs.getIntPref('ui.dragThresholdX') / 240 * dpi;
+
+    delete this.threshold;
+    return this.threshold = threshold;
+  },
+
+  distance: new Point(0, 0),
+  isPan: function cp_isPan() {
+    return (Math.abs(this.distance.x) > this.threshold ||
+            Math.abs(this.distance.y) > this.threshold);
+  },
+
+  _startAnimation: function kp_startAnimation() {
+    let c = kExponentialC;
+    function getNextPosition(position, v, a, t) {
+      // Important traits for this function:
+      //   p(t=0) is 0
+      //   p'(t=0) is v0
+      //
+      // We use exponential to get a smoother stop, but by itself exponential
+      // is too smooth at the end. Adding a polynomial with the appropriate
+      // weight helps to balance
+      position.set(v.x * Math.exp(-t / c) * -c + a.x * t * t + v.x * c,
+                   v.y * Math.exp(-t / c) * -c + a.y * t * t + v.y * c);
+    }
+
+    let startTime = content.mozAnimationStartTime;
+    let elapsedTime = 0, targetedTime = 0, averageTime = 0;
+
+    let velocity = this._velocity;
+    let acceleration = this._acceleration;
+
+    let position = this._position;
+    let nextPosition = new Point(0, 0);
+    let delta = new Point(0, 0);
+
+    let callback = (function(timestamp) {
+      if (!this.target)
+        return;
+
+      // To make animation end fast enough but to keep smoothness, average the
+      // ideal time frame (smooth animation) with the actual time lapse
+      // (end fast enough).
+      // Animation will never take longer than 2 times the ideal length of time.
+      elapsedTime = timestamp - startTime;
+      targetedTime += kUpdateInterval;
+      averageTime = (targetedTime + elapsedTime) / 2;
+
+      // Calculate new position.
+      getNextPosition(nextPosition, velocity, acceleration, averageTime);
+      delta.set(Math.round(nextPosition.x - position.x),
+                Math.round(nextPosition.y - position.y));
+
+      // Test to see if movement is finished for each component.
+      if (delta.x * acceleration.x > 0)
+        delta.x = position.x = velocity.x = acceleration.x = 0;
+
+      if (delta.y * acceleration.y > 0)
+        delta.y = position.y = velocity.y = acceleration.y = 0;
+
+      if (velocity.equals(0, 0) || delta.equals(0, 0)) {
+        this.stop();
+        return;
+      }
+
+      position.add(delta);
+      if (this.target.onKineticPan(delta.scale(-1))) {
+        this.stop();
+        return;
+      }
+
+      content.mozRequestAnimationFrame(callback);
+    }).bind(this);
+
+    content.mozRequestAnimationFrame(callback);
+  }
+};
--- a/dom/browser-element/mochitest/browserElementTestHelpers.js
+++ b/dom/browser-element/mochitest/browserElementTestHelpers.js
@@ -106,97 +106,83 @@ const browserElementTestHelpers = {
   'emptyPage1': 'http://example.com' + _getPath() + '/file_empty.html',
   'emptyPage2': 'http://example.org' + _getPath() + '/file_empty.html',
   'emptyPage3': 'http://test1.example.org' + _getPath() + '/file_empty.html',
   'focusPage': 'http://example.org' + _getPath() + '/file_focus.html',
 };
 
 // Returns a promise which is resolved when a subprocess is created.  The
 // argument to resolve() is the childID of the subprocess.
-function expectProcessCreated(/* optional */ initialPriority,
-                              /* optional */ initialCPUPriority) {
+function expectProcessCreated(/* optional */ initialPriority) {
   return new Promise(function(resolve, reject) {
     var observed = false;
     browserElementTestHelpers.addProcessPriorityObserver(
       "process-created",
       function(subject, topic, data) {
         // Don't run this observer twice, so we don't ok(true) twice.  (It's fine
         // to resolve a promise twice; the second resolve() call does nothing.)
         if (observed) {
           return;
         }
         observed = true;
 
         var childID = parseInt(data);
         ok(true, 'Got new process, id=' + childID);
         if (initialPriority) {
-          expectPriorityChange(childID, initialPriority, initialCPUPriority).then(function() {
+          expectPriorityChange(childID, initialPriority).then(function() {
             resolve(childID);
           });
         } else {
           resolve(childID);
         }
       }
     );
   });
 }
 
 // Just like expectProcessCreated(), except we'll call ok(false) if a second
 // process is created.
-function expectOnlyOneProcessCreated(/* optional */ initialPriority,
-                                     /* optional */ initialCPUPriority) {
-  var p = expectProcessCreated(initialPriority, initialCPUPriority);
+function expectOnlyOneProcessCreated(/* optional */ initialPriority) {
+  var p = expectProcessCreated(initialPriority);
   p.then(function() {
     expectProcessCreated().then(function(childID) {
       ok(false, 'Got unexpected process creation, childID=' + childID);
     });
   });
   return p;
 }
 
 // Returns a promise which is resolved or rejected the next time the process
-// childID changes its priority.  We resolve if the (priority, CPU priority)
-// tuple matches (expectedPriority, expectedCPUPriority) and we reject
-// otherwise.
-//
-// expectedCPUPriority is an optional argument; if it's not specified, we
-// resolve if priority matches expectedPriority.
+// childID changes its priority. We resolve if the priority matches
+// expectedPriority, and we reject otherwise.
 
-function expectPriorityChange(childID, expectedPriority,
-                              /* optional */ expectedCPUPriority) {
+function expectPriorityChange(childID, expectedPriority) {
   return new Promise(function(resolve, reject) {
     var observed = false;
     browserElementTestHelpers.addProcessPriorityObserver(
       'process-priority-set',
       function(subject, topic, data) {
         if (observed) {
           return;
         }
 
-        var [id, priority, cpuPriority] = data.split(":");
+        var [id, priority] = data.split(":");
         if (id != childID) {
           return;
         }
 
         // Make sure we run the is() calls in this observer only once, otherwise
         // we'll expect /every/ priority change to match expectedPriority.
         observed = true;
 
         is(priority, expectedPriority,
            'Expected priority of childID ' + childID +
            ' to change to ' + expectedPriority);
 
-        if (expectedCPUPriority) {
-          is(cpuPriority, expectedCPUPriority,
-             'Expected CPU priority of childID ' + childID +
-             ' to change to ' + expectedCPUPriority);
-        }
-
-        if (priority == expectedPriority &&
-            (!expectedCPUPriority || expectedCPUPriority == cpuPriority)) {
+        if (priority == expectedPriority) {
           resolve();
         } else {
           reject();
         }
       }
     );
   });
 }
@@ -207,23 +193,24 @@ function expectPriorityChange(childID, e
 
 function expectPriorityWithBackgroundLRUSet(childID, expectedBackgroundLRU) {
   return new Promise(function(resolve, reject) {
 
     browserElementTestHelpers.addProcessPriorityObserver(
       'process-priority-with-background-LRU-set',
       function(subject, topic, data) {
 
-        var [id, priority, cpuPriority, backgroundLRU] = data.split(":");
+        var [id, priority, backgroundLRU] = data.split(":");
         if (id != childID) {
           return;
         }
 
         is(backgroundLRU, expectedBackgroundLRU,
-           'Expected backgroundLRU ' + backgroundLRU + ' of childID ' + childID +
+           'Expected backgroundLRU ' + backgroundLRU +
+           ' of childID ' + childID +
            ' to change to ' + expectedBackgroundLRU);
 
         if (backgroundLRU == expectedBackgroundLRU) {
           resolve();
         } else {
           reject();
         }
       }
deleted file mode 100644
--- a/dom/browser-element/mochitest/priority/CAUTION
+++ /dev/null
@@ -1,15 +0,0 @@
-A word to the wise:
-
-You must ensure that if your test finishes successfully, no processes have
-priority FOREGROUND_HIGH.
-
-If you don't do this, expect to see tests randomly fail with mysterious
-FOREGROUND --> FOREGROUND priority transitions.
-
-What's happening in this case is that your FOREGROUND_HIGH process lives until
-the beginning of the next test.  This causes the process started by the next
-test to have low CPU priority.  Then the FOREGROUND_HIGH process dies, because
-its iframe gets GC'ed, and we transition the new test's process from low CPU
-priority to regular CPU priority.
-
-Ouch.
--- a/dom/browser-element/mochitest/priority/mochitest.ini
+++ b/dom/browser-element/mochitest/priority/mochitest.ini
@@ -5,18 +5,16 @@ skip-if = toolkit != "gtk2" || ((buildap
 # Note: ../browserElementTestHelpers.js makes all tests in this directory OOP,
 # because testing the process-priority manager without OOP frames does not make
 # much sense.
 
 [test_Simple.html]
 [test_Visibility.html]
 [test_HighPriority.html]
 support-files = file_HighPriority.html
-[test_HighPriorityDowngrade.html]
-[test_HighPriorityDowngrade2.html]
 [test_Background.html]
 [test_BackgroundLRU.html]
 [test_Audio.html]
 support-files = file_Audio.html silence.ogg
 [test_Keyboard.html]
 [test_MultipleFrames.html]
 support-files = file_MultipleFrames.html
 [test_Preallocated.html]
deleted file mode 100644
--- a/dom/browser-element/mochitest/priority/test_HighPriorityDowngrade.html
+++ /dev/null
@@ -1,81 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-Test that high-priority processes downgrade the CPU priority of regular
-processes.
--->
-<head>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-
-<script type="application/javascript;version=1.7">
-"use strict";
-
-SimpleTest.waitForExplicitFinish();
-browserElementTestHelpers.setEnabledPref(true);
-browserElementTestHelpers.addPermission();
-browserElementTestHelpers.enableProcessPriorityManager();
-SpecialPowers.addPermission("embed-apps", true, document);
-
-var iframe = null;
-var childID = null;
-
-function runTest() {
-  var iframe = document.createElement('iframe');
-  iframe.setAttribute('mozbrowser', true);
-
-  iframe.src = browserElementTestHelpers.emptyPage1;
-
-  var highPriorityIframe = null;
-  var childID = null;
-  var lock = null;
-  var p = null;
-
-  expectProcessCreated('FOREGROUND', 'CPU_NORMAL').then(function(chid) {
-    childID = chid;
-  }).then(function() {
-    // Create a new, high-priority iframe.
-    highPriorityIframe = document.createElement('iframe');
-    highPriorityIframe.setAttribute('mozbrowser', true);
-    highPriorityIframe.setAttribute('expecting-system-message', true);
-    highPriorityIframe.setAttribute('mozapptype', 'critical');
-    highPriorityIframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
-    highPriorityIframe.src = browserElementTestHelpers.emptyPage2;
-
-    p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_LOW');
-
-    document.body.appendChild(highPriorityIframe);
-
-    return p;
-  }).then(function() {
-    return expectPriorityChange(childID, 'FOREGROUND', 'CPU_NORMAL');
-  }).then(function() {
-    p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_LOW');
-    lock = navigator.requestWakeLock('high-priority');
-    return p;
-  }).then(function() {
-    p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_NORMAL');
-    lock.unlock();
-    return p;
-  }).then(SimpleTest.finish);
-
-  document.body.appendChild(iframe);
-}
-
-addEventListener('testready', function() {
-  SpecialPowers.pushPrefEnv(
-    {set: [
-      /* Cause the CPU wake lock taken on behalf of the high-priority process
-       * to time out after 1s. */
-       ["dom.ipc.systemMessageCPULockTimeoutSec", 1],
-       ["dom.wakelock.enabled", true]
-    ]},
-    runTest);
-});
-
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/browser-element/mochitest/priority/test_HighPriorityDowngrade2.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-Test that high-priority processes downgrade the CPU priority of regular
-processes.
-
-This is just like test_HighPriorityDowngrade, except instead of waiting for the
-high-priority process's wake lock to expire, we kill the process by removing
-its iframe from the DOM.
--->
-<head>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-
-<script type="application/javascript;version=1.7">
-"use strict";
-
-SimpleTest.waitForExplicitFinish();
-browserElementTestHelpers.setEnabledPref(true);
-browserElementTestHelpers.addPermission();
-browserElementTestHelpers.enableProcessPriorityManager();
-SpecialPowers.addPermission("embed-apps", true, document);
-
-function runTest() {
-  var iframe = document.createElement('iframe');
-  iframe.setAttribute('mozbrowser', true);
-
-  iframe.src = browserElementTestHelpers.emptyPage1;
-
-  var highPriorityIframe = null;
-  var childID = null;
-
-  expectProcessCreated('FOREGROUND', 'CPU_NORMAL').then(function(chid) {
-    childID = chid;
-  }).then(function() {
-    // Create a new, high-priority iframe.
-    highPriorityIframe = document.createElement('iframe');
-    highPriorityIframe.setAttribute('mozbrowser', true);
-    highPriorityIframe.setAttribute('expecting-system-message', true);
-    highPriorityIframe.setAttribute('mozapptype', 'critical');
-    highPriorityIframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
-    highPriorityIframe.src = browserElementTestHelpers.emptyPage2;
-
-    var p = Promise.all(
-      [expectPriorityChange(childID, 'FOREGROUND', 'CPU_LOW'),
-       expectMozbrowserEvent(highPriorityIframe, 'loadend')]
-    );
-
-    document.body.appendChild(highPriorityIframe);
-
-    return p;
-  }).then(function() {
-    // Killing the high-priority iframe should cause our CPU priority to go back
-    // up to regular.
-    var p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_NORMAL');
-    document.body.removeChild(highPriorityIframe);
-    return p;
-  }).then(SimpleTest.finish);
-
-  document.body.appendChild(iframe);
-}
-
-addEventListener('testready', function() {
-  // Cause the CPU wake lock taken on behalf of the high-priority process never
-  // to time out during this test.
-  SpecialPowers.pushPrefEnv(
-    {set: [["dom.ipc.systemMessageCPULockTimeoutSec", 1000]]},
-    runTest);
-});
-
-</script>
-</body>
-</html>
--- a/dom/browser-element/mochitest/priority/test_Preallocated.html
+++ b/dom/browser-element/mochitest/priority/test_Preallocated.html
@@ -48,17 +48,17 @@ function runTest()
     ok(false, "dom.ipc.processPrelaunch.enabled must be " +
               "false for this test to work.");
     SimpleTest.finish();
     return;
   }
 
   // Ensure that the preallocated process initially gets BACKGROUND priority.
   // That's it.
-  expectProcessCreated('PREALLOC', 'CPU_LOW').then(function() {
+  expectProcessCreated('PREALLOC').then(function() {
     // We need to set the pref asynchoronously or the preallocated process won't
     // be shut down.
     SimpleTest.executeSoon(function(){
       cleanUp();
       SimpleTest.finish();
     });
   });
 }
--- a/dom/canvas/test/_webgl-conformance.ini
+++ b/dom/canvas/test/_webgl-conformance.ini
@@ -494,16 +494,17 @@ support-files = webgl-conformance/../web
 [webgl-conformance/_wrappers/test_conformance__buffers__buffer-bind-test.html]
 [webgl-conformance/_wrappers/test_conformance__buffers__buffer-data-array-buffer.html]
 [webgl-conformance/_wrappers/test_conformance__buffers__index-validation-copies-indices.html]
 [webgl-conformance/_wrappers/test_conformance__buffers__index-validation-crash-with-buffer-sub-data.html]
 [webgl-conformance/_wrappers/test_conformance__buffers__index-validation-verifies-too-many-indices.html]
 [webgl-conformance/_wrappers/test_conformance__buffers__index-validation-with-resized-buffer.html]
 [webgl-conformance/_wrappers/test_conformance__buffers__index-validation.html]
 [webgl-conformance/_wrappers/test_conformance__canvas__buffer-offscreen-test.html]
+skip-if = os == 'android'
 [webgl-conformance/_wrappers/test_conformance__canvas__buffer-preserve-test.html]
 [webgl-conformance/_wrappers/test_conformance__canvas__canvas-test.html]
 [webgl-conformance/_wrappers/test_conformance__canvas__canvas-zero-size.html]
 [webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html]
 skip-if = os == 'mac'
 [webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-test.html]
 [webgl-conformance/_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html]
 [webgl-conformance/_wrappers/test_conformance__context__constants.html]
@@ -770,16 +771,17 @@ skip-if = (os == 'android') || (os == 'b
 [webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind-2.html]
 [webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind.html]
 [webgl-conformance/_wrappers/test_conformance__textures__texture-complete.html]
 [webgl-conformance/_wrappers/test_conformance__textures__texture-formats-test.html]
 [webgl-conformance/_wrappers/test_conformance__textures__texture-mips.html]
 [webgl-conformance/_wrappers/test_conformance__textures__texture-npot-video.html]
 skip-if = os == 'win'
 [webgl-conformance/_wrappers/test_conformance__textures__texture-npot.html]
+skip-if = os == 'android'
 [webgl-conformance/_wrappers/test_conformance__textures__texture-size.html]
 skip-if = os == 'android'
 [webgl-conformance/_wrappers/test_conformance__textures__texture-size-cube-maps.html]
 skip-if = os == 'android'
 [webgl-conformance/_wrappers/test_conformance__textures__texture-transparent-pixels-initialized.html]
 [webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-crash.html]
 [webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-view-crash.html]
 [webgl-conformance/_wrappers/test_conformance__typedarrays__array-unit-tests.html]
--- a/dom/canvas/test/test_toDataURL_alpha.html
+++ b/dom/canvas/test/test_toDataURL_alpha.html
@@ -154,17 +154,17 @@ function do_canvas(row, col, type, optio
     var data = canvas.toDataURL(type, options);
 
     ctx.fillStyle = '#000';
     ctx.fillRect(0, 0, 100, 50);
     var img = new Image();
 
     var color = document.getElementById('c' + row).textContent;
     color = color.substr(5, color.length - 6); // strip off the 'argb()'
-    var colors = color.replace(' ', '', 'g').split(',');
+    var colors = color.replace(/ /g, '').split(',');
     var r = colors[0]*colors[3],
         g = colors[1]*colors[3],
         b = colors[2]*colors[3];
 
     img.onload = function ()
     {
         ctx.drawImage(img, 0, 0);
         isPixel(ctx, 50,25, r,g,b,255, 8);
--- a/dom/canvas/test/webgl-conformance/mochi-single.html
+++ b/dom/canvas/test/webgl-conformance/mochi-single.html
@@ -117,17 +117,16 @@ function GetExpectedTestFailSet() {
         failSet['conformance/glsl/functions/glsl-function-step-gentype.html'] = true;
         failSet['conformance/limits/gl-max-texture-dimensions.html'] = true;
         failSet['conformance/limits/gl-min-textures.html'] = true;
         failSet['conformance/rendering/draw-elements-out-of-bounds.html'] = true;
         failSet['conformance/state/gl-get-calls.html'] = true;
         failSet['conformance/textures/tex-image-with-format-and-type.html'] = true;
         failSet['conformance/textures/tex-sub-image-2d.html'] = true;
         failSet['conformance/textures/texture-mips.html'] = true;
-        failSet['conformance/textures/texture-npot.html'] = true;
         failSet['conformance/textures/texture-size-cube-maps.html'] = true;
       } else {
         // Android 2.3 slaves.
         failSet['conformance/extensions/oes-texture-float.html'] = true;
         failSet['conformance/glsl/functions/glsl-function-sin.html'] = true;
         failSet['conformance/misc/object-deletion-behaviour.html'] = true;
         failSet['conformance/programs/program-test.html'] = true;
         failSet['conformance/textures/tex-image-and-sub-image-2d-with-video.html'] = true;
--- a/dom/canvas/test/webgl-conformance/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conformance/mochitest-errata.ini
@@ -48,31 +48,38 @@ skip-if = (os == 'android') || (os == 'b
 skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
 [_wrappers/test_conformance__textures__tex-image-with-format-and-type.html]
 # Crashes or blues on Android 2.3
 skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
 [_wrappers/test_conformance__textures__tex-input-validation.html]
 # Crashes on 'Android 2.3'
 # Asserts on 'B2G ICS Emulator Debug'.
 skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
+[_wrappers/test_conformance__canvas__buffer-offscreen-test.html]
+# Causes frequent *blues*: "DMError: Remote Device Error: unable to
+# connect to 127.0.0.1 after 5 attempts" on 'Android 2.3 Opt'.
+skip-if = os == 'android'
 
 ########################################################################
 # Android
 [_wrappers/test_conformance__misc__uninitialized-test.html]
 # Crashes on Android.
 skip-if = os == 'android'
 [_wrappers/test_conformance__renderbuffers__framebuffer-object-attachment.html]
 # Crashes on Android.
 skip-if = os == 'android'
 [_wrappers/test_conformance__textures__texture-size.html]
 # Crashes on Android 4.0.
 skip-if = os == 'android'
 [_wrappers/test_conformance__textures__texture-size-cube-maps.html]
 # Crashes on Android 4.0.
 skip-if = os == 'android'
+[_wrappers/test_conformance__textures__texture-npot.html]
+# Intermittent fail on Android 4.0.
+skip-if = os == 'android'
 
 ########################################################################
 # B2G
 [_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html]
 # Asserts on 'B2G ICS Emulator Debug'.
 skip-if = (os == 'b2g')
 [_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html]
 # Intermittently asserts on 'B2G ICS Emulator Debug'.
--- a/dom/cellbroadcast/gonk/CellBroadcastService.js
+++ b/dom/cellbroadcast/gonk/CellBroadcastService.js
@@ -23,19 +23,23 @@ const kSettingsCellBroadcastSearchList =
 XPCOMUtils.defineLazyServiceGetter(this, "gCellbroadcastMessenger",
                                    "@mozilla.org/ril/system-messenger-helper;1",
                                    "nsICellbroadcastMessenger");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
                                    "@mozilla.org/settingsService;1",
                                    "nsISettingsService");
 
-XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
-                                   "@mozilla.org/ril;1",
-                                   "nsIRadioInterfaceLayer");
+XPCOMUtils.defineLazyGetter(this, "gRadioInterfaceLayer", function() {
+  let ril = { numRadioInterfaces: 0 };
+  try {
+    ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
+  } catch(e) {}
+  return ril;
+});
 
 const GONK_CELLBROADCAST_SERVICE_CONTRACTID =
   "@mozilla.org/cellbroadcast/gonkservice;1";
 const GONK_CELLBROADCAST_SERVICE_CID =
   Components.ID("{7ba407ce-21fd-11e4-a836-1bfdee377e5c}");
 const CELLBROADCASTMESSAGE_CID =
   Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
 const CELLBROADCASTETWSINFO_CID =
--- a/dom/cellbroadcast/moz.build
+++ b/dom/cellbroadcast/moz.build
@@ -13,17 +13,17 @@ EXPORTS.mozilla.dom += [
 
 UNIFIED_SOURCES += [
     'CellBroadcast.cpp',
     'CellBroadcastMessage.cpp',
     'ipc/CellBroadcastIPCService.cpp',
     'ipc/CellBroadcastParent.cpp',
 ]
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL'] and not CONFIG['DISABLE_MOZ_RIL_GEOLOC']:
     EXTRA_COMPONENTS += [
         'gonk/CellBroadcastService.js',
         'gonk/CellBroadcastService.manifest',
     ]
 
 EXPORTS.mozilla.dom.cellbroadcast += [
     'ipc/CellBroadcastIPCService.h',
     'ipc/CellBroadcastParent.h',
--- a/dom/downloads/tests/file_app.sjs
+++ b/dom/downloads/tests/file_app.sjs
@@ -28,28 +28,27 @@ function readTemplate(path) {
   var split = path.split("/");
   for(var i = 0; i < split.length; ++i) {
     file.append(split[i]);
   }
   fis.init(file, -1, -1, false);
   cis.init(fis, "UTF-8", 0, 0);
 
   var data = "";
-  let (str = {}) {
-    let read = 0;
-    do {
-      read = cis.readString(0xffffffff, str); // read as much as we can and put it in str.value
-      data += str.value;
-    } while (read != 0);
-  }
+  let str = {};
+  let read = 0;
+  do {
+    read = cis.readString(0xffffffff, str); // read as much as we can and put it in str.value
+    data += str.value;
+  } while (read != 0);
+
   cis.close();
   return data;
 }
 
 function getQuery(request) {
   var query = {};
   request.queryString.split('&').forEach(function (val) {
     var [name, value] = val.split('=');
     query[name] = unescape(value);
   });
   return query;
 }
-
new file mode 100644
--- /dev/null
+++ b/dom/geolocation/MLSFallback.cpp
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MLSFallback.h"
+#include "nsGeoPosition.h"
+#include "nsIGeolocationProvider.h"
+#include "nsServiceManagerUtils.h"
+
+NS_IMPL_ISUPPORTS(MLSFallback, nsITimerCallback)
+
+MLSFallback::MLSFallback(uint32_t delay)
+: mDelayMs(delay)
+{
+}
+
+MLSFallback::~MLSFallback()
+{
+}
+
+nsresult
+MLSFallback::Startup(nsIGeolocationUpdate* aWatcher)
+{
+  if (mHandoffTimer || mMLSFallbackProvider) {
+    return NS_OK;
+  }
+
+  mUpdateWatcher = aWatcher;
+  nsresult rv;
+  mHandoffTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = mHandoffTimer->InitWithCallback(this, mDelayMs, nsITimer::TYPE_ONE_SHOT);
+  return rv;
+}
+
+nsresult
+MLSFallback::Shutdown()
+{
+  mUpdateWatcher = nullptr;
+
+  if (mHandoffTimer) {
+    mHandoffTimer->Cancel();
+    mHandoffTimer = nullptr;
+  }
+
+  nsresult rv = NS_OK;
+  if (mMLSFallbackProvider) {
+    rv = mMLSFallbackProvider->Shutdown();
+    mMLSFallbackProvider = nullptr;
+  }
+  return rv;
+}
+
+NS_IMETHODIMP
+MLSFallback::Notify(nsITimer* aTimer)
+{
+  return CreateMLSFallbackProvider();
+}
+
+nsresult
+MLSFallback::CreateMLSFallbackProvider()
+{
+  if (mMLSFallbackProvider || !mUpdateWatcher) {
+    return NS_OK;
+  }
+
+  nsresult rv;
+  mMLSFallbackProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (mMLSFallbackProvider) {
+    rv = mMLSFallbackProvider->Startup();
+    if (NS_SUCCEEDED(rv)) {
+      mMLSFallbackProvider->Watch(mUpdateWatcher);
+    }
+  }
+  mUpdateWatcher = nullptr;
+  return rv;
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/geolocation/MLSFallback.h
@@ -0,0 +1,47 @@
+/* -*- 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 "nsCOMPtr.h"
+#include "nsITimer.h"
+
+class nsIGeolocationUpdate;
+class nsIGeolocationProvider;
+
+/*
+ This class wraps the NetworkGeolocationProvider in a delayed startup.
+ It is for providing a fallback to MLS when:
+ 1) using another provider as the primary provider, and
+ 2) that primary provider may fail to return a result (i.e. the error returned
+ is indeterminate, or no error callback occurs)
+
+ The intent is that the primary provider is started, then MLSFallback
+ is started with sufficient delay that the primary provider will respond first
+ if successful (in the majority of cases).
+
+ MLS has an average response of 3s, so with the 2s default delay, a response can
+ be expected in 5s.
+
+ Telemetry is recommended to monitor that the primary provider is responding
+ first when expected to do so.
+*/
+class MLSFallback : public nsITimerCallback
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSITIMERCALLBACK
+
+  explicit MLSFallback(uint32_t delayMs = 2000);
+  nsresult Startup(nsIGeolocationUpdate* aWatcher);
+  nsresult Shutdown();
+
+private:
+  nsresult CreateMLSFallbackProvider();
+  virtual ~MLSFallback();
+  nsCOMPtr<nsITimer> mHandoffTimer;
+  nsCOMPtr<nsIGeolocationProvider> mMLSFallbackProvider;
+  nsCOMPtr<nsIGeolocationUpdate> mUpdateWatcher;
+  const uint32_t mDelayMs;
+};
+
--- a/dom/geolocation/moz.build
+++ b/dom/geolocation/moz.build
@@ -10,16 +10,17 @@ EXPORTS += [
     'nsGeoPositionIPCSerialiser.h',
 ]
 
 SOURCES += [
     'nsGeolocation.cpp',
 ]
 
 UNIFIED_SOURCES += [
+    'MLSFallback.cpp',
     'nsGeoGridFuzzer.cpp',
     'nsGeolocationSettings.cpp',
     'nsGeoPosition.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/html/test/forms/test_input_typing_sanitization.html
+++ b/dom/html/test/forms/test_input_typing_sanitization.html
@@ -39,17 +39,17 @@ function submitForm() {
   form.submit();
 }
 
 function sendKeyEventToSubmitForm() {
   sendKey("return");
 }
 
 function urlify(aStr) {
-  return aStr.replace(':', '%3A', 'g');
+  return aStr.replace(/:/g, '%3A');
 }
 
 function runTestsForNextInputType()
 {
   try {
     testRunner.next();
   } catch (e) {
     if (e.toString() == '[object StopIteration]') {
--- a/dom/html/test/test_documentAll.html
+++ b/dom/html/test/test_documentAll.html
@@ -37,17 +37,17 @@ function testNumSame() {
   is(document.all.id2[1], p.children[2], "two ids");
   is(document.all.id2.length, 2, "two length");
   is(document.all.id3[0], p.children[3], "three ids");
   is(document.all.id3[1], p.children[4], "three ids");
   is(document.all.id3[2], p.children[5], "three ids");
   is(document.all.id3.length, 3, "three length");
 }
 testNumSame();
-p.innerHTML = p.innerHTML.replace("id=", "name=", "g");
+p.innerHTML = p.innerHTML.replace(/id=/g, "name=");
 testNumSame();
 
 
 // Test that dynamic changes behave properly
 
 // Add two elements and check that they are added to the correct lists
 child = Array.prototype.slice.call(p.children);
 child[6] = document.createElement("a");
--- a/dom/html/test/test_formSubmission.html
+++ b/dom/html/test/test_formSubmission.html
@@ -575,20 +575,20 @@ expectedAugment = [
 
 function checkMPSubmission(sub, expected, test) {
   function getPropCount(o) {
     var x, l = 0;
     for (x in o) ++l;
     return l;
   }
   function mpquote(s) {
-    return s.replace("\r\n", " ", "g")
-            .replace("\r", " ", "g")
-            .replace("\n", " ", "g")
-            .replace("\"", "\\\"", "g");
+    return s.replace(/\r\n/g, " ")
+            .replace(/\r/g, " ")
+            .replace(/\n/g, " ")
+            .replace(/\"/g, "\\\"");
   }
 
   is(sub.length, expected.length,
      "Correct number of multipart items in " + test);
   
   if (sub.length != expected.length) {
     alert(JSON.stringify(sub));
   }
@@ -623,19 +623,19 @@ function checkMPSubmission(sub, expected
 }
 
 function utf8encode(s) {
   return unescape(encodeURIComponent(s));
 }
 
 function checkURLSubmission(sub, expected) {
   function urlEscape(s) {
-    return escape(utf8encode(s)).replace("%20", "+", "g")
-                                .replace("/", "%2F", "g")
-                                .replace("@", "%40", "g");
+    return escape(utf8encode(s)).replace(/%20/g, "+")
+                                .replace(/\//g, "%2F")
+                                .replace(/@/g, "%40");
   }
 
   subItems = sub.split("&");
   is(subItems.length, expected.length,
      "Correct number of url items");
   var i;
   for (i = 0; i < expected.length; ++i) {
     let expect = urlEscape(expected[i].name) + "=" +
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -447,17 +447,18 @@ private:
 
         JS::Rooted<JS::Value> value(aCx);
 
         nsresult rv = GetResult(aCx, &cloneInfo, &value);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
 
-        if (NS_WARN_IF(!JS_SetElement(aCx, array, index, value))) {
+        if (NS_WARN_IF(!JS_DefineElement(aCx, array, index, value,
+                                         JSPROP_ENUMERATE))) {
           IDB_REPORT_INTERNAL_ERR();
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
       }
     }
 
     aResult.setObject(*array);
     return NS_OK;
@@ -500,17 +501,18 @@ private:
 
         JS::Rooted<JS::Value> value(aCx);
 
         nsresult rv = GetResult(aCx, &key, &value);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
 
-        if (NS_WARN_IF(!JS_SetElement(aCx, array, index, value))) {
+        if (NS_WARN_IF(!JS_DefineElement(aCx, array, index, value,
+                                         JSPROP_ENUMERATE))) {
           IDB_REPORT_INTERNAL_ERR();
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
       }
     }
 
     aResult.setObject(*array);
     return NS_OK;
@@ -1089,17 +1091,17 @@ BackgroundFactoryRequestChild::Recv__del
       break;
 
     default:
       MOZ_CRASH("Unknown response type!");
   }
 
   IDBOpenDBRequest* request = GetOpenDBRequest();
   MOZ_ASSERT(request);
-  
+
   request->NoteComplete();
 
   if (NS_WARN_IF(!result)) {
     return false;
   }
 
   return true;
 }
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -213,17 +213,17 @@ Key::DecodeJSValInternal(const unsigned 
     JS::Rooted<JS::Value> val(aCx);
     while (aPos < aEnd && *aPos - aTypeOffset != eTerminator) {
       nsresult rv = DecodeJSValInternal(aPos, aEnd, aCx, aTypeOffset,
                                         &val, aRecursionDepth + 1);
       NS_ENSURE_SUCCESS(rv, rv);
 
       aTypeOffset = 0;
 
-      if (!JS_SetElement(aCx, array, index++, val)) {
+      if (!JS_DefineElement(aCx, array, index++, val, JSPROP_ENUMERATE)) {
         NS_WARNING("Failed to set array element!");
         IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
     NS_ASSERTION(aPos >= aEnd || (*aPos % eMaxType) == eTerminator,
                  "Should have found end-of-array marker");
--- a/dom/indexedDB/KeyPath.cpp
+++ b/dom/indexedDB/KeyPath.cpp
@@ -354,17 +354,17 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aC
     nsresult rv = GetJSValFromKeyPathString(aCx, aValue, mStrings[i],
                                             value.address(),
                                             DoNotCreateProperties, nullptr,
                                             nullptr);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
-    if (!JS_SetElement(aCx, arrayObj, i, value)) {
+    if (!JS_DefineElement(aCx, arrayObj, i, value, JSPROP_ENUMERATE)) {
       IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
 
   *aOutVal = OBJECT_TO_JSVAL(arrayObj);
   return NS_OK;
 }
@@ -466,17 +466,17 @@ KeyPath::ToJSVal(JSContext* aCx, JS::Mut
     for (uint32_t i = 0; i < len; ++i) {
       JS::Rooted<JS::Value> val(aCx);
       nsString tmp(mStrings[i]);
       if (!xpc::StringToJsval(aCx, tmp, &val)) {
         IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
-      if (!JS_SetElement(aCx, array, i, val)) {
+      if (!JS_DefineElement(aCx, array, i, val, JSPROP_ENUMERATE)) {
         IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
     aValue.setObject(*array);
     return NS_OK;
   }
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -134,23 +134,16 @@ public:
   /**
    * If a magic testing-only pref is set, notify the observer service on the
    * given topic with the given data.  This is used for testing
    */
   void FireTestOnlyObserverNotification(const char* aTopic,
                                         const nsACString& aData = EmptyCString());
 
   /**
-   * Does some process, other than the one handled by aParticularManager, have
-   * priority FOREGROUND_HIGH?
-   */
-  bool OtherProcessHasHighPriority(
-    ParticularProcessPriorityManager* aParticularManager);
-
-  /**
    * Does one of the child processes have priority FOREGROUND_HIGH?
    */
   bool ChildProcessHasHighPriority();
 
   /**
    * This must be called by a ParticularProcessPriorityManager when it changes
    * its priority.
    */
@@ -177,17 +170,16 @@ private:
 
   void Init();
 
   already_AddRefed<ParticularProcessPriorityManager>
   GetParticularProcessPriorityManager(ContentParent* aContentParent);
 
   void ObserveContentParentCreated(nsISupports* aContentParent);
   void ObserveContentParentDestroyed(nsISupports* aSubject);
-  void ResetAllCPUPriorities();
 
   nsDataHashtable<nsUint64HashKey, nsRefPtr<ParticularProcessPriorityManager> >
     mParticularManagers;
 
   bool mHighPriority;
   nsTHashtable<nsUint64HashKey> mHighPriorityChildIDs;
 };
 
@@ -262,49 +254,36 @@ public:
   void OnAudioChannelProcessChanged(nsISupports* aSubject);
   void OnRemoteBrowserFrameShown(nsISupports* aSubject);
   void OnTabParentDestroyed(nsISupports* aSubject);
   void OnFrameloaderVisibleChanged(nsISupports* aSubject);
   void OnChannelConnected(nsISupports* aSubject);
 
   ProcessPriority CurrentPriority();
   ProcessPriority ComputePriority();
-  ProcessCPUPriority ComputeCPUPriority(ProcessPriority aPriority);
 
   void ScheduleResetPriority(const char* aTimeoutPref);
   void ResetPriority();
   void ResetPriorityNow();
-  void ResetCPUPriorityNow();
-
-  /**
-   * This overload is equivalent to SetPriorityNow(aPriority,
-   * ComputeCPUPriority()).
-   */
-  void SetPriorityNow(ProcessPriority aPriority,
-                      uint32_t aBackgroundLRU = 0);
-
-  void SetPriorityNow(ProcessPriority aPriority,
-                      ProcessCPUPriority aCPUPriority,
-                      uint32_t aBackgroundLRU = 0);
+  void SetPriorityNow(ProcessPriority aPriority, uint32_t aBackgroundLRU = 0);
 
   void ShutDown();
 
 private:
   void FireTestOnlyObserverNotification(
     const char* aTopic,
     const nsACString& aData = EmptyCString());
 
   void FireTestOnlyObserverNotification(
     const char* aTopic,
     const char* aData = nullptr);
 
   ContentParent* mContentParent;
   uint64_t mChildID;
   ProcessPriority mPriority;
-  ProcessCPUPriority mCPUPriority;
   bool mHoldsCPUWakeLock;
   bool mHoldsHighPriorityWakeLock;
 
   /**
    * Used to implement NameWithComma().
    */
   nsAutoCString mNameWithComma;
 
@@ -434,18 +413,17 @@ ProcessPriorityManagerImpl::~ProcessPrio
 void
 ProcessPriorityManagerImpl::Init()
 {
   LOG("Starting up.  This is the master process.");
 
   // The master process's priority never changes; set it here and then forget
   // about it.  We'll manage only subprocesses' priorities using the process
   // priority manager.
-  hal::SetProcessPriority(getpid(), PROCESS_PRIORITY_MASTER,
-                          PROCESS_CPU_PRIORITY_NORMAL);
+  hal::SetProcessPriority(getpid(), PROCESS_PRIORITY_MASTER);
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
     os->AddObserver(this, "ipc:content-created", /* ownsWeak */ false);
     os->AddObserver(this, "ipc:content-shutdown", /* ownsWeak */ false);
   }
 }
 
@@ -512,28 +490,16 @@ ProcessPriorityManagerImpl::ObserveConte
 {
   // Do nothing; it's sufficient to get the PPPM.  But assign to nsRefPtr so we
   // don't leak the already_AddRefed object.
   nsCOMPtr<nsIContentParent> cp = do_QueryInterface(aContentParent);
   nsRefPtr<ParticularProcessPriorityManager> pppm =
     GetParticularProcessPriorityManager(cp->AsContentParent());
 }
 
-static PLDHashOperator
-EnumerateParticularProcessPriorityManagers(
-  const uint64_t& aKey,
-  nsRefPtr<ParticularProcessPriorityManager> aValue,
-  void* aUserData)
-{
-  nsTArray<nsRefPtr<ParticularProcessPriorityManager> >* aArray =
-    static_cast<nsTArray<nsRefPtr<ParticularProcessPriorityManager> >*>(aUserData);
-  aArray->AppendElement(aValue);
-  return PL_DHASH_NEXT;
-}
-
 void
 ProcessPriorityManagerImpl::ObserveContentParentDestroyed(nsISupports* aSubject)
 {
   nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
   NS_ENSURE_TRUE_VOID(props);
 
   uint64_t childID = CONTENT_PROCESS_ID_UNKNOWN;
   props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
@@ -543,122 +509,79 @@ ProcessPriorityManagerImpl::ObserveConte
   mParticularManagers.Get(childID, &pppm);
   if (pppm) {
     pppm->ShutDown();
 
     mParticularManagers.Remove(childID);
 
     if (mHighPriorityChildIDs.Contains(childID)) {
       mHighPriorityChildIDs.RemoveEntry(childID);
-
-      // We just lost a high-priority process; reset everyone's CPU priorities.
-      ResetAllCPUPriorities();
     }
   }
 }
 
-void
-ProcessPriorityManagerImpl::ResetAllCPUPriorities( void )
-{
-  nsTArray<nsRefPtr<ParticularProcessPriorityManager> > pppms;
-  mParticularManagers.EnumerateRead(
-    &EnumerateParticularProcessPriorityManagers,
-    &pppms);
-
-  for (uint32_t i = 0; i < pppms.Length(); i++) {
-    pppms[i]->ResetCPUPriorityNow();
-  }
-}
-
-bool
-ProcessPriorityManagerImpl::OtherProcessHasHighPriority(
-  ParticularProcessPriorityManager* aParticularManager)
-{
-  if (mHighPriority) {
-    return true;
-  } else if (mHighPriorityChildIDs.Contains(aParticularManager->ChildID())) {
-    return mHighPriorityChildIDs.Count() > 1;
-  }
-  return mHighPriorityChildIDs.Count() > 0;
-}
-
 bool
 ProcessPriorityManagerImpl::ChildProcessHasHighPriority( void )
 {
   return mHighPriorityChildIDs.Count() > 0;
 }
 
 void
 ProcessPriorityManagerImpl::NotifyProcessPriorityChanged(
   ParticularProcessPriorityManager* aParticularManager,
   ProcessPriority aOldPriority)
 {
-  // This priority change can only affect other processes' priorities if we're
-  // changing to/from FOREGROUND_HIGH.
+  /* We're interested only in changes to/from FOREGROUND_HIGH as we use we
+   * need to track high priority processes so that we can react to their
+   * presence. */
 
   if (aOldPriority < PROCESS_PRIORITY_FOREGROUND_HIGH &&
       aParticularManager->CurrentPriority() <
         PROCESS_PRIORITY_FOREGROUND_HIGH) {
 
     return;
   }
 
   if (aParticularManager->CurrentPriority() >=
       PROCESS_PRIORITY_FOREGROUND_HIGH) {
     mHighPriorityChildIDs.PutEntry(aParticularManager->ChildID());
   } else {
     mHighPriorityChildIDs.RemoveEntry(aParticularManager->ChildID());
   }
-
-  nsTArray<nsRefPtr<ParticularProcessPriorityManager> > pppms;
-  mParticularManagers.EnumerateRead(
-    &EnumerateParticularProcessPriorityManagers,
-    &pppms);
-
-  for (uint32_t i = 0; i < pppms.Length(); i++) {
-    if (pppms[i] != aParticularManager) {
-      pppms[i]->ResetCPUPriorityNow();
-    }
-  }
 }
 
 /* virtual */ void
 ProcessPriorityManagerImpl::Notify(const WakeLockInformation& aInfo)
 {
   /* The main process always has an ID of 0, if it is present in the wake-lock
    * information then we explicitly requested a high-priority wake-lock for the
    * main process. */
   if (aInfo.topic().EqualsLiteral("high-priority")) {
     if (aInfo.lockingProcesses().Contains((uint64_t)0)) {
       mHighPriority = true;
     } else {
       mHighPriority = false;
     }
 
-    /* The main process got a high-priority wakelock change; reset everyone's
-     * CPU priorities. */
-    ResetAllCPUPriorities();
-
     LOG("Got wake lock changed event. "
         "Now mHighPriorityParent = %d\n", mHighPriority);
   }
 }
 
 
 NS_IMPL_ISUPPORTS(ParticularProcessPriorityManager,
                   nsIObserver,
                   nsITimerCallback,
                   nsISupportsWeakReference);
 
 ParticularProcessPriorityManager::ParticularProcessPriorityManager(
   ContentParent* aContentParent)
   : mContentParent(aContentParent)
   , mChildID(aContentParent->ChildID())
   , mPriority(PROCESS_PRIORITY_UNKNOWN)
-  , mCPUPriority(PROCESS_CPU_PRIORITY_NORMAL)
   , mHoldsCPUWakeLock(false)
   , mHoldsHighPriorityWakeLock(false)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   LOGP("Creating ParticularProcessPriorityManager.");
 }
 
 void
@@ -1010,72 +933,40 @@ ParticularProcessPriorityManager::Comput
     return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
   }
 
   return HasAppType("homescreen") ?
          PROCESS_PRIORITY_BACKGROUND_HOMESCREEN :
          PROCESS_PRIORITY_BACKGROUND;
 }
 
-ProcessCPUPriority
-ParticularProcessPriorityManager::ComputeCPUPriority(ProcessPriority aPriority)
-{
-  if (aPriority == PROCESS_PRIORITY_PREALLOC) {
-    return PROCESS_CPU_PRIORITY_LOW;
-  }
-
-  if (aPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH) {
-    return PROCESS_CPU_PRIORITY_NORMAL;
-  }
-
-  return ProcessPriorityManagerImpl::GetSingleton()->
-    OtherProcessHasHighPriority(this) ?
-    PROCESS_CPU_PRIORITY_LOW :
-    PROCESS_CPU_PRIORITY_NORMAL;
-}
-
-void
-ParticularProcessPriorityManager::ResetCPUPriorityNow()
-{
-  SetPriorityNow(mPriority);
-}
-
 void
 ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority,
                                                  uint32_t aBackgroundLRU)
 {
-  SetPriorityNow(aPriority, ComputeCPUPriority(aPriority), aBackgroundLRU);
-}
-
-void
-ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority,
-                                                 ProcessCPUPriority aCPUPriority,
-                                                 uint32_t aBackgroundLRU)
-{
   if (aPriority == PROCESS_PRIORITY_UNKNOWN) {
     MOZ_ASSERT(false);
     return;
   }
 
   if (aBackgroundLRU > 0 &&
       aPriority == PROCESS_PRIORITY_BACKGROUND &&
       mPriority == PROCESS_PRIORITY_BACKGROUND) {
-    hal::SetProcessPriority(Pid(), mPriority, mCPUPriority, aBackgroundLRU);
+    hal::SetProcessPriority(Pid(), mPriority, aBackgroundLRU);
 
     nsPrintfCString ProcessPriorityWithBackgroundLRU("%s:%d",
-      ProcessPriorityToString(mPriority, mCPUPriority),
-      aBackgroundLRU);
+      ProcessPriorityToString(mPriority), aBackgroundLRU);
 
     FireTestOnlyObserverNotification("process-priority-with-background-LRU-set",
       ProcessPriorityWithBackgroundLRU.get());
   }
 
   if (!mContentParent ||
       !ProcessPriorityManagerImpl::PrefsEnabled() ||
-      (mPriority == aPriority && mCPUPriority == aCPUPriority)) {
+      (mPriority == aPriority)) {
     return;
   }
 
   // If the prefs were disabled after this ParticularProcessPriorityManager was
   // created, we can at least avoid any further calls to
   // hal::SetProcessPriority.  Supporting dynamic enabling/disabling of the
   // ProcessPriorityManager is mostly for testing.
   if (!ProcessPriorityManagerImpl::PrefsEnabled()) {
@@ -1090,40 +981,37 @@ ParticularProcessPriorityManager::SetPri
 
   if (aPriority != PROCESS_PRIORITY_BACKGROUND &&
       mPriority == PROCESS_PRIORITY_BACKGROUND &&
       !IsPreallocated()) {
     ProcessPriorityManager::RemoveFromBackgroundLRUPool(mContentParent);
   }
 
   LOGP("Changing priority from %s to %s.",
-       ProcessPriorityToString(mPriority, mCPUPriority),
-       ProcessPriorityToString(aPriority, aCPUPriority));
+       ProcessPriorityToString(mPriority),
+       ProcessPriorityToString(aPriority));
 
   ProcessPriority oldPriority = mPriority;
 
   mPriority = aPriority;
-  mCPUPriority = aCPUPriority;
-  hal::SetProcessPriority(Pid(), mPriority, mCPUPriority);
+  hal::SetProcessPriority(Pid(), mPriority);
 
   if (oldPriority != mPriority) {
+    ProcessPriorityManagerImpl::GetSingleton()->
+      NotifyProcessPriorityChanged(this, oldPriority);
+
     unused << mContentParent->SendNotifyProcessPriorityChanged(mPriority);
   }
 
   if (aPriority < PROCESS_PRIORITY_FOREGROUND) {
     unused << mContentParent->SendFlushMemory(NS_LITERAL_STRING("low-memory"));
   }
 
   FireTestOnlyObserverNotification("process-priority-set",
-    ProcessPriorityToString(mPriority, mCPUPriority));
-
-  if (oldPriority != mPriority) {
-    ProcessPriorityManagerImpl::GetSingleton()->
-      NotifyProcessPriorityChanged(this, oldPriority);
-  }
+    ProcessPriorityToString(mPriority));
 }
 
 void
 ParticularProcessPriorityManager::ShutDown()
 {
   MOZ_ASSERT(mContentParent);
 
   UnregisterWakeLockObserver(this);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2006,17 +2006,17 @@ TabChild::RecvUpdateDimensions(const nsI
     if (initialSizing) {
       mHasValidInnerSize = true;
     }
 
     mOrientation = orientation;
     ScreenIntSize oldScreenSize = mInnerSize;
     mInnerSize = ScreenIntSize::FromUnknownSize(
       gfx::IntSize(size.width, size.height));
-    mWidget->Resize(0, 0, size.width, size.height,
+    mWidget->Resize(rect.x + chromeDisp.x, rect.y + chromeDisp.y, size.width, size.height,
                     true);
 
     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
     baseWin->SetPositionAndSize(0, 0, size.width, size.height,
                                 true);
 
     if (initialSizing && mContentDocumentIsDisplayed) {
       // If this is the first time we're getting a valid mInnerSize, and the
@@ -2222,17 +2222,17 @@ TabChild::UpdateTapState(const WidgetTou
   if (aEvent.message == NS_TOUCH_START) {
     if (currentlyTrackingTouch || aEvent.touches.Length() > 1) {
       // We're tracking a possible tap for another point, or we saw a
       // touchstart for a later pointer after we canceled tracking of
       // the first point.  Ignore this one.
       return;
     }
     if (aStatus == nsEventStatus_eConsumeNoDefault ||
-        nsIPresShell::gPreventMouseEvents ||
+        TouchManager::gPreventMouseEvents ||
         aEvent.mFlags.mMultipleActionsPrevented) {
       return;
     }
 
     Touch* touch = aEvent.touches[0];
     mGestureDownPoint = LayoutDevicePoint(touch->mRefPoint.x, touch->mRefPoint.y);
     mActivePointerId = touch->mIdentifier;
     if (sClickHoldContextMenusEnabled) {
@@ -2263,17 +2263,17 @@ TabChild::UpdateTapState(const WidgetTou
   case NS_TOUCH_MOVE:
     if (std::abs(currentPoint.x - mGestureDownPoint.x) > sDragThreshold.width ||
         std::abs(currentPoint.y - mGestureDownPoint.y) > sDragThreshold.height) {
       CancelTapTracking();
     }
     return;
 
   case NS_TOUCH_END:
-    if (!nsIPresShell::gPreventMouseEvents) {
+    if (!TouchManager::gPreventMouseEvents) {
       APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, currentPoint, mWidget);
       APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, currentPoint, mWidget);
       APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, currentPoint, mWidget);
     }
     // fall through
   case NS_TOUCH_CANCEL:
     CancelTapTracking();
     return;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -75,16 +75,17 @@
 #include "LoadContext.h"
 #include "nsNetCID.h"
 #include "nsIAuthInformation.h"
 #include "nsIAuthPromptCallback.h"
 #include "nsAuthInformationHolder.h"
 #include "nsICancelable.h"
 #include "gfxPrefs.h"
 #include "nsILoginManagerPrompter.h"
+#include "nsPIWindowRoot.h"
 #include <algorithm>
 
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 using namespace mozilla::services;
 using namespace mozilla::widget;
@@ -316,17 +317,37 @@ TabParent::RemoveTabParentFromTable(uint
     delete sLayerToTabParentTable;
     sLayerToTabParentTable = nullptr;
   }
 }
 
 void
 TabParent::SetOwnerElement(Element* aElement)
 {
+  // If we held previous content then unregister for its events.
+  if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
+    nsCOMPtr<nsPIDOMWindow> window = mFrameElement->OwnerDoc()->GetWindow();
+    nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
+    if (eventTarget) {
+      eventTarget->RemoveEventListener(NS_LITERAL_STRING("MozUpdateWindowPos"),
+                                       this, false);
+    }
+  }
+
+  // Update to the new content, and register to listen for events from it.
   mFrameElement = aElement;
+  if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
+    nsCOMPtr<nsPIDOMWindow> window = mFrameElement->OwnerDoc()->GetWindow();
+    nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
+    if (eventTarget) {
+      eventTarget->AddEventListener(NS_LITERAL_STRING("MozUpdateWindowPos"),
+                                    this, false, false);
+    }
+  }
+
   TryCacheDPIAndScale();
 }
 
 void
 TabParent::GetAppType(nsAString& aOut)
 {
   aOut.Truncate();
   nsCOMPtr<Element> elem = do_QueryInterface(mFrameElement);
@@ -352,16 +373,18 @@ TabParent::IsVisible()
 
 void
 TabParent::Destroy()
 {
   if (mIsDestroyed) {
     return;
   }
 
+  SetOwnerElement(nullptr);
+
   // If this fails, it's most likely due to a content-process crash,
   // and auto-cleanup will kick in.  Otherwise, the child side will
   // destroy itself and send back __delete__().
   unused << SendDestroy();
 
   if (RenderFrameParent* frame = GetRenderFrame()) {
     RemoveTabParentFromTable(frame->GetLayersId());
     frame->Destroy();
@@ -876,35 +899,76 @@ TabParent::RecvSetDimensions(const uint3
     treeOwnerAsWin->SetSize(aCx, aCy, true);
     return true;
   }
 
   MOZ_ASSERT(false, "Unknown flags!");
   return false;
 }
 
+static nsIntPoint
+GetChromeDisplacement(nsFrameLoader *aFrameLoader)
+{
+  if (!aFrameLoader) {
+    return nsIntPoint();
+  }
+
+  // Calculate the displacement from the primary frame of the tab
+  // content to the top-level frame of the widget we are in.
+  nsIFrame* contentFrame = aFrameLoader->GetPrimaryFrameOfOwningContent();
+  if (!contentFrame) {
+    return nsIntPoint();
+  }
+
+  nsIFrame* nextFrame = nsLayoutUtils::GetCrossDocParentFrame(contentFrame);
+  if (!nextFrame) {
+    NS_WARNING("Couldn't find window chrome to calculate displacement to.");
+    return nsIntPoint();
+  }
+
+  nsIFrame* rootFrame = nextFrame;
+  while (nextFrame) {
+    rootFrame = nextFrame;
+    nextFrame = nsLayoutUtils::GetCrossDocParentFrame(rootFrame);
+  }
+
+  nsPoint offset = contentFrame->GetOffsetToCrossDoc(rootFrame);
+  int32_t appUnitsPerDevPixel = rootFrame->PresContext()->AppUnitsPerDevPixel();
+  return nsIntPoint((int)(offset.x/appUnitsPerDevPixel),
+                    (int)(offset.y/appUnitsPerDevPixel));
+}
+
 void
-TabParent::UpdateDimensions(const nsIntRect& rect, const nsIntSize& size,
-                            const nsIntPoint& aChromeDisp)
+TabParent::UpdateDimensions(const nsIntRect& rect, const nsIntSize& size)
 {
   if (mIsDestroyed) {
     return;
   }
   hal::ScreenConfiguration config;
   hal::GetCurrentScreenConfiguration(&config);
   ScreenOrientation orientation = config.orientation();
 
   if (!mUpdatedDimensions || mOrientation != orientation ||
       mDimensions != size || !mRect.IsEqualEdges(rect)) {
+    nsCOMPtr<nsIWidget> widget = GetWidget();
+    nsIntRect contentRect = rect;
+    if (widget) {
+      contentRect.x += widget->GetClientOffset().x;
+      contentRect.y += widget->GetClientOffset().y;
+    }
+
     mUpdatedDimensions = true;
-    mRect = rect;
+    mRect = contentRect;
     mDimensions = size;
     mOrientation = orientation;
 
-    unused << SendUpdateDimensions(mRect, mDimensions, mOrientation, aChromeDisp);
+    nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+    nsIntPoint chromeOffset = GetChromeDisplacement(frameLoader);
+
+    unused << SendUpdateDimensions(mRect, mDimensions, mOrientation, chromeOffset);
   }
 }
 
 void
 TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics)
 {
   if (!mIsDestroyed) {
     unused << SendUpdateFrame(aFrameMetrics);
@@ -2649,16 +2713,37 @@ TabParent::AllocPPluginWidgetParent()
 
 bool
 TabParent::DeallocPPluginWidgetParent(mozilla::plugins::PPluginWidgetParent* aActor)
 {
   delete aActor;
   return true;
 }
 
+nsresult
+TabParent::HandleEvent(nsIDOMEvent* aEvent)
+{
+  nsAutoString eventType;
+  aEvent->GetType(eventType);
+
+  if (eventType.EqualsLiteral("MozUpdateWindowPos")) {
+    // This event is sent when the widget moved.  Therefore we only update
+    // the position.
+    nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+    if (!frameLoader) {
+      return NS_OK;
+    }
+    nsIntRect windowDims;
+    NS_ENSURE_SUCCESS(frameLoader->GetWindowDimensions(windowDims), NS_ERROR_FAILURE);
+    UpdateDimensions(windowDims, mDimensions);
+    return NS_OK;
+  }
+  return NS_OK;
+}
+
 class FakeChannel MOZ_FINAL : public nsIChannel,
                               public nsIAuthPromptCallback,
                               public nsIInterfaceRequestor,
                               public nsILoadContext
 {
 public:
   FakeChannel(const nsCString& aUri, uint64_t aCallbackId, Element* aElement)
     : mCallbackId(aCallbackId)
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -17,16 +17,17 @@
 #include "nsIBrowserDOMWindow.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsWeakReference.h"
 #include "Units.h"
 #include "WritingModes.h"
 #include "js/TypeDecls.h"
+#include "nsIDOMEventListener.h"
 
 class nsFrameLoader;
 class nsIFrameLoader;
 class nsIContent;
 class nsIPrincipal;
 class nsIURI;
 class nsIWidget;
 class nsILoadContext;
@@ -53,17 +54,18 @@ struct IMENotification;
 
 namespace dom {
 
 class ClonedMessageData;
 class nsIContentParent;
 class Element;
 struct StructuredCloneData;
 
-class TabParent : public PBrowserParent 
+class TabParent : public PBrowserParent
+                , public nsIDOMEventListener
                 , public nsITabParent 
                 , public nsIAuthPromptProvider
                 , public nsISecureBrowserUI
                 , public nsSupportsWeakReference
                 , public TabContext
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
 
@@ -93,16 +95,19 @@ public:
      */
     bool IsVisible();
 
     nsIBrowserDOMWindow *GetBrowserDOMWindow() { return mBrowserDOMWindow; }
     void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserDOMWindow) {
         mBrowserDOMWindow = aBrowserDOMWindow;
     }
 
+    // nsIDOMEventListener interfaces 
+    NS_DECL_NSIDOMEVENTLISTENER
+
     already_AddRefed<nsILoadContext> GetLoadContext();
 
     nsIXULBrowserWindow* GetXULBrowserWindow();
 
     /**
      * Return the TabParent that has decided it wants to capture an
      * event series for fast-path dispatch to its subprocess, if one
      * has.
@@ -236,18 +241,17 @@ public:
     AllocPColorPickerParent(const nsString& aTitle, const nsString& aInitialColor) MOZ_OVERRIDE;
     virtual bool DeallocPColorPickerParent(PColorPickerParent* aColorPicker) MOZ_OVERRIDE;
 
     void LoadURL(nsIURI* aURI);
     // XXX/cjones: it's not clear what we gain by hiding these
     // message-sending functions under a layer of indirection and
     // eating the return values
     void Show(const nsIntSize& size, bool aParentIsActive);
-    void UpdateDimensions(const nsIntRect& rect, const nsIntSize& size,
-                          const nsIntPoint& chromeDisp);
+    void UpdateDimensions(const nsIntRect& rect, const nsIntSize& size);
     void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
     void UIResolutionChanged();
     void AcknowledgeScrollUpdate(const ViewID& aScrollId, const uint32_t& aScrollGeneration);
     void HandleDoubleTap(const CSSPoint& aPoint,
                          int32_t aModifiers,
                          const ScrollableLayerGuid& aGuid);
     void HandleSingleTap(const CSSPoint& aPoint,
                          int32_t aModifiers,
--- a/dom/ipc/jar.mn
+++ b/dom/ipc/jar.mn
@@ -3,10 +3,11 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit.jar:
         content/global/test-ipc.xul (test.xul)
         content/global/remote-test-ipc.js (remote-test.js)
         content/global/BrowserElementChild.js (../browser-element/BrowserElementChild.js)
         content/global/BrowserElementChildPreload.js (../browser-element/BrowserElementChildPreload.js)
 *       content/global/BrowserElementPanning.js (../browser-element/BrowserElementPanning.js)
+*       content/global/BrowserElementPanningAPZDisabled.js (../browser-element/BrowserElementPanningAPZDisabled.js)
         content/global/preload.js (preload.js)
         content/global/post-fork-preload.js (post-fork-preload.js)
--- a/dom/ipc/preload.js
+++ b/dom/ipc/preload.js
@@ -86,16 +86,23 @@ const BrowserElementIsPreloaded = true;
 
   try {
     if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
       Services.scriptloader.loadSubScript("chrome://global/content/forms.js", global);
     }
   } catch (e) {
   }
 
+  try {
+    if (Services.prefs.getBoolPref("layers.async-pan-zoom.enabled") === false) {
+      Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanningAPZDisabled.js", global);
+    }
+  } catch (e) {
+  }
+
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js", global);
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js", global);
 
   Services.io.getProtocolHandler("app");
   Services.io.getProtocolHandler("default");
 
   docShell.isActive = false;
   docShell.createAboutBlankContentViewer(null);
--- a/dom/locales/en-US/chrome/accessibility/mac/accessible.properties
+++ b/dom/locales/en-US/chrome/accessibility/mac/accessible.properties
@@ -20,15 +20,17 @@ cycle   =       Cycle
 # (Mac Only)
 # The Role Description for AXWebArea (the web widget). Like in Safari.
 htmlContent = HTML Content
 # The Role Description for the Tab button.
 tab     =       tab
 # The Role Description for definition list dl, dt and dd
 term    =       term
 definition =    definition
+# The Role Description for an input type="search" text field
+searchTextField = search text field
 # The Role Description for WAI-ARIA Landmarks
 search  =       search
 banner  =       banner
 navigation =    navigation
 complementary = complementary
 content =       content
 main    =       main
--- a/dom/media/AudioSink.cpp
+++ b/dom/media/AudioSink.cpp
@@ -80,16 +80,25 @@ AudioSink::GetPosition()
       (pos = mAudioStream->GetPosition()) >= 0) {
     // Update the last good position when we got a good one.
     mLastGoodPosition = pos;
   }
 
   return mLastGoodPosition;
 }
 
+bool
+AudioSink::HasUnplayedFrames()
+{
+  AssertCurrentThreadInMonitor();
+  // Experimentation suggests that GetPositionInFrames() is zero-indexed,
+  // so we need to add 1 here before comparing it to mWritten.
+  return mAudioStream && mAudioStream->GetPositionInFrames() + 1 < mWritten;
+}
+
 void
 AudioSink::PrepareToShutdown()
 {
   AssertCurrentThreadInMonitor();
   mStopAudioThread = true;
   if (mAudioStream) {
     mAudioStream->Cancel();
   }
--- a/dom/media/AudioSink.h
+++ b/dom/media/AudioSink.h
@@ -22,16 +22,20 @@ public:
 
   AudioSink(MediaDecoderStateMachine* aStateMachine,
             int64_t aStartTime, AudioInfo aInfo, dom::AudioChannel aChannel);
 
   nsresult Init();
 
   int64_t GetPosition();
 
+  // Check whether we've pushed more frames to the audio hardware than it has
+  // played.
+  bool HasUnplayedFrames();
+
   // Tell the AudioSink to stop processing and initiate shutdown.  Must be
   // called with the decoder monitor held.
   void PrepareToShutdown();
 
   // Shut down the AudioSink's resources.  The decoder monitor must not be
   // held during this call, as it may block processing thread event queues.
   void Shutdown();
 
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -650,16 +650,19 @@ DecoderTraits::CreateDecoder(const nsACS
   return decoder.forget();
 }
 
 /* static */
 MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, AbstractMediaDecoder* aDecoder)
 {
   MediaDecoderReader* decoderReader = nullptr;
 
+  if (!aDecoder) {
+    return decoderReader;
+  }
 #ifdef MOZ_FMP4
   if (IsMP4SupportedType(aType)) {
     decoderReader = new MP4Reader(aDecoder);
   } else
 #endif
 #ifdef MOZ_GSTREAMER
   if (IsGStreamerSupportedType(aType)) {
     decoderReader = new GStreamerReader(aDecoder);
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -1168,18 +1168,20 @@ MediaCache::Update()
 
     int32_t resumeThreshold = Preferences::GetInt("media.cache_resume_threshold", 10);
     int32_t readaheadLimit = Preferences::GetInt("media.cache_readahead_limit", 30);
 
     for (uint32_t i = 0; i < mStreams.Length(); ++i) {
       actions.AppendElement(NONE);
 
       MediaCacheStream* stream = mStreams[i];
-      if (stream->mClosed)
+      if (stream->mClosed) {
+        CACHE_LOG(PR_LOG_DEBUG, ("Stream %p closed", stream));
         continue;
+      }
 
       // Figure out where we should be reading from. It's the first
       // uncached byte after the current mStreamOffset.
       int64_t dataOffset = stream->GetCachedDataEndInternal(stream->mStreamOffset);
       MOZ_ASSERT(dataOffset >= 0);
 
       // Compute where we'd actually seek to to read at readOffset
       int64_t desiredOffset = dataOffset;
@@ -1275,17 +1277,17 @@ MediaCache::Update()
           enableReading = predictedNewDataUse < latestNextUse;
         }
       }
 
       if (enableReading) {
         for (uint32_t j = 0; j < i; ++j) {
           MediaCacheStream* other = mStreams[j];
           if (other->mResourceID == stream->mResourceID &&
-              !other->mClient->IsSuspended() &&
+              !other->mClosed && !other->mClient->IsSuspended() &&
               other->mChannelOffset/BLOCK_SIZE == desiredOffset/BLOCK_SIZE) {
             // This block is already going to be read by the other stream.
             // So don't try to read it from this stream as well.
             enableReading = false;
             CACHE_LOG(PR_LOG_DEBUG, ("Stream %p waiting on same block (%lld) from stream %p",
                                      stream, desiredOffset/BLOCK_SIZE, other));
             break;
           }
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1433,25 +1433,23 @@ void MediaDecoder::SetMediaSeekable(bool
   MOZ_ASSERT(NS_IsMainThread() || OnDecodeThread());
   mMediaSeekable = aMediaSeekable;
 }
 
 bool
 MediaDecoder::IsTransportSeekable()
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-  MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread());
   return GetResource()->IsTransportSeekable();
 }
 
 bool MediaDecoder::IsMediaSeekable()
 {
   NS_ENSURE_TRUE(GetStateMachine(), false);
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-  MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread());
   return mMediaSeekable;
 }
 
 nsresult MediaDecoder::GetSeekable(dom::TimeRanges* aSeekable)
 {
   double initialTime = 0.0;
 
   // We can seek in buffered range if the media is seekable. Also, we can seek
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -305,32 +305,30 @@ bool MediaDecoderStateMachine::HasFuture
 
 bool MediaDecoderStateMachine::HaveNextFrameData() {
   AssertCurrentThreadInMonitor();
   return (!HasAudio() || HasFutureAudio()) &&
          (!HasVideo() || VideoQueue().GetSize() > 0);
 }
 
 int64_t MediaDecoderStateMachine::GetDecodedAudioDuration() {
-  NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
-               "Should be on decode thread or state machine thread");
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
   int64_t audioDecoded = AudioQueue().Duration();
   if (mAudioEndTime != -1) {
     audioDecoded += mAudioEndTime - GetMediaTime();
   }
   return audioDecoded;
 }
 
 void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
                                                DecodedStreamData* aStream,
                                                AudioSegment* aOutput)
 {
-  NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
-               "Should be on decode thread or state machine thread");
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
 
   // This logic has to mimic AudioSink closely to make sure we write
   // the exact same silences
   CheckedInt64 audioWrittenOffset = aStream->mAudioFramesWritten +
       UsecsToFrames(mInfo.mAudio.mRate, aStream->mInitialTime + mStartTime);
   CheckedInt64 frameOffset = UsecsToFrames(mInfo.mAudio.mRate, aAudio->mTime);
 
@@ -697,16 +695,17 @@ MediaDecoderStateMachine::IsVideoSeekCom
     (mCurrentSeekTarget.IsValid() &&
      !mDropVideoUntilNextDiscontinuity &&
      (VideoQueue().IsFinished() || VideoQueue().GetSize() > 0));
 }
 
 void
 MediaDecoderStateMachine::OnAudioDecoded(AudioData* aAudioSample)
 {
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   nsRefPtr<AudioData> audio(aAudioSample);
   MOZ_ASSERT(audio);
   mAudioDataRequest.Complete();
   mDecodedAudioEndTime = audio->GetEndTime();
 
   SAMPLE_LOG("OnAudioDecoded [%lld,%lld] disc=%d",
              (audio ? audio->mTime : -1),
@@ -817,17 +816,17 @@ MediaDecoderStateMachine::Push(VideoData
     mDecoder->GetReentrantMonitor().NotifyAll();
   }
 }
 
 void
 MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
                                        MediaDecoderReader::NotDecodedReason aReason)
 {
-  MOZ_ASSERT(OnDecodeThread());
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   SAMPLE_LOG("OnNotDecoded (aType=%u, aReason=%u)", aType, aReason);
   bool isAudio = aType == MediaData::AUDIO_DATA;
   MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA);
 
   if (isAudio) {
     mAudioDataRequest.Complete();
   } else {
@@ -840,20 +839,21 @@ MediaDecoderStateMachine::OnNotDecoded(M
     return;
   }
 
   // If the decoder is waiting for data, we tell it to call us back when the
   // data arrives.
   if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
     MOZ_ASSERT(mReader->IsWaitForDataSupported(),
                "Readers that send WAITING_FOR_DATA need to implement WaitForData");
-    WaitRequestRef(aType).Begin(mReader->WaitForData(aType)
-                                ->RefableThen(DecodeTaskQueue(), __func__, this,
-                                               &MediaDecoderStateMachine::OnWaitForDataResolved,
-                                               &MediaDecoderStateMachine::OnWaitForDataRejected));
+    WaitRequestRef(aType).Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
+                                               &MediaDecoderReader::WaitForData, aType)
+      ->RefableThen(mScheduler.get(), __func__, this,
+                    &MediaDecoderStateMachine::OnWaitForDataResolved,
+                    &MediaDecoderStateMachine::OnWaitForDataRejected));
     return;
   }
 
   if (aReason == MediaDecoderReader::CANCELED) {
     DispatchDecodeTasksIfNeeded();
     return;
   }
 
@@ -921,30 +921,31 @@ MediaDecoderStateMachine::AcquireMonitor
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   DecodeError();
 }
 
 void
 MediaDecoderStateMachine::MaybeFinishDecodeFirstFrame()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
   if ((IsAudioDecoding() && AudioQueue().GetSize() == 0) ||
       (IsVideoDecoding() && VideoQueue().GetSize() == 0)) {
     return;
   }
   if (NS_FAILED(FinishDecodeFirstFrame())) {
     DecodeError();
   }
 }
 
 void
 MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
 {
-  MOZ_ASSERT(OnDecodeThread());
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   nsRefPtr<VideoData> video(aVideoSample);
   mVideoDataRequest.Complete();
   mDecodedVideoEndTime = video ? video->GetEndTime() : mDecodedVideoEndTime;
 
   SAMPLE_LOG("OnVideoDecoded [%lld,%lld] disc=%d",
              (video ? video->mTime : -1),
              (video ? video->GetEndTime() : -1),
@@ -1041,16 +1042,17 @@ MediaDecoderStateMachine::OnVideoDecoded
       return;
     }
   }
 }
 
 void
 MediaDecoderStateMachine::CheckIfSeekComplete()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
 
   const bool videoSeekComplete = IsVideoSeekComplete();
   if (HasVideo() && !videoSeekComplete) {
     // We haven't reached the target. Ensure we have requested another sample.
     if (NS_FAILED(EnsureVideoDecodeTaskQueued())) {
       DECODER_WARN("Failed to request video during seek");
       DecodeError();
@@ -1068,17 +1070,17 @@ MediaDecoderStateMachine::CheckIfSeekCom
 
   SAMPLE_LOG("CheckIfSeekComplete() audioSeekComplete=%d videoSeekComplete=%d",
              audioSeekComplete, videoSeekComplete);
 
   if (audioSeekComplete && videoSeekComplete) {
     mDecodeToSeekTarget = false;
     RefPtr<nsIRunnable> task(
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
-    nsresult rv = DecodeTaskQueue()->Dispatch(task);
+    nsresult rv = GetStateMachineThread()->Dispatch(task, NS_DISPATCH_NORMAL);
     if (NS_FAILED(rv)) {
       DecodeError();
     }
   }
 }
 
 bool
 MediaDecoderStateMachine::IsAudioDecoding()
@@ -1141,33 +1143,39 @@ nsresult MediaDecoderStateMachine::Init(
   rv = mReader->Init(cloneReader);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 void MediaDecoderStateMachine::StopPlayback()
 {
+  // XXXbholley - Needed because DecodeSeek runs on the decode thread.
+  // Once bug 1135170 lands, this becomes state-machine only, and we can invoke
+  // DispatchDecodeTasksIfNeeded directly.
+  MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread());
   DECODER_LOG("StopPlayback()");
 
   AssertCurrentThreadInMonitor();
 
   mDecoder->NotifyPlaybackStopped();
 
   if (IsPlaying()) {
     mPlayDuration = GetClock() - mStartTime;
     SetPlayStartTime(TimeStamp());
   }
   // Notify the audio sink, so that it notices that we've stopped playing,
   // so it can pause audio playback.
   mDecoder->GetReentrantMonitor().NotifyAll();
   NS_ASSERTION(!IsPlaying(), "Should report not playing at end of StopPlayback()");
   mDecoder->UpdateStreamBlockingForStateMachinePlaying();
 
-  DispatchDecodeTasksIfNeeded();
+  nsCOMPtr<nsIRunnable> event =
+    NS_NewRunnableMethod(this, &MediaDecoderStateMachine::AcquireMonitorAndInvokeDispatchDecodeTasksIfNeeded);
+  GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL);
 }
 
 void MediaDecoderStateMachine::SetSyncPointForMediaStream()
 {
   AssertCurrentThreadInMonitor();
 
   DecodedStreamData* stream = mDecoder->GetDecodedStream();
   if (!stream) {
@@ -1237,19 +1245,20 @@ void MediaDecoderStateMachine::MaybeStar
 
   mDecoder->GetReentrantMonitor().NotifyAll();
   mDecoder->UpdateStreamBlockingForStateMachinePlaying();
   DispatchDecodeTasksIfNeeded();
 }
 
 void MediaDecoderStateMachine::UpdatePlaybackPositionInternal(int64_t aTime)
 {
+  // XXXbholley - Needed because DecodeSeek runs on the decode thread.
+  // Once bug 1135170 lands, this becomes state-machine only.
+  MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread());
   SAMPLE_LOG("UpdatePlaybackPositionInternal(%lld) (mStartTime=%lld)", aTime, mStartTime);
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine thread.");
   AssertCurrentThreadInMonitor();
 
   NS_ASSERTION(mStartTime >= 0, "Should have positive mStartTime");
   mCurrentFrameTime = aTime - mStartTime;
   NS_ASSERTION(mCurrentFrameTime >= 0, "CurrentTime should be positive!");
   if (aTime > mEndTime) {
     NS_ASSERTION(mCurrentFrameTime > GetDuration(),
                  "CurrentTime must be after duration if aTime > endTime!");
@@ -1504,17 +1513,16 @@ void MediaDecoderStateMachine::SetDorman
       } else if (mCurrentSeekTarget.IsValid()) {
         mQueuedSeekTarget = mCurrentSeekTarget;
       }
     }
     mSeekTarget.Reset();
     mCurrentSeekTarget.Reset();
     ScheduleStateMachine();
     SetState(DECODER_STATE_DORMANT);
-    StopPlayback();
     mDecoder->GetReentrantMonitor().NotifyAll();
   } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
     mDecodingFrozenAtStateDecoding = true;
     ScheduleStateMachine();
     mCurrentFrameTime = 0;
     SetState(DECODER_STATE_DECODING_NONE);
     mDecoder->GetReentrantMonitor().NotifyAll();
   }
@@ -1535,18 +1543,17 @@ void MediaDecoderStateMachine::Shutdown(
   if (mAudioSink) {
     mAudioSink->PrepareToShutdown();
   }
   mDecoder->GetReentrantMonitor().NotifyAll();
 }
 
 void MediaDecoderStateMachine::StartDecoding()
 {
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   if (mState == DECODER_STATE_DECODING) {
     return;
   }
   SetState(DECODER_STATE_DECODING);
 
   mDecodeStartTime = TimeStamp::Now();
 
@@ -1637,16 +1644,20 @@ void MediaDecoderStateMachine::PlayInter
     DispatchDecodeTasksIfNeeded();
   }
 
   ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::ResetPlayback()
 {
+  // XXXbholley - Needed because DecodeSeek runs on the decode thread.
+  // Once bug 1135170 lands, this becomes state-machine only.
+  MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread());
+
   // We should be reseting because we're seeking, shutting down, or
   // entering dormant state. We could also be in the process of going dormant,
   // and have just switched to exiting dormant before we finished entering
   // dormant, hence the DECODING_NONE case below.
   AssertCurrentThreadInMonitor();
   MOZ_ASSERT(mState == DECODER_STATE_SEEKING ||
              mState == DECODER_STATE_SHUTDOWN ||
              mState == DECODER_STATE_DORMANT ||
@@ -1779,18 +1790,19 @@ MediaDecoderStateMachine::StartSeek(cons
   if (mAudioCaptured) {
     mDecoder->RecreateDecodedStream(seekTime - mStartTime);
   }
   ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::StopAudioThread()
 {
-  NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
-               "Should be on decode thread or state machine thread");
+  // XXXbholley - Needed because DecodeSeek runs on the decode thread.
+  // Once bug 1135170 lands, this becomes state-machine only.
+  MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread());
   AssertCurrentThreadInMonitor();
 
   if (mStopAudioThread) {
     // Audio sink is being stopped in another thread. Wait until finished.
     while (mAudioSink) {
       mDecoder->GetReentrantMonitor().Wait();
     }
     return;
@@ -1828,37 +1840,38 @@ MediaDecoderStateMachine::EnqueueDecodeM
 nsresult
 MediaDecoderStateMachine::EnqueueDecodeFirstFrameTask()
 {
   AssertCurrentThreadInMonitor();
   MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME);
 
   RefPtr<nsIRunnable> task(
     NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeFirstFrame));
-  nsresult rv = DecodeTaskQueue()->Dispatch(task);
+  nsresult rv = GetStateMachineThread()->Dispatch(task, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 void
 MediaDecoderStateMachine::SetReaderIdle()
 {
-#ifdef PR_LOGGING
-  {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    DECODER_LOG("SetReaderIdle() audioQueue=%lld videoQueue=%lld",
-                GetDecodedAudioDuration(),
-                VideoQueue().Duration());
-  }
-#endif
   MOZ_ASSERT(OnDecodeThread());
+  DECODER_LOG("Invoking SetReaderIdle()");
   mReader->SetIdle();
 }
 
 void
+MediaDecoderStateMachine::AcquireMonitorAndInvokeDispatchDecodeTasksIfNeeded()
+{
+  MOZ_ASSERT(OnStateMachineThread());
+  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+  DispatchDecodeTasksIfNeeded();
+}
+
+void
 MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
 {
   AssertCurrentThreadInMonitor();
 
   if (mState != DECODER_STATE_DECODING &&
       mState != DECODER_STATE_DECODING_FIRSTFRAME &&
       mState != DECODER_STATE_BUFFERING &&
       mState != DECODER_STATE_SEEKING) {
@@ -1904,63 +1917,63 @@ MediaDecoderStateMachine::DispatchDecode
   if (needToDecodeAudio) {
     EnsureAudioDecodeTaskQueued();
   }
   if (needToDecodeVideo) {
     EnsureVideoDecodeTaskQueued();
   }
 
   if (needIdle) {
+    DECODER_LOG("Dispatching SetReaderIdle() audioQueue=%lld videoQueue=%lld",
+                GetDecodedAudioDuration(),
+                VideoQueue().Duration());
     RefPtr<nsIRunnable> event = NS_NewRunnableMethod(
         this, &MediaDecoderStateMachine::SetReaderIdle);
     nsresult rv = DecodeTaskQueue()->Dispatch(event.forget());
     if (NS_FAILED(rv) && mState != DECODER_STATE_SHUTDOWN) {
       DECODER_WARN("Failed to dispatch event to set decoder idle state");
     }
   }
 }
 
 nsresult
 MediaDecoderStateMachine::EnqueueDecodeSeekTask()
 {
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
 
   RefPtr<nsIRunnable> task(
     NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeSeek));
   nsresult rv = DecodeTaskQueue()->Dispatch(task);
   if (NS_FAILED(rv)) {
     DECODER_WARN("Dispatch DecodeSeek task failed.");
     DecodeError();
   }
 
   return rv;
 }
 
 nsresult
 MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
 
   if (NeedToDecodeAudio()) {
     return EnsureAudioDecodeTaskQueued();
   }
 
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
 
   SAMPLE_LOG("EnsureAudioDecodeTaskQueued isDecoding=%d status=%s",
               IsAudioDecoding(), AudioRequestStatus());
 
   if (mState != DECODER_STATE_DECODING &&
       mState != DECODER_STATE_DECODING_FIRSTFRAME &&
       mState != DECODER_STATE_BUFFERING &&
       mState != DECODER_STATE_SEEKING) {
@@ -1972,48 +1985,45 @@ MediaDecoderStateMachine::EnsureAudioDec
     return NS_OK;
   }
 
   SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
              AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
 
   mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
                                          __func__, &MediaDecoderReader::RequestAudioData)
-    ->RefableThen(DecodeTaskQueue(), __func__, this,
+    ->RefableThen(mScheduler.get(), __func__, this,
                   &MediaDecoderStateMachine::OnAudioDecoded,
                   &MediaDecoderStateMachine::OnAudioNotDecoded));
 
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
 
   if (NeedToDecodeVideo()) {
     return EnsureVideoDecodeTaskQueued();
   }
 
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
 
   SAMPLE_LOG("EnsureVideoDecodeTaskQueued isDecoding=%d status=%s",
              IsVideoDecoding(), VideoRequestStatus());
 
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
-
   if (mState != DECODER_STATE_DECODING &&
       mState != DECODER_STATE_DECODING_FIRSTFRAME &&
       mState != DECODER_STATE_BUFFERING &&
       mState != DECODER_STATE_SEEKING) {
     return NS_OK;
   }
 
   if (!IsVideoDecoding() || mVideoDataRequest.Exists() ||
@@ -2031,27 +2041,26 @@ MediaDecoderStateMachine::EnsureVideoDec
 
   SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
              VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
              currentTime);
 
   mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
                                          &MediaDecoderReader::RequestVideoData,
                                          skipToNextKeyFrame, currentTime)
-    ->RefableThen(DecodeTaskQueue(), __func__, this,
+    ->RefableThen(mScheduler.get(), __func__, this,
                   &MediaDecoderStateMachine::OnVideoDecoded,
                   &MediaDecoderStateMachine::OnVideoNotDecoded));
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::StartAudioThread()
 {
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
   if (mAudioCaptured) {
     NS_ASSERTION(mStopAudioThread, "mStopAudioThread must always be true if audio is captured");
     return NS_OK;
   }
 
   mStopAudioThread = false;
   if (HasAudio() && !mAudioSink) {
@@ -2098,16 +2107,23 @@ bool MediaDecoderStateMachine::HasLowDec
   // provided we've not decoded to the end of the audio stream, or
   // if we're low on video frames, provided
   // we've not decoded to the end of the video stream.
   return ((IsAudioDecoding() && AudioDecodedUsecs() < aAudioUsecs) ||
          (IsVideoDecoding() &&
           static_cast<uint32_t>(VideoQueue().GetSize()) < LOW_VIDEO_FRAMES));
 }
 
+bool MediaDecoderStateMachine::OutOfDecodedAudio()
+{
+    return IsAudioDecoding() && !AudioQueue().IsFinished() &&
+           AudioQueue().GetSize() == 0 &&
+           (!mAudioSink || !mAudioSink->HasUnplayedFrames());
+}
+
 bool MediaDecoderStateMachine::HasLowUndecodedData()
 {
   return HasLowUndecodedData(mLowDataThresholdUsecs);
 }
 
 bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs)
 {
   AssertCurrentThreadInMonitor();
@@ -2142,23 +2158,34 @@ bool MediaDecoderStateMachine::HasLowUnd
          !buffered->Contains(static_cast<double>(endOfDecodedData) / USECS_PER_S,
                              static_cast<double>(std::min(endOfDecodedData + aUsecs, GetDuration())) / USECS_PER_S);
 }
 
 void
 MediaDecoderStateMachine::DecodeError()
 {
   AssertCurrentThreadInMonitor();
-  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
-
   if (mState == DECODER_STATE_SHUTDOWN) {
     // Already shutdown.
     return;
   }
 
+  // DecodeError should probably be redesigned so that it doesn't need to run
+  // on the Decode Task Queue, but this does the trick for now.
+  if (!OnDecodeThread()) {
+    RefPtr<nsIRunnable> task(
+      NS_NewRunnableMethod(this, &MediaDecoderStateMachine::AcquireMonitorAndInvokeDecodeError));
+    nsresult rv = DecodeTaskQueue()->Dispatch(task);
+
+    if (NS_FAILED(rv)) {
+      DECODER_WARN("Failed to dispatch AcquireMonitorAndInvokeDecodeError");
+    }
+    return;
+  }
+
   // Change state to shutdown before sending error report to MediaDecoder
   // and the HTMLMediaElement, so that our pipeline can start exiting
   // cleanly during the sync dispatch below.
   DECODER_WARN("Decode error, changed state to SHUTDOWN due to error");
   SetState(DECODER_STATE_SHUTDOWN);
   mScheduler->ScheduleAndShutdown();
   mDecoder->GetReentrantMonitor().NotifyAll();
 
@@ -2282,84 +2309,83 @@ MediaDecoderStateMachine::EnqueueFirstFr
     new FirstFrameLoadedEventRunner(mDecoder, info, mSentFirstFrameLoadedEvent);
   NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   mSentFirstFrameLoadedEvent = true;
 }
 
 void
 MediaDecoderStateMachine::CallDecodeFirstFrame()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   if (mState != DECODER_STATE_DECODING_FIRSTFRAME) {
     return;
   }
   if (NS_FAILED(DecodeFirstFrame())) {
     DECODER_WARN("Decode failed to start, shutting down decoder");
     DecodeError();
   }
 }
 
 nsresult
 MediaDecoderStateMachine::DecodeFirstFrame()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
-  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME);
   DECODER_LOG("DecodeFirstFrame started");
 
   if (HasAudio()) {
     RefPtr<nsIRunnable> decodeTask(
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded));
-    AudioQueue().AddPopListener(decodeTask, DecodeTaskQueue());
+    AudioQueue().AddPopListener(decodeTask, GetStateMachineThread());
   }
   if (HasVideo()) {
     RefPtr<nsIRunnable> decodeTask(
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded));
-    VideoQueue().AddPopListener(decodeTask, DecodeTaskQueue());
+    VideoQueue().AddPopListener(decodeTask, GetStateMachineThread());
   }
 
   if (IsRealTime()) {
     SetStartTime(0);
     nsresult res = FinishDecodeFirstFrame();
     NS_ENSURE_SUCCESS(res, res);
   } else if (mSentFirstFrameLoadedEvent) {
     // We're resuming from dormant state, so we don't need to request
     // the first samples in order to determine the media start time,
     // we have the start time from last time we loaded.
     SetStartTime(mStartTime);
     nsresult res = FinishDecodeFirstFrame();
     NS_ENSURE_SUCCESS(res, res);
   } else {
-    // NB: We're already on the decode thread, but we proxy these anyway so that
-    // we don't need to worry about dropping locks.
     if (HasAudio()) {
       mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
                                              __func__, &MediaDecoderReader::RequestAudioData)
-        ->RefableThen(DecodeTaskQueue(), __func__, this,
+        ->RefableThen(mScheduler.get(), __func__, this,
                       &MediaDecoderStateMachine::OnAudioDecoded,
                       &MediaDecoderStateMachine::OnAudioNotDecoded));
     }
     if (HasVideo()) {
       mVideoDecodeStartTime = TimeStamp::Now();
       mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
                                              __func__, &MediaDecoderReader::RequestVideoData, false, int64_t(0))
-        ->RefableThen(DecodeTaskQueue(), __func__, this,
+        ->RefableThen(mScheduler.get(), __func__, this,
                       &MediaDecoderStateMachine::OnVideoDecoded,
                       &MediaDecoderStateMachine::OnVideoNotDecoded));
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::FinishDecodeFirstFrame()
 {
   AssertCurrentThreadInMonitor();
-  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   DECODER_LOG("FinishDecodeFirstFrame");
 
   if (mState == DECODER_STATE_SHUTDOWN) {
     return NS_ERROR_FAILURE;
   }
 
   if (!IsRealTime() && !mSentFirstFrameLoadedEvent) {
     const VideoData* v = VideoQueue().PeekFront();
@@ -2494,18 +2520,18 @@ void MediaDecoderStateMachine::DecodeSee
   }
 
   mDecodeToSeekTarget = false;
 
   if (!currentTimeChanged) {
     DECODER_LOG("Seek !currentTimeChanged...");
     mDropAudioUntilNextDiscontinuity = false;
     mDropVideoUntilNextDiscontinuity = false;
-    nsresult rv = DecodeTaskQueue()->Dispatch(
-      NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
+    nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted);
+    nsresult rv = GetStateMachineThread()->Dispatch(task, NS_DISPATCH_NORMAL);
     if (NS_FAILED(rv)) {
       DecodeError();
     }
   } else {
     // The seek target is different than the current playback position,
     // we'll need to seek the playback position, so shutdown our decode
     // thread and audio sink.
     StopAudioThread();
@@ -2537,17 +2563,21 @@ MediaDecoderStateMachine::OnSeekComplete
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mWaitingForDecoderSeek = false;
   mCancelingSeek = false;
 
   // We must decode the first samples of active streams, so we can determine
   // the new stream time. So dispatch tasks to do that.
   mDecodeToSeekTarget = true;
-  DispatchDecodeTasksIfNeeded();
+
+  // XXXbholley - This can become a direct call once bug 1135170 lands.
+  nsCOMPtr<nsIRunnable> event =
+    NS_NewRunnableMethod(this, &MediaDecoderStateMachine::AcquireMonitorAndInvokeDispatchDecodeTasksIfNeeded);
+  GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL);
 }
 
 void
 MediaDecoderStateMachine::OnSeekFailed(nsresult aResult)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   bool wasCanceled = mCancelingSeek;
   mWaitingForDecoderSeek = false;
@@ -2565,25 +2595,25 @@ MediaDecoderStateMachine::OnSeekFailed(n
                   &MediaDecoderStateMachine::OnSeekFailed);
     mWaitingForDecoderSeek = true;
   }
 }
 
 void
 MediaDecoderStateMachine::SeekCompleted()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
   // We must reset the seek target when exiting this function, but not
   // before, as if we dropped the monitor in any function called here,
   // we may begin a new seek on the state machine thread, and be in
   // an inconsistent state.
   AutoSetOnScopeExit<SeekTarget> reset(mCurrentSeekTarget, SeekTarget());
 
-  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   if (mState != DECODER_STATE_SEEKING) {
     return;
   }
 
   int64_t seekTime = mCurrentSeekTarget.mTime;
   int64_t newCurrentTime = mCurrentSeekTarget.mTime;
 
   // Setup timestamp state.
@@ -2660,18 +2690,16 @@ MediaDecoderStateMachine::SeekCompleted(
   UpdatePlaybackPositionInternal(newCurrentTime);
   if (mDecoder->GetDecodedStream()) {
     SetSyncPointForMediaStream();
   }
 
   // Try to decode another frame to detect if we're at the end...
   DECODER_LOG("Seek completed, mCurrentFrameTime=%lld", mCurrentFrameTime);
 
-  mCurrentSeekTarget = SeekTarget();
-
   // Reset quick buffering status. This ensures that if we began the
   // seek while quick-buffering, we won't bypass quick buffering mode
   // if we need to buffer after the seek.
   mQuickBuffering = false;
 
   // Prevent changes in playback position before 'seeked' is fired for we
   // expect currentTime equals seek target in 'seeked' callback.
   mScheduler->FreezeScheduling();
@@ -2723,17 +2751,17 @@ private:
   nsRefPtr<MediaDecoder> mDecoder;
   nsRefPtr<MediaDecoderStateMachine> mStateMachine;
 };
 
 void
 MediaDecoderStateMachine::ShutdownReader()
 {
   MOZ_ASSERT(OnDecodeThread());
-  mReader->Shutdown()->Then(GetStateMachineThread(), __func__, this,
+  mReader->Shutdown()->Then(mScheduler.get(), __func__, this,
                             &MediaDecoderStateMachine::FinishShutdown,
                             &MediaDecoderStateMachine::FinishShutdown);
 }
 
 void
 MediaDecoderStateMachine::FinishShutdown()
 {
   MOZ_ASSERT(OnStateMachineThread());
@@ -2953,18 +2981,17 @@ nsresult MediaDecoderStateMachine::RunSt
   }
 
   return NS_OK;
 }
 
 void
 MediaDecoderStateMachine::FlushDecoding()
 {
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
 
   {
     // Put a task in the decode queue to abort any decoding operations.
     // The reader is not supposed to put any tasks to deliver samples into
     // the queue after this runs (unless we request another sample from it).
     RefPtr<nsIRunnable> task;
     task = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::ResetDecode);
@@ -3005,18 +3032,17 @@ MediaDecoderStateMachine::ResetDecode()
     }
   }
   mReader->ResetDecode();
 }
 
 void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData,
                                                 TimeStamp aTarget)
 {
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
 
   if (aData->mDuplicate) {
     return;
   }
 
   VERBOSE_LOG("playing video frame %lld (queued=%i, state-machine=%i, decoder-queued=%i)",
               aData->mTime, VideoQueue().GetSize() + mReader->SizeOfVideoQueueInFrames(),
@@ -3631,22 +3657,17 @@ void MediaDecoderStateMachine::OnAudioSi
 
   // Make the best effort to continue playback when there is video.
   if (HasVideo()) {
     return;
   }
 
   // Otherwise notify media decoder/element about this error for it makes
   // no sense to play an audio-only file without sound output.
-  RefPtr<nsIRunnable> task(
-    NS_NewRunnableMethod(this, &MediaDecoderStateMachine::AcquireMonitorAndInvokeDecodeError));
-  nsresult rv = DecodeTaskQueue()->Dispatch(task);
-  if (NS_FAILED(rv)) {
-    DECODER_WARN("Failed to dispatch AcquireMonitorAndInvokeDecodeError");
-  }
+  DecodeError();
 }
 
 } // namespace mozilla
 
 // avoid redefined macro in unified build
 #undef DECODER_LOG
 #undef VERBOSE_LOG
 #undef DECODER_WARN
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -491,20 +491,17 @@ protected:
   bool NeedToDecodeVideo();
 
   // Returns true if we've got less than aAudioUsecs microseconds of decoded
   // and playable data. The decoder monitor must be held.
   //
   // May not be invoked when mReader->UseBufferingHeuristics() is false.
   bool HasLowDecodedData(int64_t aAudioUsecs);
 
-  bool OutOfDecodedAudio()
-  {
-    return IsAudioDecoding() && !AudioQueue().IsFinished() && AudioQueue().GetSize() == 0;
-  }
+  bool OutOfDecodedAudio();
 
   bool OutOfDecodedVideo()
   {
     // In buffering mode, we keep the last already-played frame in the queue.
     int emptyVideoSize = mState == DECODER_STATE_BUFFERING ? 1 : 0;
     return IsVideoDecoding() && !VideoQueue().IsFinished() && VideoQueue().GetSize() <= emptyVideoSize;
   }
 
@@ -617,17 +614,17 @@ protected:
 
   // Dispatches a LoadedMetadataEvent.
   // This is threadsafe and can be called on any thread.
   // The decoder monitor must be held.
   void EnqueueLoadedMetadataEvent();
 
   void EnqueueFirstFrameLoadedEvent();
 
-  // Dispatches a task to the decode task queue to begin decoding content.
+  // Dispatches a task to the state machine thread to begin decoding content.
   // This is threadsafe and can be called on any thread.
   // The decoder monitor must be held.
   nsresult EnqueueDecodeFirstFrameTask();
 
   // Dispatches a task to the decode task queue to seek the decoder.
   // The decoder monitor must be held.
   nsresult EnqueueDecodeSeekTask();
 
@@ -652,16 +649,17 @@ protected:
   // the decode task queue, don't call it directly.
   void SetReaderIdle();
 
   // Re-evaluates the state and determines whether we need to dispatch
   // events to run the decode, or if not whether we should set the reader
   // to idle mode. This is threadsafe, and can be called from any thread.
   // The decoder monitor must be held.
   void DispatchDecodeTasksIfNeeded();
+  void AcquireMonitorAndInvokeDispatchDecodeTasksIfNeeded();
 
   // Returns the "media time". This is the absolute time which the media
   // playback has reached. i.e. this returns values in the range
   // [mStartTime, mEndTime], and mStartTime will not be 0 if the media does
   // not start at 0. Note this is different to the value returned
   // by GetCurrentTime(), which is in the range [0,duration].
   int64_t GetMediaTime() const {
     AssertCurrentThreadInMonitor();
@@ -679,17 +677,17 @@ protected:
 
   // Load metadata. Called on the decode thread. The decoder monitor
   // must be held with exactly one lock count.
   nsresult DecodeMetadata();
 
   // Wraps the call to DecodeMetadata(), signals a DecodeError() on failure.
   void CallDecodeMetadata();
 
-  // Initiate first content decoding. Called on the decode thread.
+  // Initiate first content decoding. Called on the state machine thread.
   // The decoder monitor must be held with exactly one lock count.
   nsresult DecodeFirstFrame();
 
   // Wraps the call to DecodeFirstFrame(), signals a DecodeError() on failure.
   void CallDecodeFirstFrame();
 
   // Checks whether we're finished decoding first audio and/or video packets,
   // and switches to DECODING state if so.
@@ -770,17 +768,17 @@ protected:
   // shutting down, without fear of the monitor being destroyed. After
   // shutting down, the state machine will then release this reference,
   // causing the decoder to be destroyed. This is accessed on the decode,
   // state machine, audio and main threads.
   nsRefPtr<MediaDecoder> mDecoder;
 
   // Used to schedule state machine cycles. This should never outlive
   // the life cycle of the state machine.
-  const nsAutoPtr<MediaDecoderStateMachineScheduler> mScheduler;
+  const nsRefPtr<MediaDecoderStateMachineScheduler> mScheduler;
 
   // Time at which the last video sample was requested. If it takes too long
   // before the sample arrives, we will increase the amount of audio we buffer.
   // This is necessary for legacy synchronous decoders to prevent underruns.
   TimeStamp mVideoDecodeStartTime;
 
   // Queue of audio frames. This queue is threadsafe, and is accessed from
   // the audio, decoder, state machine, and main threads.
--- a/dom/media/MediaDecoderStateMachineScheduler.h
+++ b/dom/media/MediaDecoderStateMachineScheduler.h
@@ -21,20 +21,20 @@ class ReentrantMonitor;
 class MediaDecoderStateMachineScheduler {
   enum State {
     SCHEDULER_STATE_NONE,
     SCHEDULER_STATE_FROZEN,
     SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK,
     SCHEDULER_STATE_SHUTDOWN
   };
 public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachineScheduler)
   MediaDecoderStateMachineScheduler(ReentrantMonitor& aMonitor,
                                     nsresult (*aTimeoutCallback)(void*),
                                     void* aClosure, bool aRealTime);
-  ~MediaDecoderStateMachineScheduler();
   nsresult Init();
   nsresult Schedule(int64_t aUsecs = 0);
   void ScheduleAndShutdown();
   nsresult TimeoutExpired(int aTimerId);
   void FreezeScheduling();
   void ThawScheduling();
 
   bool OnStateMachineThread() const;
@@ -49,16 +49,17 @@ public:
   }
 
   bool IsFrozen() const {
     return mState == SCHEDULER_STATE_FROZEN ||
            mState == SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK;
   }
 
 private:
+  ~MediaDecoderStateMachineScheduler();
   void ResetTimer();
 
   // Callback function provided by MediaDecoderStateMachine to run
   // state machine cycles.
   nsresult (*const mTimeoutCallback)(void*);
   // Since StateMachineScheduler will never outlive the state machine,
   // it is safe to keep a raw pointer only to avoid reference cycles.
   void* const mClosure;
--- a/dom/media/MediaPromise.cpp
+++ b/dom/media/MediaPromise.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaPromise.h"
+
+#include "MediaDecoderStateMachineScheduler.h"
 #include "MediaTaskQueue.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace detail {
 
 nsresult
 DispatchMediaPromiseRunnable(MediaTaskQueue* aTaskQueue, nsIRunnable* aRunnable)
@@ -18,23 +20,35 @@ DispatchMediaPromiseRunnable(MediaTaskQu
 }
 
 nsresult
 DispatchMediaPromiseRunnable(nsIEventTarget* aEventTarget, nsIRunnable* aRunnable)
 {
   return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
 }
 
+nsresult
+DispatchMediaPromiseRunnable(MediaDecoderStateMachineScheduler* aScheduler, nsIRunnable* aRunnable)
+{
+  return aScheduler->GetStateMachineThread()->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
+}
+
 void
 AssertOnThread(MediaTaskQueue* aQueue)
 {
   MOZ_ASSERT(aQueue->IsCurrentThreadIn());
 }
 
 void AssertOnThread(nsIEventTarget* aTarget)
 {
   nsCOMPtr<nsIThread> targetThread = do_QueryInterface(aTarget);
   MOZ_ASSERT(targetThread, "Don't know how to deal with threadpools etc here");
   MOZ_ASSERT(NS_GetCurrentThread() == targetThread);
 }
 
+void
+AssertOnThread(MediaDecoderStateMachineScheduler* aScheduler)
+{
+  MOZ_ASSERT(aScheduler->OnStateMachineThread());
+}
+
 }
 } // namespace mozilla
--- a/dom/media/MediaPromise.h
+++ b/dom/media/MediaPromise.h
@@ -27,24 +27,27 @@ namespace mozilla {
 
 extern PRLogModuleInfo* gMediaPromiseLog;
 
 #define PROMISE_LOG(x, ...) \
   MOZ_ASSERT(gMediaPromiseLog); \
   PR_LOG(gMediaPromiseLog, PR_LOG_DEBUG, (x, ##__VA_ARGS__))
 
 class MediaTaskQueue;
+class MediaDecoderStateMachineScheduler;
 namespace detail {
 
 nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable);
 nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable);
+nsresult DispatchMediaPromiseRunnable(MediaDecoderStateMachineScheduler* aScheduler, nsIRunnable* aRunnable);
 
 #ifdef DEBUG
 void AssertOnThread(MediaTaskQueue* aQueue);
 void AssertOnThread(nsIEventTarget* aTarget);
+void AssertOnThread(MediaDecoderStateMachineScheduler* aScheduler);
 #endif
 
 } // namespace detail
 
 /*
  * A promise manages an asynchronous request that may or may not be able to be
  * fulfilled immediately. When an API returns a promise, the consumer may attach
  * callbacks to be invoked (asynchronously, on a specified thread) when the
@@ -586,17 +589,29 @@ public:
   MethodCallWithNoArgs(ThisType* aThisVal, Type aMethod)
     : mThisVal(aThisVal), mMethod(aMethod) {}
   nsRefPtr<PromiseType> Invoke() MOZ_OVERRIDE { return ((*mThisVal).*mMethod)(); }
 protected:
   nsRefPtr<ThisType> mThisVal;
   Type mMethod;
 };
 
-// NB: MethodCallWithOneArg definition should go here, if/when it is needed.
+template<typename PromiseType, typename ThisType, typename Arg1Type>
+class MethodCallWithOneArg : public MethodCallBase<PromiseType>
+{
+public:
+  typedef nsRefPtr<PromiseType>(ThisType::*Type)(Arg1Type);
+  MethodCallWithOneArg(ThisType* aThisVal, Type aMethod, Arg1Type aArg1)
+    : mThisVal(aThisVal), mMethod(aMethod), mArg1(aArg1) {}
+  nsRefPtr<PromiseType> Invoke() MOZ_OVERRIDE { return ((*mThisVal).*mMethod)(mArg1); }
+protected:
+  nsRefPtr<ThisType> mThisVal;
+  Type mMethod;
+  Arg1Type mArg1;
+};
 
 template<typename PromiseType, typename ThisType, typename Arg1Type, typename Arg2Type>
 class MethodCallWithTwoArgs : public MethodCallBase<PromiseType>
 {
 public:
   typedef nsRefPtr<PromiseType>(ThisType::*Type)(Arg1Type, Arg2Type);
   MethodCallWithTwoArgs(ThisType* aThisVal, Type aMethod, Arg1Type aArg1, Arg2Type aArg2)
     : mThisVal(aThisVal), mMethod(aMethod), mArg1(aArg1), mArg2(aArg2) {}
@@ -647,17 +662,25 @@ static nsRefPtr<PromiseType>
 ProxyMediaCall(TargetType* aTarget, ThisType* aThisVal, const char* aCallerName,
                nsRefPtr<PromiseType>(ThisType::*aMethod)())
 {
   typedef detail::MethodCallWithNoArgs<PromiseType, ThisType> MethodCallType;
   MethodCallType* methodCall = new MethodCallType(aThisVal, aMethod);
   return detail::ProxyInternal(aTarget, methodCall, aCallerName);
 }
 
-// NB: One-arg overload should go here, if/when it is needed.
+template<typename PromiseType, typename TargetType, typename ThisType, typename Arg1Type>
+static nsRefPtr<PromiseType>
+ProxyMediaCall(TargetType* aTarget, ThisType* aThisVal, const char* aCallerName,
+               nsRefPtr<PromiseType>(ThisType::*aMethod)(Arg1Type), Arg1Type aArg1)
+{
+  typedef detail::MethodCallWithOneArg<PromiseType, ThisType, Arg1Type> MethodCallType;
+  MethodCallType* methodCall = new MethodCallType(aThisVal, aMethod, aArg1);
+  return detail::ProxyInternal(aTarget, methodCall, aCallerName);
+}
 
 template<typename PromiseType, typename TargetType, typename ThisType,
          typename Arg1Type, typename Arg2Type>
 static nsRefPtr<PromiseType>
 ProxyMediaCall(TargetType* aTarget, ThisType* aThisVal, const char* aCallerName,
                nsRefPtr<PromiseType>(ThisType::*aMethod)(Arg1Type, Arg2Type), Arg1Type aArg1, Arg2Type aArg2)
 {
   typedef detail::MethodCallWithTwoArgs<PromiseType, ThisType, Arg1Type, Arg2Type> MethodCallType;
--- a/dom/media/MediaQueue.h
+++ b/dom/media/MediaQueue.h
@@ -152,45 +152,45 @@ template <class T> class MediaQueue : pr
     return frames;
   }
 
   void ClearListeners() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     mPopListeners.Clear();
   }
 
-  void AddPopListener(nsIRunnable* aRunnable, MediaTaskQueue* aTaskQueue) {
+  void AddPopListener(nsIRunnable* aRunnable, nsIEventTarget* aTarget) {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    mPopListeners.AppendElement(Listener(aRunnable, aTaskQueue));
+    mPopListeners.AppendElement(Listener(aRunnable, aTarget));
   }
 
 private:
   mutable ReentrantMonitor mReentrantMonitor;
 
   struct Listener {
-    Listener(nsIRunnable* aRunnable, MediaTaskQueue* aTaskQueue)
+    Listener(nsIRunnable* aRunnable, nsIEventTarget* aTarget)
       : mRunnable(aRunnable)
-      , mTarget(aTaskQueue)
+      , mTarget(aTarget)
     {
     }
     Listener(const Listener& aOther)
       : mRunnable(aOther.mRunnable)
       , mTarget(aOther.mTarget)
     {
     }
     RefPtr<nsIRunnable> mRunnable;
-    RefPtr<MediaTaskQueue> mTarget;
+    RefPtr<nsIEventTarget> mTarget;
   };
 
   nsTArray<Listener> mPopListeners;
 
   void NotifyPopListeners() {
     for (uint32_t i = 0; i < mPopListeners.Length(); i++) {
       Listener& l = mPopListeners[i];
-      l.mTarget->Dispatch(l.mRunnable);
+      l.mTarget->Dispatch(l.mRunnable, NS_DISPATCH_NORMAL);
     }
   }
 
   // True when we've decoded the last frame of data in the
   // bitstream for which we're queueing frame data.
   bool mEndOfStream;
 };
 
--- a/dom/media/MediaTaskQueue.cpp
+++ b/dom/media/MediaTaskQueue.cpp
@@ -190,22 +190,18 @@ MediaTaskQueue::IsEmpty()
 {
   MonitorAutoLock mon(mQueueMonitor);
   return mTasks.empty();
 }
 
 bool
 MediaTaskQueue::IsCurrentThreadIn()
 {
-#ifdef DEBUG
   MonitorAutoLock mon(mQueueMonitor);
   return NS_GetCurrentThread() == mRunningThread;
-#else
-  return false;
-#endif
 }
 
 nsresult
 MediaTaskQueue::Runner::Run()
 {
   RefPtr<nsIRunnable> event;
   {
     MonitorAutoLock mon(mQueue->mQueueMonitor);
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -23,16 +23,17 @@
 #endif
 #ifdef XP_WIN
 #include "mozilla/WindowsVersion.h"
 #endif
 #include "nsContentCID.h"
 #include "nsServiceManagerUtils.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "mozilla/dom/MediaKeySystemAccess.h"
+#include "nsPrintfCString.h"
 
 namespace mozilla {
 
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeys,
                                       mElement,
                                       mParent,
@@ -169,40 +170,46 @@ MediaKeys::MakePromise(ErrorResult& aRv)
 
 PromiseId
 MediaKeys::StorePromise(Promise* aPromise)
 {
   static uint32_t sEMEPromiseCount = 1;
   MOZ_ASSERT(aPromise);
   uint32_t id = sEMEPromiseCount++;
 
+  EME_LOG("MediaKeys::StorePromise() id=%d", id);
+
   // Keep MediaKeys alive for the lifetime of its promises. Any still-pending
   // promises are rejected in Shutdown().
   AddRef();
 
   mPromises.Put(id, aPromise);
   return id;
 }
 
 already_AddRefed<Promise>
 MediaKeys::RetrievePromise(PromiseId aId)
 {
-  MOZ_ASSERT(mPromises.Contains(aId));
+  if (!mPromises.Contains(aId)) {
+    NS_WARNING(nsPrintfCString("Tried to retrieve a non-existent promise id=%d", aId).get());
+    return nullptr;
+  }
   nsRefPtr<Promise> promise;
   mPromises.Remove(aId, getter_AddRefs(promise));
   Release();
   return promise.forget();
 }
 
 void
 MediaKeys::RejectPromise(PromiseId aId, nsresult aExceptionCode)
 {
+  EME_LOG("MediaKeys::RejectPromise(%d, 0x%x)", aId, aExceptionCode);
+
   nsRefPtr<Promise> promise(RetrievePromise(aId));
   if (!promise) {
-    NS_WARNING("MediaKeys tried to reject a non-existent promise");
     return;
   }
   if (mPendingSessions.Contains(aId)) {
     // This promise could be a createSession or loadSession promise,
     // so we might have a pending session waiting to be resolved into
     // the promise on success. We've been directed to reject to promise,
     // so we can throw away the corresponding session object.
     mPendingSessions.Remove(aId);
@@ -237,19 +244,20 @@ MediaKeys::OnSessionIdReady(MediaKeySess
     return;
   }
   mKeySessions.Put(aSession->GetSessionId(), aSession);
 }
 
 void
 MediaKeys::ResolvePromise(PromiseId aId)
 {
+  EME_LOG("MediaKeys::ResolvePromise(%d)", aId);
+
   nsRefPtr<Promise> promise(RetrievePromise(aId));
   if (!promise) {
-    NS_WARNING("MediaKeys tried to resolve a non-existent promise");
     return;
   }
   if (mPendingSessions.Contains(aId)) {
     // We should only resolve LoadSession calls via this path,
     // not CreateSession() promises.
     nsRefPtr<MediaKeySession> session;
     if (!mPendingSessions.Get(aId, getter_AddRefs(session)) ||
         !session ||
@@ -352,21 +360,21 @@ MediaKeys::Init(ErrorResult& aRv)
   return promise.forget();
 }
 
 void
 MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId)
 {
   nsRefPtr<Promise> promise(RetrievePromise(aId));
   if (!promise) {
-    NS_WARNING("MediaKeys tried to resolve a non-existent promise");
     return;
   }
   mNodeId = aNodeId;
   nsRefPtr<MediaKeys> keys(this);
+  EME_LOG("MediaKeys::OnCDMCreated() resolve promise id=%d", aId);
   promise->MaybeResolve(keys);
   if (mCreatePromiseId == aId) {
     Release();
   }
 
   MediaKeySystemAccess::NotifyObservers(mParent,
                                         mKeySystem,
                                         MediaKeySystemStatus::Cdm_created);
@@ -394,19 +402,20 @@ MediaKeys::CreateSession(JSContext* aCx,
   return session.forget();
 }
 
 void
 MediaKeys::OnSessionLoaded(PromiseId aId, bool aSuccess)
 {
   nsRefPtr<Promise> promise(RetrievePromise(aId));
   if (!promise) {
-    NS_WARNING("MediaKeys tried to resolve a non-existent promise");
     return;
   }
+  EME_LOG("MediaKeys::OnSessionLoaded() resolve promise id=%d", aId);
+
   promise->MaybeResolve(aSuccess);
 }
 
 void
 MediaKeys::OnSessionClosed(MediaKeySession* aSession)
 {
   nsAutoString id;
   aSession->GetSessionId(id);
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -464,17 +464,19 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
   if (HasVideo()) {
     const VideoDecoderConfig& video = mDemuxer->VideoConfig();
     if (mInfo.mVideo.mHasVideo && !IsSupportedVideoMimeType(video.mime_type)) {
       return NS_ERROR_FAILURE;
     }
     mInfo.mVideo.mDisplay =
       nsIntSize(video.display_width, video.display_height);
     mVideo.mCallback = new DecoderCallback(this, kVideo);
-    if (mSharedDecoderManager) {
+    if (!mIsEncrypted && mSharedDecoderManager) {
+      // Note: Don't use SharedDecoderManager in EME content, as it doesn't
+      // handle reiniting the decoder properly yet.
       mVideo.mDecoder =
         mSharedDecoderManager->CreateVideoDecoder(mPlatform,
                                                   video,
                                                   mLayersBackendType,
                                                   mDecoder->GetImageContainer(),
                                                   mVideo.mTaskQueue,
                                                   mVideo.mCallback);
     } else {
@@ -1070,17 +1072,19 @@ void MP4Reader::NotifyResourcesStatusCha
     mDecoder->NotifyWaitingForResourcesStatusChanged();
   }
 #endif
 }
 
 void
 MP4Reader::SetIdle()
 {
-  if (mSharedDecoderManager && mVideo.mDecoder) {
+  if (!mIsEncrypted && mSharedDecoderManager && mVideo.mDecoder) {
+    // Note: Don't use SharedDecoderManager in EME content, as it doesn't
+    // handle reiniting the decoder properly yet.
     mSharedDecoderManager->SetIdle(mVideo.mDecoder);
     NotifyResourcesStatusChanged();
   }
 }
 
 void
 MP4Reader::SetSharedDecoderManager(SharedDecoderManager* aManager)
 {
--- a/dom/media/fmp4/apple/AppleDecoderModule.cpp
+++ b/dom/media/fmp4/apple/AppleDecoderModule.cpp
@@ -22,16 +22,19 @@ PRLogModuleInfo* GetAppleMediaLog() {
     log = PR_NewLogModule("AppleMedia");
   }
   return log;
 }
 #endif
 
 namespace mozilla {
 
+// This defines the resolution height over which VDA will be prefered.
+#define VDA_RESOLUTION_THRESHOLD 720
+
 bool AppleDecoderModule::sInitialized = false;
 bool AppleDecoderModule::sIsVTAvailable = false;
 bool AppleDecoderModule::sIsVTHWAvailable = false;
 bool AppleDecoderModule::sIsVDAAvailable = false;
 bool AppleDecoderModule::sForceVDA = false;
 
 AppleDecoderModule::AppleDecoderModule()
 {
@@ -42,22 +45,22 @@ AppleDecoderModule::~AppleDecoderModule(
 }
 
 /* static */
 void
 AppleDecoderModule::Init()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
 
-  sForceVDA = Preferences::GetBool("media.apple.forcevda", false);
-
   if (sInitialized) {
     return;
   }
 
+  Preferences::AddBoolVarCache(&sForceVDA, "media.apple.forcevda", false);
+
   // dlopen VideoDecodeAcceleration.framework if it's available.
   sIsVDAAvailable = AppleVDALinker::Link();
 
   // dlopen CoreMedia.framework if it's available.
   bool haveCoreMedia = AppleCMLinker::Link();
   // dlopen VideoToolbox.framework if it's available.
   // We must link both CM and VideoToolbox framework to allow for proper
   // paired Link/Unlink calls
@@ -158,17 +161,19 @@ already_AddRefed<MediaDataDecoder>
 AppleDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                                        layers::LayersBackend aLayersBackend,
                                        layers::ImageContainer* aImageContainer,
                                        FlushableMediaTaskQueue* aVideoTaskQueue,
                                        MediaDataDecoderCallback* aCallback)
 {
   nsRefPtr<MediaDataDecoder> decoder;
 
-  if (sIsVDAAvailable && (!sIsVTHWAvailable || sForceVDA)) {
+  if (sIsVDAAvailable &&
+      (!sIsVTHWAvailable || sForceVDA ||
+       aConfig.image_height >= VDA_RESOLUTION_THRESHOLD)) {
     decoder =
       AppleVDADecoder::CreateVDADecoder(aConfig,
                                         aVideoTaskQueue,
                                         aCallback,
                                         aImageContainer);
     if (decoder) {
       return decoder.forget();
     }
--- a/dom/media/fmp4/gmp/GMPAudioDecoder.cpp
+++ b/dom/media/fmp4/gmp/GMPAudioDecoder.cpp
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GMPAudioDecoder.h"
 
 namespace mozilla {
 
 #if defined(DEBUG)
-static bool IsOnGMPThread()
+bool IsOnGMPThread()
 {
   nsCOMPtr<mozIGeckoMediaPluginService> mps = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
   MOZ_ASSERT(mps);
 
   nsCOMPtr<nsIThread> gmpThread;
   nsresult rv = mps->GetThread(getter_AddRefs(gmpThread));
   MOZ_ASSERT(NS_SUCCEEDED(rv) && gmpThread);
   return NS_GetCurrentThread() == gmpThread;
--- a/dom/media/fmp4/gmp/GMPVideoDecoder.cpp
+++ b/dom/media/fmp4/gmp/GMPVideoDecoder.cpp
@@ -6,17 +6,17 @@
 
 #include "GMPVideoDecoder.h"
 #include "GMPVideoHost.h"
 #include "prsystem.h"
 
 namespace mozilla {
 
 #if defined(DEBUG)
-static bool IsOnGMPThread();
+extern bool IsOnGMPThread();
 #endif
 
 void
 VideoCallbackAdapter::Decoded(GMPVideoi420Frame* aDecodedFrame)
 {
   GMPUnique<GMPVideoi420Frame>::Ptr decodedFrame(aDecodedFrame);
 
   MOZ_ASSERT(IsOnGMPThread());
--- a/dom/media/gmp/GMPVideoDecoderParent.cpp
+++ b/dom/media/gmp/GMPVideoDecoderParent.cpp
@@ -64,17 +64,17 @@ GMPVideoDecoderParent::Host()
   return mVideoHost;
 }
 
 // Note: may be called via Terminated()
 void
 GMPVideoDecoderParent::Close()
 {
   LOGD(("%s: %p", __FUNCTION__, this));
-  MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
+  MOZ_ASSERT(!mPlugin || mPlugin->GMPThread() == NS_GetCurrentThread());
   // Consumer is done with us; we can shut down.  No more callbacks should
   // be made to mCallback.  Note: do this before Shutdown()!
   mCallback = nullptr;
   // Let Shutdown mark us as dead so it knows if we had been alive
 
   // In case this is the last reference
   nsRefPtr<GMPVideoDecoderParent> kungfudeathgrip(this);
   Release();
--- a/dom/media/gmp/gmp-api/gmp-video-host.h
+++ b/dom/media/gmp/gmp-api/gmp-video-host.h
@@ -34,18 +34,20 @@
 #ifndef GMP_VIDEO_HOST_h_
 #define GMP_VIDEO_HOST_h_
 
 #include "gmp-errors.h"
 #include "gmp-video-frame-i420.h"
 #include "gmp-video-frame-encoded.h"
 #include "gmp-video-codec.h"
 
+// This interface must be called on the main thread only.
 class GMPVideoHost
 {
 public:
   // Construct various video API objects. Host does not retain reference,
   // caller is owner and responsible for deleting.
+  // MAIN THREAD ONLY
   virtual GMPErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) = 0;
   virtual GMPErr CreatePlane(GMPPlane** aPlane) = 0;
 };
 
 #endif // GMP_VIDEO_HOST_h_
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -18,30 +18,38 @@
 
 #ifdef MOZ_FMP4
 #include "SharedDecoderManager.h"
 #include "MP4Decoder.h"
 #include "MP4Reader.h"
 #endif
 
 #ifdef PR_LOGGING
+extern PRLogModuleInfo* GetMediaSourceLog();
+
 #define MSE_DEBUG(arg, ...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG, ("MediaSourceReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 #define MSE_DEBUGV(arg, ...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG + 1, ("MediaSourceReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 #else
 #define MSE_DEBUG(...)
 #define MSE_DEBUGV(...)
 #endif
 
 // When a stream hits EOS it needs to decide what other stream to switch to. Due
 // to inaccuracies is determining buffer end frames (Bug 1065207) and rounding
 // issues we use a fuzz factor to determine the end time of this stream for
 // switching to the new stream. This value is based on the end of frame
 // default value used in Blink, kDefaultBufferDurationInMs.
 #define EOS_FUZZ_US 125000
 
+// Audio and video source buffers often have a slight duration
+// discrepency. We want to handle the case where a source buffer is smaller than
+// another by more than EOS_FUZZ_US so we can properly detect EOS in IsNearEnd().
+// This value was chosen at random, to cater for most streams seen in the wild.
+#define DURATION_DIFFERENCE_FUZZ 300000
+
 using mozilla::dom::TimeRanges;
 
 namespace mozilla {
 
 MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)
   , mLastAudioTime(0)
   , mLastVideoTime(0)
@@ -103,16 +111,17 @@ MediaSourceReader::SizeOfAudioQueueInFra
     return 0;
   }
   return GetAudioReader()->SizeOfAudioQueueInFrames();
 }
 
 nsRefPtr<MediaDecoderReader::AudioDataPromise>
 MediaSourceReader::RequestAudioData()
 {
+  MOZ_ASSERT(OnDecodeThread());
   nsRefPtr<AudioDataPromise> p = mAudioPromise.Ensure(__func__);
   MSE_DEBUGV("");
   if (!mAudioTrack) {
     MSE_DEBUG("called with no audio track");
     mAudioPromise.Reject(DECODE_ERROR, __func__);
     return p;
   }
   if (IsSeeking()) {
@@ -246,16 +255,17 @@ MediaSourceReader::OnAudioNotDecoded(Not
   }
 
   CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
 }
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
 MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
 {
+  MOZ_ASSERT(OnDecodeThread());
   nsRefPtr<VideoDataPromise> p = mVideoPromise.Ensure(__func__);
   MSE_DEBUGV("RequestVideoData(%d, %lld)",
              aSkipToNextKeyframe, aTimeThreshold);
   if (!mVideoTrack) {
     MSE_DEBUG("called with no video track");
     mVideoPromise.Reject(DECODE_ERROR, __func__);
     return p;
   }
@@ -373,17 +383,17 @@ MediaSourceReader::OnVideoNotDecoded(Not
 
   CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
 }
 
 void
 MediaSourceReader::CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime)
 {
   // If the entire MediaSource is done, generate an EndOfStream.
-  if (IsNearEnd(aTime)) {
+  if (IsNearEnd(aType, aTime)) {
     if (aType == MediaData::AUDIO_DATA) {
       mAudioPromise.Reject(END_OF_STREAM, __func__);
     } else {
       mVideoPromise.Reject(END_OF_STREAM, __func__);
     }
     return;
   }
 
@@ -595,17 +605,17 @@ CreateReaderForType(const nsACString& aT
 {
 #ifdef MOZ_FMP4
   // The MP4Reader that supports fragmented MP4 and uses
   // PlatformDecoderModules is hidden behind prefs for regular video
   // elements, but we always want to use it for MSE, so instantiate it
   // directly here.
   if ((aType.LowerCaseEqualsLiteral("video/mp4") ||
        aType.LowerCaseEqualsLiteral("audio/mp4")) &&
-      MP4Decoder::IsEnabled()) {
+      MP4Decoder::IsEnabled() && aDecoder) {
     return new MP4Reader(aDecoder);
   }
 #endif
   return DecoderTraits::CreateReader(aType, aDecoder);
 }
 
 already_AddRefed<SourceBufferDecoder>
 MediaSourceReader::CreateSubDecoder(const nsACString& aType, int64_t aTimestampOffset)
@@ -931,16 +941,17 @@ MediaSourceReader::GetBuffered(dom::Time
 
   MSE_DEBUG("ranges=%s", DumpTimeRanges(intersectionRanges).get());
   return NS_OK;
 }
 
 nsRefPtr<MediaDecoderReader::WaitForDataPromise>
 MediaSourceReader::WaitForData(MediaData::Type aType)
 {
+  MOZ_ASSERT(OnDecodeThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   nsRefPtr<WaitForDataPromise> p = WaitPromise(aType).Ensure(__func__);
   MaybeNotifyHaveData();
   return p;
 }
 
 void
 MediaSourceReader::MaybeNotifyHaveData()
@@ -1040,20 +1051,37 @@ MediaSourceReader::Ended()
 bool
 MediaSourceReader::IsEnded()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   return mEnded;
 }
 
 bool
-MediaSourceReader::IsNearEnd(int64_t aTime)
+MediaSourceReader::IsNearEnd(MediaData::Type aType, int64_t aTime)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  return mEnded && aTime >= (mMediaSourceDuration * USECS_PER_S - EOS_FUZZ_US);
+  if (!mEnded) {
+    return false;
+  }
+  if (aTime >= (mMediaSourceDuration * USECS_PER_S - EOS_FUZZ_US)) {
+    return true;
+  }
+  // We may have discrepencies between the mediasource duration and the
+  // sourcebuffer end time (mMediaSourceDuration == max(audio.EndTime, video.EndTime)
+  // If the sourcebuffer duration is close enough to the mediasource duration,
+  // then use it instead to determine if we're near the end.
+  TrackBuffer* trackBuffer =
+    aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
+  nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
+  trackBuffer->Buffered(buffered);
+  if ((mMediaSourceDuration - buffered->GetEndTime()) * USECS_PER_S <= DURATION_DIFFERENCE_FUZZ) {
+    return aTime >= std::floor(buffered->GetEndTime() * USECS_PER_S);
+  }
+  return false;
 }
 
 void
 MediaSourceReader::SetMediaSourceDuration(double aDuration)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mMediaSourceDuration = aDuration;
 }
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -127,17 +127,17 @@ public:
   // Return true if all of the active tracks contain data for the specified time.
   bool TrackBuffersContainTime(int64_t aTime);
 
   // Mark the reader to indicate that EndOfStream has been called on our MediaSource
   void Ended();
 
   // Return true if the Ended method has been called
   bool IsEnded();
-  bool IsNearEnd(int64_t aTime /* microseconds */);
+  bool IsNearEnd(MediaData::Type aType, int64_t aTime /* microseconds */);
 
   // Set the duration of the attached mediasource element.
   void SetMediaSourceDuration(double aDuration /* seconds */);
 
 #ifdef MOZ_EME
   nsresult SetCDMProxy(CDMProxy* aProxy);
 #endif
 
--- a/dom/media/mediasource/SourceBufferList.cpp
+++ b/dom/media/mediasource/SourceBufferList.cpp
@@ -12,17 +12,19 @@
 #include "mozilla/mozalloc.h"
 #include "nsCOMPtr.h"
 #include "nsIRunnable.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "prlog.h"
 
 #ifdef PR_LOGGING
+extern PRLogModuleInfo* GetMediaSourceLog();
 extern PRLogModuleInfo* GetMediaSourceAPILog();
+
 #define MSE_API(arg, ...) PR_LOG(GetMediaSourceAPILog(), PR_LOG_DEBUG, ("SourceBufferList(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 #define MSE_DEBUG(arg, ...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG, ("SourceBufferList(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 #else
 #define MSE_API(...)
 #define MSE_DEBUG(...)
 #endif
 
 struct JSContext;
--- a/dom/mobileconnection/gonk/MobileConnectionService.js
+++ b/dom/mobileconnection/gonk/MobileConnectionService.js
@@ -51,19 +51,23 @@ const UNKNOWN_RSSI = 99;
 XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionMessenger",
                                    "@mozilla.org/ril/system-messenger-helper;1",
                                    "nsIMobileConnectionMessenger");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
                                    "@mozilla.org/network/manager;1",
                                    "nsINetworkManager");
 
-XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
-                                   "@mozilla.org/ril;1",
-                                   "nsIRadioInterfaceLayer");
+XPCOMUtils.defineLazyGetter(this, "gRadioInterfaceLayer", function() {
+  let ril = { numRadioInterfaces: 0 };
+  try {
+    ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
+  } catch(e) {}
+  return ril;
+});
 
 let DEBUG = RIL.DEBUG_RIL;
 function debug(s) {
   dump("MobileConnectionService: " + s + "\n");
 }
 
 function MobileNetworkInfo() {
   this.shortName = null;
@@ -333,17 +337,17 @@ MobileConnectionProvider.prototype = {
     if (supportedNetworkTypes.length === 1 && supportedNetworkTypes[0] === "") {
       key = "ro.telephony.default_network";
       let indexString = libcutils.property_get(key, "");
       let index = parseInt(indexString, 10);
       if (DEBUG) this._debug("Fallback to " + key + ": " + index);
 
       let networkTypes = RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[index];
       supportedNetworkTypes = networkTypes ?
-        networkTypes.replace("-auto", "", "g").split("/") :
+        networkTypes.replace(/-auto/g, "").split("/") :
         RIL.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT.split(",");
     }
 
     let enumNetworkTypes = [];
     for (let type of supportedNetworkTypes) {
       // If the value in system property is not valid, use the default one which
       // is defined in ril_consts.js.
       if (RIL.GECKO_SUPPORTED_NETWORK_TYPES.indexOf(type) < 0) {
--- a/dom/mobileconnection/moz.build
+++ b/dom/mobileconnection/moz.build
@@ -57,20 +57,21 @@ IPDL_SOURCES += [
     'ipc/PMobileConnectionTypes.ipdlh',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
     XPIDL_SOURCES += [
         'gonk/nsIGonkMobileConnectionService.idl',
         'gonk/nsIMobileConnectionMessenger.idl',
     ]
-    EXTRA_COMPONENTS += [
-        'gonk/MobileConnectionService.js',
-        'gonk/MobileConnectionService.manifest',
-    ]
+    if not CONFIG['DISABLE_MOZ_RIL_GEOLOC']:
+        EXTRA_COMPONENTS += [
+            'gonk/MobileConnectionService.js',
+            'gonk/MobileConnectionService.manifest',
+        ]
 
 LOCAL_INCLUDES += [
     '/dom/system/gonk',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/mobilemessage/MmsMessage.cpp
+++ b/dom/mobilemessage/MmsMessage.cpp
@@ -582,17 +582,17 @@ MmsMessage::GetAttachments(JSContext* aC
     if (!GetOrCreateDOMReflector(aCx, newBlob, &val)) {
       return NS_ERROR_FAILURE;
     }
 
     if (!JS_DefineProperty(aCx, attachmentObj, "content", val, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
-    if (!JS_SetElement(aCx, attachments, i, attachmentObj)) {
+    if (!JS_DefineElement(aCx, attachments, i, attachmentObj, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   aAttachments.setObject(*attachments);
   return NS_OK;
 }
 
--- a/dom/mobilemessage/MobileMessageCallback.cpp
+++ b/dom/mobilemessage/MobileMessageCallback.cpp
@@ -192,17 +192,17 @@ MobileMessageCallback::NotifyMessageDele
   AutoJSAPI jsapi;
   if (NS_WARN_IF(!jsapi.Init(mDOMRequest->GetOwner()))) {
     return NS_ERROR_FAILURE;
   }
   JSContext* cx = jsapi.cx();
 
   JS::Rooted<JSObject*> deleteArrayObj(cx, JS_NewArrayObject(cx, aSize));
   for (uint32_t i = 0; i < aSize; i++) {
-    JS_SetElement(cx, deleteArrayObj, i, aDeleted[i]);
+    JS_DefineElement(cx, deleteArrayObj, i, aDeleted[i], JSPROP_ENUMERATE);
   }
 
   JS::Rooted<JS::Value> deleteArrayVal(cx, JS::ObjectValue(*deleteArrayObj));
   return NotifySuccess(deleteArrayVal);
 }
 
 NS_IMETHODIMP
 MobileMessageCallback::NotifyDeleteMessageFailed(int32_t aError)
--- a/dom/mobilemessage/gonk/SmsService.js
+++ b/dom/mobilemessage/gonk/SmsService.js
@@ -35,17 +35,20 @@ const kSmsDeliveryErrorObserverTopic    
 const DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED = "received";
 const DOM_MOBILE_MESSAGE_DELIVERY_SENDING  = "sending";
 const DOM_MOBILE_MESSAGE_DELIVERY_SENT     = "sent";
 const DOM_MOBILE_MESSAGE_DELIVERY_ERROR    = "error";
 
 const SMS_HANDLED_WAKELOCK_TIMEOUT = 5000;
 
 XPCOMUtils.defineLazyGetter(this, "gRadioInterfaces", function() {
-  let ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
+  let ril = { numRadioInterfaces: 0 };
+  try {
+    ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
+  } catch(e) {}
 
   let interfaces = [];
   for (let i = 0; i < ril.numRadioInterfaces; i++) {
     interfaces.push(ril.getRadioInterface(i));
   }
   return interfaces;
 });
 
--- a/dom/mobilemessage/ipc/SmsParent.cpp
+++ b/dom/mobilemessage/ipc/SmsParent.cpp
@@ -115,17 +115,17 @@ GetParamsFromSendMmsMessageRequest(JSCon
 
   // attachments
   JS::Rooted<JSObject*> attachmentArray(aCx, JS_NewArrayObject(aCx,
                                                                aRequest.attachments().Length()));
   for (uint32_t i = 0; i < aRequest.attachments().Length(); i++) {
     JS::Rooted<JSObject*> obj(aCx,
       MmsAttachmentDataToJSObject(aCx, aRequest.attachments().ElementAt(i)));
     NS_ENSURE_TRUE(obj, false);
-    if (!JS_SetElement(aCx, attachmentArray, i, obj)) {
+    if (!JS_DefineElement(aCx, attachmentArray, i, obj, JSPROP_ENUMERATE)) {
       return false;
     }
   }
 
   if (!JS_DefineProperty(aCx, paramsObj, "attachments", attachmentArray, 0)) {
     return false;
   }
 
--- a/dom/mobilemessage/moz.build
+++ b/dom/mobilemessage/moz.build
@@ -30,19 +30,22 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'go
         'gonk/wap_consts.js',
         'gonk/WspPduHelper.jsm',
     ]
     EXTRA_COMPONENTS += [
         'gonk/MmsService.js',
         'gonk/MmsService.manifest',
         'gonk/MobileMessageDatabaseService.js',
         'gonk/MobileMessageDatabaseService.manifest',
-        'gonk/SmsService.js',
-        'gonk/SmsService.manifest',
     ]
+    if not CONFIG['DISABLE_MOZ_RIL_GEOLOC']:
+        EXTRA_COMPONENTS += [
+            'gonk/SmsService.js',
+            'gonk/SmsService.manifest',
+        ]
 
 EXPORTS.mozilla.dom += [
     'DOMMobileMessageError.h',
     'MmsMessage.h',
     'MobileMessageManager.h',
     'SmsMessage.h',
 ]
 
--- a/dom/nfc/gonk/NfcGonkMessage.h
+++ b/dom/nfc/gonk/NfcGonkMessage.h
@@ -3,36 +3,38 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NfcGonkMessage_h
 #define NfcGonkMessage_h
 
 namespace mozilla {
 
 #define NFCD_MAJOR_VERSION 1
-#define NFCD_MINOR_VERSION 20
+#define NFCD_MINOR_VERSION 21
 
 enum NfcRequest {
-  ChangeRFStateReq = 0,
+  ChangeRFStateReq,
   ReadNDEFReq,
   WriteNDEFReq,
   MakeReadOnlyReq,
   FormatReq,
   TransceiveReq,
 };
 
 enum NfcResponse {
-  GeneralRsp = 1000,
   ChangeRFStateRsp,
   ReadNDEFRsp,
-  TransceiveRsp
+  WriteNDEFRsp,
+  MakeReadOnlyRsp,
+  FormatRsp,
+  TransceiveRsp,
 };
 
 enum NfcNotification {
-  Initialized = 2000,
+  Initialized,
   TechDiscovered,
   TechLost,
   HCIEventTransaction,
 };
 
 enum NfcTechlogy {
   NDEF = 0,
   NDEFWritable,
--- a/dom/nfc/gonk/NfcMessageHandler.cpp
+++ b/dom/nfc/gonk/NfcMessageHandler.cpp
@@ -44,52 +44,72 @@ NfcMessageHandler::Marshall(Parcel& aPar
   const char* type = NS_ConvertUTF16toUTF8(aOptions.mType).get();
 
   if (!strcmp(type, kChangeRFStateRequest)) {
     result = ChangeRFStateRequest(aParcel, aOptions);
   } else if (!strcmp(type, kReadNDEFRequest)) {
     result = ReadNDEFRequest(aParcel, aOptions);
   } else if (!strcmp(type, kWriteNDEFRequest)) {
     result = WriteNDEFRequest(aParcel, aOptions);
-    mPendingReqQueue.AppendElement(NfcRequest::WriteNDEFReq);
   } else if (!strcmp(type, kMakeReadOnlyRequest)) {
     result = MakeReadOnlyRequest(aParcel, aOptions);
-    mPendingReqQueue.AppendElement(NfcRequest::MakeReadOnlyReq);
   } else if (!strcmp(type, kFormatRequest)) {
     result = FormatRequest(aParcel, aOptions);
-    mPendingReqQueue.AppendElement(NfcRequest::FormatReq);
   } else if (!strcmp(type, kTransceiveRequest)) {
     result = TransceiveRequest(aParcel, aOptions);
   } else {
     result = false;
   }
 
   return result;
 }
 
 bool
 NfcMessageHandler::Unmarshall(const Parcel& aParcel, EventOptions& aOptions)
 {
-  bool result;
   mozilla::unused << htonl(aParcel.readInt32());  // parcel size
   int32_t type = aParcel.readInt32();
+  bool isNotification = type >> 31;
+  int32_t msgType = type & ~(1 << 31);
 
-  switch (type) {
-    case NfcResponse::GeneralRsp:
-      result = GeneralResponse(aParcel, aOptions);
-      break;
+  return isNotification ? ProcessNotification(msgType, aParcel, aOptions) :
+                          ProcessResponse(msgType, aParcel, aOptions);
+}
+
+bool
+NfcMessageHandler::ProcessResponse(int32_t aType, const Parcel& aParcel, EventOptions& aOptions)
+{
+  bool result;
+  switch (aType) {
     case NfcResponse::ChangeRFStateRsp:
       result = ChangeRFStateResponse(aParcel, aOptions);
       break;
     case NfcResponse::ReadNDEFRsp:
       result = ReadNDEFResponse(aParcel, aOptions);
       break;
+    case NfcResponse::WriteNDEFRsp: // Fall through.
+    case NfcResponse::MakeReadOnlyRsp:
+    case NfcResponse::FormatRsp:
+      result = GeneralResponse(aType, aParcel, aOptions);
+      break;
     case NfcResponse::TransceiveRsp:
       result = TransceiveResponse(aParcel, aOptions);
       break;
+    default:
+      result = false;
+  }
+
+  return result;
+}
+
+bool
+NfcMessageHandler::ProcessNotification(int32_t aType, const Parcel& aParcel, EventOptions& aOptions)
+{
+  bool result;
+  switch (aType) {
     case NfcNotification::Initialized:
       result = InitializeNotification(aParcel, aOptions);
       break;
     case NfcNotification::TechDiscovered:
       result = TechDiscoveredNotification(aParcel, aOptions);
       break;
     case NfcNotification::TechLost:
       result = TechLostNotification(aParcel, aOptions);
@@ -101,35 +121,31 @@ NfcMessageHandler::Unmarshall(const Parc
       result = false;
       break;
   }
 
   return result;
 }
 
 bool
-NfcMessageHandler::GeneralResponse(const Parcel& aParcel, EventOptions& aOptions)
+NfcMessageHandler::GeneralResponse(const int32_t aResponse, const Parcel& aParcel, EventOptions& aOptions)
 {
   const char* type;
-  NS_ENSURE_TRUE(!mPendingReqQueue.IsEmpty(), false);
-  int pendingReq = mPendingReqQueue[0];
-  mPendingReqQueue.RemoveElementAt(0);
-
-  switch (pendingReq) {
-    case NfcRequest::WriteNDEFReq:
+  switch (aResponse) {
+    case NfcResponse::WriteNDEFRsp:
       type = kWriteNDEFResponse;
       break;
-    case NfcRequest::MakeReadOnlyReq:
+    case NfcResponse::MakeReadOnlyRsp:
       type = kMakeReadOnlyResponse;
       break;
-    case NfcRequest::FormatReq:
+    case NfcResponse::FormatRsp:
       type = kFormatResponse;
       break;
     default:
-      NMH_LOG("Nfcd, unknown general response %d", pendingReq);
+      NMH_LOG("Nfcd, unknown general aResponse %d", aResponse);
       return false;
   }
 
   aOptions.mType = NS_ConvertUTF8toUTF16(type);
   aOptions.mErrorCode = aParcel.readInt32();
   aOptions.mSessionId = aParcel.readInt32();
 
   NS_ENSURE_TRUE(!mRequestIdQueue.IsEmpty(), false);
--- a/dom/nfc/gonk/NfcMessageHandler.h
+++ b/dom/nfc/gonk/NfcMessageHandler.h
@@ -19,35 +19,36 @@ class EventOptions;
 
 class NfcMessageHandler
 {
 public:
   bool Marshall(android::Parcel& aParcel, const CommandOptions& aOptions);
   bool Unmarshall(const android::Parcel& aParcel, EventOptions& aOptions);
 
 private:
-  bool GeneralResponse(const android::Parcel& aParcel, EventOptions& aOptions);
+  bool ProcessResponse(int32_t aType, const android::Parcel& aParcel, EventOptions& aOptions);
+  bool GeneralResponse(int32_t aResponse, const android::Parcel& aParcel, EventOptions& aOptions);
   bool ChangeRFStateRequest(android::Parcel& aParcel, const CommandOptions& options);
   bool ChangeRFStateResponse(const android::Parcel& aParcel, EventOptions& aOptions);
   bool ReadNDEFRequest(android::Parcel& aParcel, const CommandOptions& options);
   bool ReadNDEFResponse(const android::Parcel& aParcel, EventOptions& aOptions);
   bool WriteNDEFRequest(android::Parcel& aParcel, const CommandOptions& options);
   bool MakeReadOnlyRequest(android::Parcel& aParcel, const CommandOptions& options);
   bool FormatRequest(android::Parcel& aParcel, const CommandOptions& options);
   bool TransceiveRequest(android::Parcel& aParcel, const CommandOptions& options);
   bool TransceiveResponse(const android::Parcel& aParcel, EventOptions& aOptions);
 
+  bool ProcessNotification(int32_t aType, const android::Parcel& aParcel, EventOptions& aOptions);
   bool InitializeNotification(const android::Parcel& aParcel, EventOptions& aOptions);
   bool TechDiscoveredNotification(const android::Parcel& aParcel, EventOptions& aOptions);
   bool TechLostNotification(const android::Parcel& aParcel, EventOptions& aOptions);
   bool HCIEventTransactionNotification(const android::Parcel& aParcel, EventOptions& aOptions);
 
   bool ReadNDEFMessage(const android::Parcel& aParcel, EventOptions& aOptions);
   bool WriteNDEFMessage(android::Parcel& aParcel, const CommandOptions& aOptions);
   bool ReadTransceiveResponse(const android::Parcel& aParcel, EventOptions& aOptions);
 private:
-  nsTArray<int32_t> mPendingReqQueue;
   nsTArray<nsString> mRequestIdQueue;
 };
 
 } // namespace mozilla
 
 #endif // NfcMessageHandler_h
--- a/dom/payment/Payment.jsm
+++ b/dom/payment/Payment.jsm
@@ -296,17 +296,17 @@ let PaymentManager =  {
 
     let payloadObject;
     try {
       // We only care about the payload segment, which contains the jwt type
       // that should match with any of the stored payment provider's data and
       // the payment request information to be shown to the user.
       // Before decoding the JWT string we need to normalize it to be compliant
       // with RFC 4648.
-      segments[1] = segments[1].replace("-", "+", "g").replace("_", "/", "g");
+      segments[1] = segments[1].replace(/-/g, "+").replace(/_/g, "/");
       let payload = atob(segments[1]);
       if (this._debug) {
         this.LOG("Payload " + payload);
       }
       if (!payload.length) {
         this.paymentFailed(aRequestId, "PAY_REQUEST_ERROR_EMPTY_PAYLOAD");
         return true;
       }
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -784,28 +784,27 @@ NPBool nsPluginInstanceOwner::ConvertPoi
   nsPoint windowPosition = AsNsPoint(rootWidget->GetWindowPosition()) / scaleFactor;
 
   // Window size is tab size + chrome size.
   nsIntRect tabContentBounds;
   NS_ENSURE_SUCCESS(puppetWidget->GetBounds(tabContentBounds), false);
   tabContentBounds.ScaleInverseRoundOut(scaleFactor);
   int32_t windowH = tabContentBounds.height + int(chromeSize.y);
 
-  // This is actually relative to window-chrome.
   nsPoint pluginPosition = AsNsPoint(pluginFrame->GetScreenRect().TopLeft());
 
   // Convert (sourceX, sourceY) to 'real' (not PuppetWidget) screen space.
   // In OSX, the Y-axis increases upward, which is the reverse of ours.
   // We want OSX coordinates for window and screen so those equations are swapped.
   nsPoint sourcePoint(sourceX, sourceY);
   nsPoint screenPoint;
   switch (sourceSpace) {
     case NPCoordinateSpacePlugin:
-      screenPoint = sourcePoint + pluginFrame->GetContentRectRelativeToSelf().TopLeft() +
-        chromeSize + pluginPosition + windowPosition;
+      screenPoint = sourcePoint + pluginPosition +
+        pluginFrame->GetContentRectRelativeToSelf().TopLeft() / nsPresContext::AppUnitsPerCSSPixel();
       break;
     case NPCoordinateSpaceWindow:
       screenPoint = nsPoint(sourcePoint.x, windowH-sourcePoint.y) +
         windowPosition;
       break;
     case NPCoordinateSpaceFlippedWindow:
       screenPoint = sourcePoint + windowPosition;
       break;
@@ -818,18 +817,18 @@ NPBool nsPluginInstanceOwner::ConvertPoi
     default:
       return false;
   }
 
   // Convert from screen to dest space.
   nsPoint destPoint;
   switch (destSpace) {
     case NPCoordinateSpacePlugin:
-      destPoint = screenPoint - pluginFrame->GetContentRectRelativeToSelf().TopLeft() -
-        chromeSize - pluginPosition - windowPosition;
+      destPoint = screenPoint - pluginPosition -
+        pluginFrame->GetContentRectRelativeToSelf().TopLeft() / nsPresContext::AppUnitsPerCSSPixel();
       break;
     case NPCoordinateSpaceWindow:
       destPoint = screenPoint - windowPosition;
       destPoint.y = windowH - destPoint.y;
       break;
     case NPCoordinateSpaceFlippedWindow:
       destPoint = screenPoint - windowPosition;
       break;
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -111,17 +111,19 @@ MakePrefNameForPlugin(const char* const 
 
 static nsresult
 CStringArrayToXPCArray(nsTArray<nsCString> & aArray,
                        uint32_t* aCount,
                        char16_t*** aResults)
 {
   uint32_t count = aArray.Length();
   if (!count) {
-    return NS_ERROR_NOT_AVAILABLE;
+    *aResults = nullptr;
+    *aCount = 0;
+    return NS_OK;
   }
 
   *aResults =
     static_cast<char16_t**>(nsMemory::Alloc(count * sizeof(**aResults)));
   *aCount = count;
 
   for (uint32_t i = 0; i < count; i++) {
     (*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(aArray[i]));
--- a/dom/settings/SettingsService.js
+++ b/dom/settings/SettingsService.js
@@ -200,17 +200,17 @@ SettingsServiceLock.prototype = {
                                         lockID: this._id,
                                         settings: settings});
   },
 
   callHandle: function callHandle(aCallback, aName, aValue) {
     try {
         aCallback && aCallback.handle ? aCallback.handle(aName, aValue) : null;
     } catch (e) {
-      if (DEBUG) debug("settings 'handle' callback threw an exception, dropping: " + e + "\n");
+      if (DEBUG) debug("settings 'handle' for " + aName + " callback threw an exception, dropping: " + e + "\n");
     }
   },
 
   callAbort: function callAbort(aCallback, aMessage) {
     try {
       aCallback && aCallback.handleAbort ? aCallback.handleAbort(aMessage) : null;
     } catch (e) {
       if (DEBUG) debug("settings 'abort' callback threw an exception, dropping: " + e + "\n");
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -68,18 +68,21 @@ XPCOMUtils.defineLazyServiceGetter(this,
                   "nsIUUIDGenerator");
 
 XPCOMUtils.defineLazyGetter(this, "gNumRadioInterfaces", function() {
   let appInfo = Cc["@mozilla.org/xre/app-info;1"];
   let isParentProcess = !appInfo || appInfo.getService(Ci.nsIXULRuntime)
                           .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
 
   if (isParentProcess) {
-    let ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
-    return ril.numRadioInterfaces;
+    let ril = { numRadioInterfaces: 0 };
+    try {
+      ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
+    } catch(e) {}
+    return ril.numRadioInterfaces
   }
 
   return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces);
 });
 
 function IccInfo() {}
 IccInfo.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccInfo]),
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/RILContentHelper.manifest
@@ -0,0 +1,18 @@
+# Copyright 2012 Mozilla Foundation and Mozilla contributors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# 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.
+
+# RILContentHelper.js
+component {472816e1-1fd6-4405-996c-806f9ea68174} RILContentHelper.js
+contract @mozilla.org/ril/content-helper;1 {472816e1-1fd6-4405-996c-806f9ea68174}
+category profile-after-change RILContentHelper @mozilla.org/ril/content-helper;1
--- a/dom/system/gonk/RadioInterfaceLayer.manifest
+++ b/dom/system/gonk/RadioInterfaceLayer.manifest
@@ -11,13 +11,8 @@
 # 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.
 
 # RadioInterfaceLayer.js
 component {2d831c8d-6017-435b-a80c-e5d422810cea} RadioInterfaceLayer.js
 contract @mozilla.org/ril;1 {2d831c8d-6017-435b-a80c-e5d422810cea}
 category profile-after-change RadioInterfaceLayer @mozilla.org/ril;1
-
-# RILContentHelper.js
-component {472816e1-1fd6-4405-996c-806f9ea68174} RILContentHelper.js
-contract @mozilla.org/ril/content-helper;1 {472816e1-1fd6-4405-996c-806f9ea68174}
-category profile-after-change RILContentHelper @mozilla.org/ril/content-helper;1
--- a/dom/system/gonk/moz.build
+++ b/dom/system/gonk/moz.build
@@ -83,28 +83,32 @@ EXTRA_JS_MODULES += [
     'systemlibs.js',
 ]
 
 if CONFIG['MOZ_B2G_RIL']:
     XPIDL_SOURCES += [
         'nsIRadioInterfaceLayer.idl',
     ]
     EXTRA_COMPONENTS += [
-        'RadioInterfaceLayer.js',
-        'RadioInterfaceLayer.manifest',
         'RILContentHelper.js',
+        'RILContentHelper.manifest',
         'RILSystemMessengerHelper.js',
         'RILSystemMessengerHelper.manifest',
     ]
     EXTRA_JS_MODULES += [
         'ril_consts.js',
         'ril_worker.js',
         'ril_worker_buf_object.js',
         'RILSystemMessenger.jsm',
     ]
+    if not CONFIG['DISABLE_MOZ_RIL_GEOLOC']:
+        EXTRA_COMPONENTS += [
+            'RadioInterfaceLayer.js',
+            'RadioInterfaceLayer.manifest',
+        ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/dom/base',
     '/dom/bluetooth',
--- a/dom/system/mac/CoreLocationLocationProvider.h
+++ b/dom/system/mac/CoreLocationLocationProvider.h
@@ -1,57 +1,59 @@
 /* -*- 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 "nsCOMPtr.h"
 #include "nsIGeolocationProvider.h"
 
+
 /*
  * The CoreLocationObjects class contains the CoreLocation objects
  * we'll need.
  *
  * Declaring them directly in CoreLocationLocationProvider
  * would require Objective-C++ syntax, which would contaminate all
  * files that include this header and require them to be Objective-C++
  * as well.
  *
  * The solution then is to forward-declare CoreLocationObjects here and
  * hold a pointer to it in CoreLocationLocationProvider, and only actually
  * define it in CoreLocationLocationProvider.mm, thus making it safe
  * for nsGeolocation.cpp, which is C++-only, to include this header.
  */
 class CoreLocationObjects;
+class MLSFallback;
 
 class CoreLocationLocationProvider
   : public nsIGeolocationProvider
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIGEOLOCATIONPROVIDER
 
   CoreLocationLocationProvider();
   void NotifyError(uint16_t aErrorCode);
   void Update(nsIDOMGeoPosition* aSomewhere);
   void CreateMLSFallbackProvider();
   void CancelMLSFallbackProvider();
 
 private:
-  virtual ~CoreLocationLocationProvider() {};
+  virtual ~CoreLocationLocationProvider();
 
   CoreLocationObjects* mCLObjects;
   nsCOMPtr<nsIGeolocationUpdate> mCallback;
-  nsCOMPtr<nsIGeolocationProvider> mMLSFallbackProvider;
+  nsRefPtr<MLSFallback> mMLSFallbackProvider;
 
   class MLSUpdate : public nsIGeolocationUpdate
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIGEOLOCATIONUPDATE
 
     explicit MLSUpdate(CoreLocationLocationProvider& parentProvider);
 
   private:
     CoreLocationLocationProvider& mParentLocationProvider;
-    virtual ~MLSUpdate() {}
+    virtual ~MLSUpdate();
   };
 };
--- a/dom/system/mac/CoreLocationLocationProvider.mm
+++ b/dom/system/mac/CoreLocationLocationProvider.mm
@@ -8,16 +8,17 @@
 #include "nsGeoPosition.h"
 #include "nsIConsoleService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIDOMGeoPositionError.h"
 #include "CoreLocationLocationProvider.h"
 #include "nsCocoaFeatures.h"
 #include "prtime.h"
 #include "mozilla/Telemetry.h"
+#include "MLSFallback.h"
 
 #include <CoreLocation/CLError.h>
 #include <CoreLocation/CLLocation.h>
 #include <CoreLocation/CLLocationManager.h>
 #include <CoreLocation/CLLocationManagerDelegate.h>
 
 #include <objc/objc.h>
 #include <objc/objc-runtime.h>
@@ -27,17 +28,16 @@
 using namespace mozilla;
 
 static const CLLocationAccuracy kHIGH_ACCURACY = kCLLocationAccuracyBest;
 static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTenMeters;
 
 @interface LocationDelegate : NSObject <CLLocationManagerDelegate>
 {
   CoreLocationLocationProvider* mProvider;
-  NSTimer* mHandoffTimer;
 }
 
 - (id)init:(CoreLocationLocationProvider*)aProvider;
 - (void)locationManager:(CLLocationManager*)aManager
   didFailWithError:(NSError *)aError;
 - (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)locations;
 
 @end
@@ -47,33 +47,16 @@ static const CLLocationAccuracy kDEFAULT
 {
   if ((self = [super init])) {
     mProvider = aProvider;
   }
 
   return self;
 }
 
-- (void)shutdownHandoffTimer
-{
-  if (!mHandoffTimer) {
-    return;
-  }
-
-  [mHandoffTimer invalidate];
-  [mHandoffTimer release];
-  mHandoffTimer = nil;
-}
-
-- (void)handoffToGeoIPProvider
-{
-  [self shutdownHandoffTimer];
-  mProvider->CreateMLSFallbackProvider();
-}
-
 - (void)locationManager:(CLLocationManager*)aManager
   didFailWithError:(NSError *)aError
 {
   nsCOMPtr<nsIConsoleService> console =
     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
 
   NS_ENSURE_TRUE_VOID(console);
 
@@ -82,40 +65,33 @@ static const CLLocationAccuracy kDEFAULT
 
   console->LogStringMessage(NS_ConvertUTF8toUTF16([message UTF8String]).get());
 
   if ([aError code] == kCLErrorDenied) {
     mProvider->NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED);
     return;
   }
 
-  if (!mHandoffTimer) {
-    // The CL provider does not fallback to GeoIP, so use NetworkGeolocationProvider for this.
-    // The concept here is: on error, hand off geolocation to MLS, which will then report
-    // back a location or error. We can't call this with no delay however, as this method
-    // is called with an error code of 0 in both failed geolocation cases, and also when
-    // geolocation is not immediately available.
-    // The 2 sec delay is arbitrarily large enough that CL has a reasonable head start and
-    // if it is likely to succeed, it should complete before the MLS provider.
-    // Take note that in locationManager:didUpdateLocations: the handoff to MLS is stopped.
-    mHandoffTimer = [[NSTimer scheduledTimerWithTimeInterval:2.0
-                                                     target:self
-                                                   selector:@selector(handoffToGeoIPProvider)
-                                                   userInfo:nil
-                                                    repeats:NO] retain];
-  }
+  // The CL provider does not fallback to GeoIP, so use NetworkGeolocationProvider for this.
+  // The concept here is: on error, hand off geolocation to MLS, which will then report
+  // back a location or error. We can't call this with no delay however, as this method
+  // is called with an error code of 0 in both failed geolocation cases, and also when
+  // geolocation is not immediately available.
+  // The 2 sec delay is arbitrarily large enough that CL has a reasonable head start and
+  // if it is likely to succeed, it should complete before the MLS provider.
+  // Take note that in locationManager:didUpdateLocations: the handoff to MLS is stopped.
+  mProvider->CreateMLSFallbackProvider();
 }
 
 - (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)aLocations
 {
   if (aLocations.count < 1) {
     return;
   }
 
-  [self shutdownHandoffTimer];
   mProvider->CancelMLSFallbackProvider();
 
   CLLocation* location = [aLocations objectAtIndex:0];
 
   nsCOMPtr<nsIDOMGeoPosition> geoPosition =
     new nsGeoPosition(location.coordinate.latitude,
                       location.coordinate.longitude,
                       location.altitude,
@@ -132,16 +108,20 @@ static const CLLocationAccuracy kDEFAULT
 
 NS_IMPL_ISUPPORTS(CoreLocationLocationProvider::MLSUpdate, nsIGeolocationUpdate);
 
 CoreLocationLocationProvider::MLSUpdate::MLSUpdate(CoreLocationLocationProvider& parentProvider)
   : mParentLocationProvider(parentProvider)
 {
 }
 
+CoreLocationLocationProvider::MLSUpdate::~MLSUpdate()
+{
+}
+
 NS_IMETHODIMP
 CoreLocationLocationProvider::MLSUpdate::Update(nsIDOMGeoPosition *position)
 {
   nsCOMPtr<nsIDOMGeoPositionCoords> coords;
   position->GetCoords(getter_AddRefs(coords));
   if (!coords) {
     return NS_ERROR_FAILURE;
   }
@@ -195,16 +175,20 @@ public:
 
 NS_IMPL_ISUPPORTS(CoreLocationLocationProvider, nsIGeolocationProvider)
 
 CoreLocationLocationProvider::CoreLocationLocationProvider()
   : mCLObjects(nullptr), mMLSFallbackProvider(nullptr)
 {
 }
 
+CoreLocationLocationProvider::~CoreLocationLocationProvider()
+{
+}
+
 NS_IMETHODIMP
 CoreLocationLocationProvider::Startup()
 {
   if (!mCLObjects) {
     nsAutoPtr<CoreLocationObjects> clObjs(new CoreLocationObjects());
 
     nsresult rv = clObjs->Init(this);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -229,17 +213,16 @@ CoreLocationLocationProvider::Watch(nsIG
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CoreLocationLocationProvider::Shutdown()
 {
   NS_ENSURE_STATE(mCLObjects);
 
-  [mCLObjects->mLocationDelegate shutdownHandoffTimer];
   [mCLObjects->mLocationManager stopUpdatingLocation];
 
   delete mCLObjects;
   mCLObjects = nullptr;
 
   if (mMLSFallbackProvider) {
     mMLSFallbackProvider->Shutdown();
     mMLSFallbackProvider = nullptr;
@@ -275,23 +258,18 @@ CoreLocationLocationProvider::NotifyErro
 
 void
 CoreLocationLocationProvider::CreateMLSFallbackProvider()
 {
   if (mMLSFallbackProvider) {
     return;
   }
 
-  mMLSFallbackProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1");
-  if (mMLSFallbackProvider) {
-    nsresult rv = mMLSFallbackProvider->Startup();
-    if (NS_SUCCEEDED(rv)) {
-      mMLSFallbackProvider->Watch(new CoreLocationLocationProvider::MLSUpdate(*this));
-    }
-  }
+  mMLSFallbackProvider = new MLSFallback();
+  mMLSFallbackProvider->Startup(new MLSUpdate(*this));
 }
 
 void
 CoreLocationLocationProvider::CancelMLSFallbackProvider()
 {
   if (!mMLSFallbackProvider) {
     return;
   }
--- a/dom/telephony/gonk/DialNumberUtils.jsm
+++ b/dom/telephony/gonk/DialNumberUtils.jsm
@@ -73,28 +73,16 @@ this.DialNumberUtils = {
     let fullmmi = "(" + procedure + serviceCode + allSi + "#)";
 
     // Dial string after the #.
     let optionalDialString = "([^#]+)?";
 
     return new RegExp("^" + fullmmi + optionalDialString + "$");
   })(),
 
-  _isPoundString: function(aString) {
-    return aString && aString[aString.length - 1] === "#";
-  },
-
-  _isShortString: function(aString) {
-    if (!aString || this.isEmergency(aString) || aString.length > 2 ||
-        (aString.length == 2 && aString[0] === "1")) {
-      return false;
-    }
-    return true;
-  },
-
   /**
    * Check parse the given string as an MMI code.
    *
    * An MMI code should be:
    * - Activation (*SC*SI#).
    * - Deactivation (#SC*SI#).
    * - Interrogation (*#SC*SI#).
    * - Registration (**SC*SI#).
@@ -112,17 +100,11 @@ this.DialNumberUtils = {
         sia: matches[MMI_MATCH_GROUP_SIA],
         sib: matches[MMI_MATCH_GROUP_SIB],
         sic: matches[MMI_MATCH_GROUP_SIC],
         pwd: matches[MMI_MATCH_GROUP_PWD_CONFIRM],
         dialNumber: matches[MMI_MATCH_GROUP_DIALING_NUMBER]
       };
     }
 
-    if (this._isPoundString(aString) || this._isShortString(aString)) {
-      return {
-        fullMMI: aString
-      };
-    }
-
     return null;
   }
 };
--- a/dom/telephony/gonk/TelephonyService.js
+++ b/dom/telephony/gonk/TelephonyService.js
@@ -6,16 +6,17 @@
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 
+/* global RIL */
 XPCOMUtils.defineLazyGetter(this, "RIL", function () {
   let obj = {};
   Cu.import("resource://gre/modules/ril_consts.js", obj);
   return obj;
 });
 
 const GONK_TELEPHONYSERVICE_CONTRACTID =
   "@mozilla.org/telephony/gonktelephonyservice;1";
@@ -53,42 +54,53 @@ const DIAL_ERROR_RADIO_NOT_AVAILABLE = R
 
 const TONES_GAP_DURATION = 70;
 
 let DEBUG;
 function debug(s) {
   dump("TelephonyService: " + s + "\n");
 }
 
-XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
-                                   "@mozilla.org/ril;1",
-                                   "nsIRadioInterfaceLayer");
+/* global gRadioInterfaceLayer */
+XPCOMUtils.defineLazyGetter(this, "gRadioInterfaceLayer", function() {
+  let ril = { numRadioInterfaces: 0 };
+  try {
+    ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
+  } catch(e) {}
+  return ril;
+});
 
+/* global gPowerManagerService */
 XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
                                    "@mozilla.org/power/powermanagerservice;1",
                                    "nsIPowerManagerService");
 
+/* global gTelephonyMessenger */
 XPCOMUtils.defineLazyServiceGetter(this, "gTelephonyMessenger",
                                    "@mozilla.org/ril/system-messenger-helper;1",
                                    "nsITelephonyMessenger");
 
+/* global gAudioService */
 XPCOMUtils.defineLazyServiceGetter(this, "gAudioService",
                                    "@mozilla.org/telephony/audio-service;1",
                                    "nsITelephonyAudioService");
 
+/* global gGonkMobileConnectionService */
 XPCOMUtils.defineLazyServiceGetter(this, "gGonkMobileConnectionService",
                                    "@mozilla.org/mobileconnection/mobileconnectionservice;1",
                                    "nsIGonkMobileConnectionService");
 
+/* global gPhoneNumberUtils */
 XPCOMUtils.defineLazyGetter(this, "gPhoneNumberUtils", function() {
   let ns = {};
   Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns);
   return ns.PhoneNumberUtils;
 });
 
+/* global gDialNumberUtils */
 XPCOMUtils.defineLazyGetter(this, "gDialNumberUtils", function() {
   let ns = {};
   Cu.import("resource://gre/modules/DialNumberUtils.jsm", ns);
   return ns.DialNumberUtils;
 });
 
 function MobileCallForwardingOptions(aOptions) {
   for (let key in aOptions) {
@@ -477,16 +489,21 @@ TelephonyService.prototype = {
       let call = this._currentCalls[aClientId][index];
       if (call.state === nsITelephonyService.CALL_STATE_CONNECTED) {
         return call;
       }
     }
     return null;
   },
 
+  /**
+   * Dial number. Perform call setup or SS procedure accordingly.
+   *
+   * @see 3GPP TS 22.030 Figure 3.5.3.2
+   */
   dial: function(aClientId, aNumber, aIsDialEmergency, aCallback) {
     if (DEBUG) debug("Dialing " + (aIsDialEmergency ? "emergency " : "") + aNumber);
 
     // We don't try to be too clever here, as the phone is probably in the
     // locked state. Let's just check if it's a number without normalizing
     if (!aIsDialEmergency) {
       aNumber = gPhoneNumberUtils.normalize(aNumber);
     }
@@ -496,48 +513,62 @@ TelephonyService.prototype = {
     if (!gPhoneNumberUtils.isPlainPhoneNumber(aNumber)) {
       if (DEBUG) debug("Error: Number '" + aNumber + "' is not viable. Drop.");
       aCallback.notifyError(DIAL_ERROR_BAD_NUMBER);
       return;
     }
 
     let isEmergencyNumber = gDialNumberUtils.isEmergency(aNumber);
 
-    // Should be radio on except it's an emergency number.
-    if (!(this._isRadioOn(aClientId) || isEmergencyNumber)) {
-      aCallback.notifyError(DIAL_ERROR_RADIO_NOT_AVAILABLE);
+    // DialEmergency accepts only emergency number.
+    if (aIsDialEmergency && !isEmergencyNumber) {
+      if (!this._isRadioOn(aClientId)) {
+        if (DEBUG) debug("Error: Radio is off. Drop.");
+        aCallback.notifyError(DIAL_ERROR_RADIO_NOT_AVAILABLE);
+        return;
+      }
+
+      if (DEBUG) debug("Error: Dial a non-emergency by dialEmergency. Drop.");
+      aCallback.notifyError(DIAL_ERROR_BAD_NUMBER);
       return;
     }
 
-    // DialEmergency accepts only emergency number.
-    if (aIsDialEmergency && !isEmergencyNumber) {
-      if (DEBUG) debug("Error: Dail a non-emergency by dialEmergency. Drop.");
-      aCallback.notifyError(DIAL_ERROR_BAD_NUMBER);
+    if (isEmergencyNumber) {
+      this._dialCall(aClientId, aNumber, undefined, aCallback);
       return;
     }
 
     // In cdma, we should always handle the request as a call.
     if (this._isCdmaClient(aClientId)) {
       this._dialCall(aClientId, aNumber, undefined, aCallback);
       return;
     }
 
-    if (this._hasCalls(aClientId)) {
-      this._dialInCallMMI(aClientId, aNumber, aCallback);
-      return;
-    }
-
     let mmi = gDialNumberUtils.parseMMI(aNumber);
-    if (!mmi) {
-      this._dialCall(aClientId, aNumber, undefined, aCallback);
-    } else if (this._isTemporaryCLIR(mmi)) {
-      this._dialCall(aClientId, mmi.dialNumber,
-                     this._procedureToCLIRMode(mmi.procedure), aCallback);
+    if (mmi) {
+      if (this._isTemporaryCLIR(mmi)) {
+        this._dialCall(aClientId, mmi.dialNumber,
+                       this._procedureToCLIRMode(mmi.procedure), aCallback);
+      } else {
+        this._dialMMI(aClientId, mmi, aCallback);
+      }
     } else {
-      this._dialMMI(aClientId, mmi, aCallback);
+      if (aNumber[aNumber.length - 1] === "#") {  // # string
+        this._dialMMI(aClientId, {fullMMI: aNumber}, aCallback);
+      } else if (aNumber.length <= 2) {  // short string
+        if (this._hasCalls(aClientId)) {
+          this._dialInCallMMI(aClientId, aNumber, aCallback);
+        } else if (aNumber.length === 2 && aNumber[0] === "1") {
+          this._dialCall(aClientId, aNumber, undefined, aCallback);
+        } else {
+          this._dialMMI(aClientId, {fullMMI: aNumber}, aCallback);
+        }
+      } else {
+        this._dialCall(aClientId, aNumber, undefined, aCallback);
+      }
     }
   },
 
   // Handling of supplementary services within a call as 3GPP TS 22.030 6.5.5
   _dialInCallMMI: function(aClientId, aNumber, aCallback) {
     let mmiCallback = response => {
       aCallback.notifyDialMMI(RIL.MMI_KS_SC_CALL);
       if (!response.success) {
@@ -585,19 +616,29 @@ TelephonyService.prototype = {
     // any new call on other SIM.
     if (this._hasCallsOnOtherClient(aClientId)) {
       if (DEBUG) debug("Error: Already has a call on other sim.");
       aCallback.notifyError(DIAL_ERROR_OTHER_CONNECTION_IN_USE);
       return;
     }
 
     let isEmergency = gDialNumberUtils.isEmergency(aNumber);
-    if (!isEmergency && this._isEmergencyOnly()) {
-      if (DEBUG) debug("Error: Dail a normal call when emergencyCallsOnly. Drop");
-      aCallback.notifyError(DIAL_ERROR_BAD_NUMBER);
+
+    if (!isEmergency) {
+      if (!this._isRadioOn(aClientId)) {
+        if (DEBUG) debug("Error: Dial a normal call when radio off. Drop");
+        aCallback.notifyError(DIAL_ERROR_RADIO_NOT_AVAILABLE);
+        return;
+      }
+
+      if (this._isEmergencyOnly()) {
+        if (DEBUG) debug("Error: Dial a normal call when emergencyCallsOnly. Drop");
+        aCallback.notifyError(DIAL_ERROR_BAD_NUMBER);
+        return;
+      }
     }
 
     if (isEmergency) {
       // Automatically select a proper clientId for emergency call.
       aClientId = gRadioInterfaceLayer.getClientIdForEmergencyCall() ;
       if (aClientId === -1) {
         if (DEBUG) debug("Error: No client is avaialble for emergency call.");
         aCallback.notifyError(DIAL_ERROR_INVALID_STATE_ERROR);
--- a/dom/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -20,16 +20,17 @@ qemu = true
 [test_dsds_connection_conflict.js]
 [test_dsds_default_service_id.js]
 [test_dsds_normal_call.js]
 [test_emergency.js]
 [test_emergency_label.js]
 [test_incall_mmi_call_hold.js]
 [test_incall_mmi_call_waiting.js]
 [test_incall_mmi_conference.js]
+[test_incall_mmi_imei.js]
 [test_incoming_already_connected.js]
 [test_incoming_already_held.js]
 [test_incoming_answer_hangup_oncallschanged.js]
 [test_incoming_basic_operations.js]
 [test_incoming_onstatechange.js]
 [test_mmi.js]
 [test_mmi_call_forwarding.js]
 [test_mmi_change_barring_password.js]
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_incall_mmi_imei.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+const number = "0900000001";
+let outCall;
+
+function getIMEI() {
+  log("Test *#06# ...");
+
+  return gSendMMI("*#06#").then(aResult => {
+    ok(aResult.success, "success");
+    is(aResult.serviceCode, "scImei", "Service code IMEI");
+    // IMEI is hardcoded as "000000000000000".
+    // See it here {B2G_HOME}/external/qemu/telephony/android_modem.c
+    // (The aResult of +CGSN).
+    is(aResult.statusMessage, "000000000000000", "Emulator IMEI");
+    is(aResult.additionalInformation, undefined, "No additional information");
+  });
+}
+
+function testInCallMMI_IMEI() {
+  log('= testInCallMMI_IMEI =');
+
+  return gDial(number)
+    .then(call => outCall = call)
+    .then(() => gRemoteAnswer(outCall))
+    .then(() => getIMEI())
+    .then(() => gRemoteHangUpCalls([outCall]));
+}
+
+startTest(function() {
+  testInCallMMI_IMEI()
+    .catch(error => ok(false, "Promise reject: " + error))
+    .then(finish);
+});
--- a/dom/telephony/test/marionette/test_outgoing_radio_off.js
+++ b/dom/telephony/test/marionette/test_outgoing_radio_off.js
@@ -60,12 +60,13 @@ function testDialEmergency_EmergencyNumb
 }
 
 startTestWithPermissions(['mobileconnection'], function() {
   Promise.resolve()
     .then(() => testDial_NormalNumber())
     .then(() => testDial_EmergencyNumber())
     .then(() => testDialEmergency_NormalNumber())
     .then(() => testDialEmergency_EmergencyNumber())
+    .catch(error => ok(false, "Promise reject: " + error))
     .then(() => setRadioEnabledAll(true))
     .catch(error => ok(false, "Promise reject: " + error))
     .then(finish);
 });
--- a/dom/telephony/test/xpcshell/test_parseMMI.js
+++ b/dom/telephony/test/xpcshell/test_parseMMI.js
@@ -25,73 +25,28 @@ add_test(function test_parseMMI_empty() 
 add_test(function test_parseMMI_undefined() {
   let mmi = parseMMI();
 
   equal(mmi, null);
 
   run_next_test();
 });
 
-add_test(function test_parseMMI_one_digit_short_code() {
-  let mmi = parseMMI("1");
-
-  equal(mmi.fullMMI, "1");
-  equal(mmi.procedure, undefined);
-  equal(mmi.serviceCode, undefined);
-  equal(mmi.sia, undefined);
-  equal(mmi.sib, undefined);
-  equal(mmi.sic, undefined);
-  equal(mmi.pwd, undefined);
-  equal(mmi.dialNumber, undefined);
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_invalid_short_code() {
-  let mmi = parseMMI("11");
-
-  equal(mmi, null);
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_short_code() {
-  let mmi = parseMMI("21");
-
-  equal(mmi.fullMMI, "21");
-  equal(mmi.procedure, undefined);
-  equal(mmi.serviceCode, undefined);
-  equal(mmi.sia, undefined);
-  equal(mmi.sib, undefined);
-  equal(mmi.sic, undefined);
-  equal(mmi.pwd, undefined);
-  equal(mmi.dialNumber, undefined);
-
-  run_next_test();
-});
-
 add_test(function test_parseMMI_dial_string() {
   let mmi = parseMMI("12345");
 
   equal(mmi, null);
 
   run_next_test();
 });
 
 add_test(function test_parseMMI_USSD_without_asterisk_prefix() {
   let mmi = parseMMI("123#");
 
-  equal(mmi.fullMMI, "123#");
-  equal(mmi.procedure, undefined);
-  equal(mmi.serviceCode, undefined);
-  equal(mmi.sia, undefined);
-  equal(mmi.sib, undefined);
-  equal(mmi.sic, undefined);
-  equal(mmi.pwd, undefined);
-  equal(mmi.dialNumber, undefined);
+  equal(mmi, null);
 
   run_next_test();
 });
 
 add_test(function test_parseMMI_USSD() {
   let mmi = parseMMI("*123#");
 
   equal(mmi.fullMMI, "*123#");
@@ -104,24 +59,17 @@ add_test(function test_parseMMI_USSD() {
   equal(mmi.dialNumber, undefined);
 
   run_next_test();
 });
 
 add_test(function test_parseMMI_USSD_with_two_sharps() {
   let mmi = parseMMI("*225#4384903113430962#");
 
-  equal(mmi.fullMMI, "*225#4384903113430962#");
-  equal(mmi.procedure, undefined);
-  equal(mmi.serviceCode, undefined);
-  equal(mmi.sia, undefined);
-  equal(mmi.sib, undefined);
-  equal(mmi.sic, undefined);
-  equal(mmi.pwd, undefined);
-  equal(mmi.dialNumber, undefined);
+  equal(mmi, null);
 
   run_next_test();
 });
 
 add_test(function test_parseMMI_sia() {
   let mmi = parseMMI("*123*1#");
 
   equal(mmi.fullMMI, "*123*1#");
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -2224,18 +2224,19 @@ private:
   bool
   DispatchFetchEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     MOZ_ASSERT(aCx);
     MOZ_ASSERT(aWorkerPrivate);
     MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
     GlobalObject globalObj(aCx, aWorkerPrivate->GlobalScope()->GetWrapper());
 
+    NS_ConvertUTF8toUTF16 local(mSpec);
     RequestOrUSVString requestInfo;
-    *requestInfo.SetAsUSVString().ToAStringPtr() = NS_ConvertUTF8toUTF16(mSpec);
+    requestInfo.SetAsUSVString().Rebind(local.Data(), local.Length());
 
     RootedDictionary<RequestInit> reqInit(aCx);
     reqInit.mMethod.Construct(mMethod);
 
     nsRefPtr<InternalHeaders> internalHeaders = new InternalHeaders(HeadersGuardEnum::Request);
     MOZ_ASSERT(mHeaderNames.Length() == mHeaderValues.Length());
     for (uint32_t i = 0; i < mHeaderNames.Length(); i++) {
       ErrorResult rv;
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -1448,19 +1448,25 @@ ChromeTooltipListener::sTooltipCallback(
       bool textFound = false;
 
       self->mTooltipTextProvider->GetNodeText(
           self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound);
 
       if (textFound) {
         nsString tipText(tooltipText);
         LayoutDeviceIntPoint screenDot = widget->WidgetToScreenOffset();
-        self->ShowTooltip(self->mMouseScreenX - screenDot.x,
-                          self->mMouseScreenY - screenDot.y,
-                          tipText);
+        double scaleFactor = 1.0;
+        if (shell->GetPresContext()) {
+          scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
+          shell->GetPresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
+        }
+        // ShowTooltip expects widget-relative position.
+        self->ShowTooltip(self->mMouseScreenX - screenDot.x / scaleFactor,
+          self->mMouseScreenY - screenDot.y / scaleFactor,
+          tipText);
       }
     }
 
     // release tooltip target if there is one, NO MATTER WHAT
     self->mPossibleTooltipNode = nullptr;
   } // if "self" data valid
 
 } // sTooltipCallback
--- a/gfx/cairo/cairo/src/moz.build
+++ b/gfx/cairo/cairo/src/moz.build
@@ -194,16 +194,28 @@ DEFINES['PACKAGE_BUGREPORT'] = '"http://
 
 for var in ('CAIRO_HAS_PTHREAD', '_GNU_SOURCE'):
     DEFINES[var] = True
 
 for var in ('MOZ_TREE_CAIRO', 'MOZ_TREE_PIXMAN'):
     if CONFIG[var]:
         DEFINES[var] = True
 
+if CONFIG['GNU_CC']:
+    DEFINES['HAVE_INTEL_ATOMIC_PRIMITIVES'] = True
+    # We would normally use autoconf to set these up, using AC_CHECK_SIZEOF.
+    # But AC_CHECK_SIZEOF requires running programs to determine the sizes,
+    # and that doesn't work so well with cross-compiling.  So instead we
+    # use these magic macros, available since at least GCC 4.3, to define
+    # the preprocessor macros cairo wanted from autoconf.
+    DEFINES['SIZEOF_VOID_P'] = '__SIZEOF_POINTER__'
+    DEFINES['SIZEOF_INT'] = '__SIZEOF_INT__'
+    DEFINES['SIZEOF_LONG'] = '__SIZEOF_LONG__'
+    DEFINES['SIZEOF_LONG_LONG'] = '__SIZEOF_LONG_LONG__'
+
 # Normally determined by cairo's configure script.
 DEFINES['HAVE_UINT64_T'] = True
 
 if CONFIG['MOZ_TREE_FREETYPE']:
     DEFINES['HAVE_FT_LIBRARY_SETLCDFILTER'] = True
     DEFINES['FT_LCD_FILTER_H'] = '%s/modules/freetype2/include/freetype/ftlcdfil.h' % TOPSRCDIR
 
 # Suppress warnings in third-party code.
--- a/gfx/layers/LayerMetricsWrapper.h
+++ b/gfx/layers/LayerMetricsWrapper.h
@@ -304,26 +304,16 @@ public:
     MOZ_ASSERT(IsValid());
 
     if (AtBottomLayer()) {
       return mLayer->GetEventRegions();
     }
     return EventRegions();
   }
 
-  bool HasTransformAnimation() const
-  {
-    MOZ_ASSERT(IsValid());
-
-    if (AtBottomLayer()) {
-      return mLayer->HasTransformAnimation();
-    }
-    return false;
-  }
-
   RefLayer* AsRefLayer() const
   {
     MOZ_ASSERT(IsValid());
 
     if (AtBottomLayer()) {
       return mLayer->AsRefLayer();
     }
     return nullptr;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -757,27 +757,16 @@ Layer::GetLocalTransform()
   transform.PostScale(GetPostXScale(), GetPostYScale(), 1.0f);
   if (ContainerLayer* c = AsContainerLayer()) {
     transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
   }
 
   return transform;
 }
 
-bool
-Layer::HasTransformAnimation() const
-{
-  for (uint32_t i = 0; i < mAnimations.Length(); i++) {
-    if (mAnimations[i].property() == eCSSProperty_transform) {
-      return true;
-    }
-  }
-  return false;
-}
-
 void
 Layer::ApplyPendingUpdatesForThisTransaction()
 {
   if (mPendingTransform && *mPendingTransform != mTransform) {
     MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
     mTransform = *mPendingTransform;
     Mutated();
   }
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1279,18 +1279,16 @@ public:
   // Note that all lengths in animation data are either in CSS pixels or app
   // units and must be converted to device pixels by the compositor.
   AnimationArray& GetAnimations() { return mAnimations; }
   InfallibleTArray<AnimData>& GetAnimationData() { return mAnimationData; }
 
   uint64_t GetAnimationGeneration() { return mAnimationGeneration; }
   void SetAnimationGeneration(uint64_t aCount) { mAnimationGeneration = aCount; }
 
-  bool HasTransformAnimation() const;
-
   /**
    * Returns the local transform for this layer: either mTransform or,
    * for shadow layers, GetShadowTransform()
    */
   const gfx::Matrix4x4 GetLocalTransform();
 
   /**
    * Returns the local opacity for this layer: either mOpacity or,
--- a/gfx/layers/apz/util/APZEventState.cpp
+++ b/gfx/layers/apz/util/APZEventState.cpp
@@ -8,16 +8,17 @@
 #include "ActiveElementManager.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/Preferences.h"
 #include "nsCOMPtr.h"
 #include "nsDocShell.h"
 #include "nsITimer.h"
 #include "nsIWeakReferenceUtils.h"
 #include "nsIWidget.h"
+#include "TouchManager.h"
 
 #define APZES_LOG(...)
 // #define APZES_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__)
 
 namespace mozilla {
 namespace layers {
 
 static int32_t sActiveDurationMs = 10;
@@ -184,17 +185,17 @@ void
 APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
                                  const ScrollableLayerGuid& aGuid,
                                  uint64_t aInputBlockId)
 {
   if (aEvent.message == NS_TOUCH_START && aEvent.touches.Length() > 0) {
     mActiveElementManager->SetTargetElement(aEvent.touches[0]->GetTarget());
   }
 
-  bool isTouchPrevented = nsIPresShell::gPreventMouseEvents ||
+  bool isTouchPrevented = TouchManager::gPreventMouseEvents ||
       aEvent.mFlags.mMultipleActionsPrevented;
   switch (aEvent.message) {
   case NS_TOUCH_START: {
     mTouchEndCancelled = false;
     if (mPendingTouchPreventedResponse) {
       // We can enter here if we get two TOUCH_STARTs in a row and didn't
       // respond to the first one. Respond to it now.
       mContentReceivedInputBlockCallback->Run(mPendingTouchPreventedGuid,
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp
+++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp
@@ -86,24 +86,21 @@ GetTransformToAncestorsParentLayer(Layer
       transform.PostScale(metrics.GetPresShellResolution(), metrics.GetPresShellResolution(), 1.f);
     }
   }
   return transform;
 }
 
 void
 ClientTiledPaintedLayer::GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
-                                           LayerMetricsWrapper* aOutDisplayPortAncestor,
-                                           bool* aOutHasTransformAnimation)
+                                          LayerMetricsWrapper* aOutDisplayPortAncestor)
 {
   LayerMetricsWrapper scrollAncestor;
   LayerMetricsWrapper displayPortAncestor;
-  bool hasTransformAnimation = false;
   for (LayerMetricsWrapper ancestor(this, LayerMetricsWrapper::StartAt::BOTTOM); ancestor; ancestor = ancestor.GetParent()) {
-    hasTransformAnimation |= ancestor.HasTransformAnimation();
     const FrameMetrics& metrics = ancestor.Metrics();
     if (!scrollAncestor && metrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID) {
       scrollAncestor = ancestor;
     }
     if (!metrics.GetDisplayPort().IsEmpty()) {
       displayPortAncestor = ancestor;
       // Any layer that has a displayport must be scrollable, so we can break
       // here.
@@ -111,19 +108,16 @@ ClientTiledPaintedLayer::GetAncestorLaye
     }
   }
   if (aOutScrollAncestor) {
     *aOutScrollAncestor = scrollAncestor;
   }
   if (aOutDisplayPortAncestor) {
     *aOutDisplayPortAncestor = displayPortAncestor;
   }
-  if (aOutHasTransformAnimation) {
-    *aOutHasTransformAnimation = hasTransformAnimation;
-  }
 }
 
 void
 ClientTiledPaintedLayer::BeginPaint()
 {
   mPaintData.mLowPrecisionPaintCount = 0;
   mPaintData.mPaintFinished = false;
   mPaintData.mCompositionBounds.SetEmpty();
@@ -135,53 +129,47 @@ ClientTiledPaintedLayer::BeginPaint()
     // given that it's a pretty rare scenario.
     return;
   }
 
   // Get the metrics of the nearest scrollable layer and the nearest layer
   // with a displayport.
   LayerMetricsWrapper scrollAncestor;
   LayerMetricsWrapper displayPortAncestor;
-  bool hasTransformAnimation;
-  GetAncestorLayers(&scrollAncestor, &displayPortAncestor, &hasTransformAnimation);
+  GetAncestorLayers(&scrollAncestor, &displayPortAncestor);
 
   if (!displayPortAncestor || !scrollAncestor) {
     // No displayport or scroll ancestor, so we can't do progressive rendering.
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_B2G)
     // Both Android and b2g are guaranteed to have a displayport set, so this
     // should never happen.
     NS_WARNING("Tiled PaintedLayer with no scrollable container ancestor");
 #endif
     return;
   }
 
-  TILING_LOG("TILING %p: Found scrollAncestor %p, displayPortAncestor %p, transform %d\n", this,
-    scrollAncestor.GetLayer(), displayPortAncestor.GetLayer(), hasTransformAnimation);
+  TILING_LOG("TILING %p: Found scrollAncestor %p and displayPortAncestor %p\n", this,
+    scrollAncestor.GetLayer(), displayPortAncestor.GetLayer());
 
   const FrameMetrics& scrollMetrics = scrollAncestor.Metrics();
   const FrameMetrics& displayportMetrics = displayPortAncestor.Metrics();
 
   // Calculate the transform required to convert ParentLayer space of our
   // display port ancestor to the Layer space of this layer.
   gfx::Matrix4x4 transformDisplayPortToLayer =
     GetTransformToAncestorsParentLayer(this, displayPortAncestor);
   transformDisplayPortToLayer.Invert();
 
   // Compute the critical display port that applies to this layer in the
-  // LayoutDevice space of this layer, but only if there is no OMT animation
-  // on this layer. If there is an OMT animation then we need to draw the whole
-  // visible region of this layer as determined by layout, because we don't know
-  // what parts of it might move into view in the compositor.
-  if (!hasTransformAnimation) {
-    ParentLayerRect criticalDisplayPort =
-      (displayportMetrics.GetCriticalDisplayPort() * displayportMetrics.GetZoom())
-      + displayportMetrics.mCompositionBounds.TopLeft();
-    mPaintData.mCriticalDisplayPort = RoundedOut(
-      ApplyParentLayerToLayerTransform(transformDisplayPortToLayer, criticalDisplayPort));
-  }
+  // LayoutDevice space of this layer.
+  ParentLayerRect criticalDisplayPort =
+    (displayportMetrics.GetCriticalDisplayPort() * displayportMetrics.GetZoom())
+    + displayportMetrics.mCompositionBounds.TopLeft();
+  mPaintData.mCriticalDisplayPort = RoundedOut(
+    ApplyParentLayerToLayerTransform(transformDisplayPortToLayer, criticalDisplayPort));
   TILING_LOG("TILING %p: Critical displayport %s\n", this, Stringify(mPaintData.mCriticalDisplayPort).c_str());
 
   // Store the resolution from the displayport ancestor layer. Because this is Gecko-side,
   // before any async transforms have occurred, we can use the zoom for this.
   mPaintData.mResolution = displayportMetrics.GetZoom();
   TILING_LOG("TILING %p: Resolution %f\n", this, mPaintData.mResolution.scale);
 
   // Store the applicable composition bounds in this layer's Layer units.
@@ -224,58 +212,61 @@ ClientTiledPaintedLayer::IsScrollingOnCo
                               aParentMetrics.GetScrollOffset().x,
                               COORDINATE_EPSILON) ||
          !FuzzyEqualsAdditive(compositorMetrics.GetScrollOffset().y,
                               aParentMetrics.GetScrollOffset().y,
                               COORDINATE_EPSILON);
 }
 
 bool
-ClientTiledPaintedLayer::UseProgressiveDraw() {
-  if (!gfxPlatform::GetPlatform()->UseProgressivePaint()) {
-    // pref is disabled, so never do progressive
-    return false;
-  }
-
-  if (ClientManager()->HasShadowTarget()) {
-    // This condition is true when we are in a reftest scenario. We don't want
-    // to draw progressively here because it can cause intermittent reftest
-    // failures because the harness won't wait for all the tiles to be drawn.
+ClientTiledPaintedLayer::UseFastPath()
+{
+  // The fast path doesn't allow rendering at low resolution. It will draw the low-res
+  // area at full resolution and cause OOM.
+  if (gfxPrefs::UseLowPrecisionBuffer()) {
     return false;
   }
 
-  if (mPaintData.mCriticalDisplayPort.IsEmpty()) {
-    // This catches three scenarios:
-    // 1) This layer doesn't have a scrolling ancestor
-    // 2) This layer is subject to OMTA transforms
-    // 3) Low-precision painting is disabled
-    // In all of these cases, we don't want to draw this layer progressively.
-    return false;
+  LayerMetricsWrapper scrollAncestor;
+  GetAncestorLayers(&scrollAncestor, nullptr);
+  if (!scrollAncestor) {
+    return true;
   }
+  const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
 
-  if (GetIsFixedPosition() || GetParent()->GetIsFixedPosition()) {
-    // This layer is fixed-position and so even if it does have a scrolling
-    // ancestor it will likely be entirely on-screen all the time, so we
-    // should draw it all at once
+  bool multipleTransactionsNeeded = gfxPlatform::GetPlatform()->UseProgressivePaint()
+                                 || !parentMetrics.GetCriticalDisplayPort().IsEmpty();
+  bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition();
+  bool isScrollable = parentMetrics.IsScrollable();
+
+  return !multipleTransactionsNeeded || isFixed || !isScrollable;
+}
+
+bool
+ClientTiledPaintedLayer::UseProgressiveDraw() {
+  // Don't draw progressively in a reftest scenario (that's what the HasShadowTarget() check is for).
+  if (!gfxPlatform::GetPlatform()->UseProgressivePaint() || ClientManager()->HasShadowTarget()) {
     return false;
   }
 
   // XXX We probably want to disable progressive drawing for non active APZ layers in the future
   //     but we should wait for a proper test case before making this change.
+
 #if 0 //!defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
   LayerMetricsWrapper scrollAncestor;
-  GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
-  MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is non-empty
+  GetAncestorLayers(&scrollAncestor, nullptr);
+  if (!scrollAncestor) {
+    return true;
+  }
   const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
-  if (!IsScrollingOnCompositor(parentMetrics)) {
-    return false;
-  }
+
+  return !IsScrollingOnCompositor(parentMetrics);
+#else
+  return true;
 #endif
-
-  return true;
 }
 
 bool
 ClientTiledPaintedLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion,
                                             const nsIntRegion& aVisibleRegion,
                                             LayerManager::DrawPaintedLayerCallback aCallback,
                                             void* aCallbackData)
 {
@@ -445,16 +436,26 @@ ClientTiledPaintedLayer::RenderLayer()
   }
 
   if (!ClientManager()->IsRepeatTransaction()) {
     // Only paint the mask layer on the first transaction.
     if (GetMaskLayer()) {
       ToClientLayer(GetMaskLayer())->RenderLayer();
     }
 
+    // In some cases we can take a fast path and just be done with it.
+    if (UseFastPath()) {
+      TILING_LOG("TILING %p: Taking fast-path\n", this);
+      mValidRegion = neededRegion;
+      mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, callback, data);
+      ClientManager()->Hold(this);
+      mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
+      return;
+    }
+
     // For more complex cases we need to calculate a bunch of metrics before we
     // can do the paint.
     BeginPaint();
     if (mPaintData.mPaintFinished) {
       return;
     }
 
     // Make sure that tiles that fall outside of the visible region or outside of the
--- a/gfx/layers/client/ClientTiledPaintedLayer.h
+++ b/gfx/layers/client/ClientTiledPaintedLayer.h
@@ -76,32 +76,37 @@ public:
   virtual void ClearCachedResources() MOZ_OVERRIDE;
 
   /**
    * Helper method to find the nearest ancestor layers which
    * scroll and have a displayport. The parameters are out-params
    * which hold the return values; the values passed in may be null.
    */
   void GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
-                         LayerMetricsWrapper* aOutDisplayPortAncestor,
-                         bool* aOutHasTransformAnimation);
+                         LayerMetricsWrapper* aOutDisplayPortAncestor);
 
 private:
   ClientLayerManager* ClientManager()
   {
     return static_cast<ClientLayerManager*>(mManager);
   }
 
   /**
    * For the initial PaintThebes of a transaction, calculates all the data
    * needed for that paint and any repeated transactions.
    */
   void BeginPaint();
 
   /**
+   * Determine if we can use a fast path to just do a single high-precision,
+   * non-progressive paint.
+   */
+  bool UseFastPath();
+
+  /**
    * Check if the layer is being scrolled by APZ on the compositor.
    */
   bool IsScrollingOnCompositor(const FrameMetrics& aParentMetrics);
 
   /**
    * Check if we should use progressive draw on this layer. We will
    * disable progressive draw based on a preference or if the layer
    * is not being scrolled.
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -1355,17 +1355,17 @@ ClientTiledLayerBuffer::ComputeProgressi
 
   // Find out if we have any non-stale content to update.
   nsIntRegion staleRegion;
   staleRegion.And(aInvalidRegion, aOldValidRegion);
 
   TILING_LOG("TILING %p: Progressive update stale region %s\n", mPaintedLayer, Stringify(staleRegion).c_str());
 
   LayerMetricsWrapper scrollAncestor;
-  mPaintedLayer->GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
+  mPaintedLayer->GetAncestorLayers(&scrollAncestor, nullptr);
 
   // Find out the current view transform to determine which tiles to draw
   // first, and see if we should just abort this paint. Aborting is usually
   // caused by there being an incoming, more relevant paint.
   ViewTransform viewTransform;
 #if defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_ANDROID_APZ)
   FrameMetrics contentMetrics = scrollAncestor.Metrics();
   bool abortPaint = false;
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -354,16 +354,17 @@ IPDL_SOURCES = [
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/docshell/base',  # for nsDocShell.h
+    '/layout/base',    # for TouchManager.h
 ]
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['MOZ_DEBUG']:
     DEFINES['D3D_DEBUG_INFO'] = True
 
 if CONFIG['MOZ_ENABLE_D3D10_LAYER']:
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -286,21 +286,23 @@ class APZCGestureDetectorTester : public
 public:
   APZCGestureDetectorTester()
     : APZCBasicTester(AsyncPanZoomController::USE_GESTURE_DETECTOR)
   {
   }
 };
 
 /* The InputReceiver template parameter used in the helper functions below needs
- * to be a class that implements a function with the signature:
+ * to be a class that implements functions with the signatures:
  * nsEventStatus ReceiveInputEvent(const InputData& aEvent,
  *                                 ScrollableLayerGuid* aGuid,
  *                                 uint64_t* aOutInputBlockId);
- * The classes that currently implement this are APZCTreeManager and
+ * void SetAllowedTouchBehavior(uint64_t aInputBlockId,
+ *                              const nsTArray<uint32_t>& aBehaviours);
+ * The classes that currently implement these are APZCTreeManager and
  * TestAsyncPanZoomController. Using this template allows us to test individual
  * APZC instances in isolation and also an entire APZ tree, while using the same
  * code to dispatch input events.
  */
 
 // Some helper functions for constructing input event objects suitable to be
 // passed either to an APZC (which expects an transformed point), or to an APZTM
 // (which expects an untransformed point). We handle both cases by setting both
@@ -318,16 +320,32 @@ CreatePinchGestureInput(PinchGestureInpu
                         float aCurrentSpan, float aPreviousSpan)
 {
   PinchGestureInput result(aType, 0, TimeStamp(), ScreenPoint(aFocusX, aFocusY),
                            aCurrentSpan, aPreviousSpan, 0);
   result.mLocalFocusPoint = ParentLayerPoint(aFocusX, aFocusY);
   return result;
 }
 
+template<class InputReceiver> static void
+SetDefaultAllowedTouchBehavior(const nsRefPtr<InputReceiver>& aTarget,
+                               uint64_t aInputBlockId,
+                               int touchPoints = 1)
+{
+  nsTArray<uint32_t> defaultBehaviors;
+  // use the default value where everything is allowed
+  for (int i = 0; i < touchPoints; i++) {
+    defaultBehaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
+                                 | mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
+                                 | mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM
+                                 | mozilla::layers::AllowedTouchBehavior::DOUBLE_TAP_ZOOM);
+  }
+  aTarget->SetAllowedTouchBehavior(aInputBlockId, defaultBehaviors);
+}
+
 template<class InputReceiver> static nsEventStatus
 TouchDown(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY, int aTime, uint64_t* aOutInputBlockId = nullptr)
 {
   MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, aTime, TimeStamp(), 0);
   mti.mTouches.AppendElement(CreateSingleTouchData(0, aX, aY));
   return aTarget->ReceiveInputEvent(mti, nullptr, aOutInputBlockId);
 }
 
@@ -347,21 +365,35 @@ TouchUp(const nsRefPtr<InputReceiver>& a
   return aTarget->ReceiveInputEvent(mti, nullptr, nullptr);
 }
 
 template<class InputReceiver> static void
 Tap(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY, int& aTime, int aTapLength,
     nsEventStatus (*aOutEventStatuses)[2] = nullptr,
     uint64_t* aOutInputBlockId = nullptr)
 {
+  // Even if the caller doesn't care about the block id, we need it to set the
+  // allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
+  uint64_t blockId;
+  if (!aOutInputBlockId) {
+    aOutInputBlockId = &blockId;
+  }
+
   nsEventStatus status = TouchDown(aTarget, aX, aY, aTime, aOutInputBlockId);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[0] = status;
   }
   aTime += aTapLength;
+
+  // If touch-action is enabled then simulate the allowed touch behaviour
+  // notification that the main thread is supposed to deliver.
+  if (gfxPrefs::TouchActionEnabled()) {
+    SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId);
+  }
+
   status = TouchUp(aTarget, aX, aY, aTime);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[1] = status;
   }
 }
 
 template<class InputReceiver> static void
 TapAndCheckStatus(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY, int& aTime, int aTapLength)
@@ -402,18 +434,21 @@ Pan(const nsRefPtr<InputReceiver>& aTarg
   nsEventStatus status = TouchDown(aTarget, 10, aTouchStartY + OVERCOME_TOUCH_TOLERANCE, aTime, aOutInputBlockId);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[0] = status;
   }
 
   aTime += TIME_BETWEEN_TOUCH_EVENT;
 
   // Allowed touch behaviours must be set after sending touch-start.
-  if (gfxPrefs::TouchActionEnabled() && aAllowedTouchBehaviors) {
+  if (aAllowedTouchBehaviors) {
+    EXPECT_EQ(1UL, aAllowedTouchBehaviors->Length());
     aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors);
+  } else if (gfxPrefs::TouchActionEnabled()) {
+    SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId);
   }
 
   status = TouchMove(aTarget, 10, aTouchStartY, aTime);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[1] = status;
   }
 
   aTime += TIME_BETWEEN_TOUCH_EVENT;
@@ -544,18 +579,21 @@ PinchWithTouchInput(const nsRefPtr<Input
   MultiTouchInput mtiStart = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
   mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocusX, aFocusY));
   mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocusX, aFocusY));
   nsEventStatus status = aTarget->ReceiveInputEvent(mtiStart, aOutInputBlockId);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[0] = status;
   }
 
-  if (gfxPrefs::TouchActionEnabled() && aAllowedTouchBehaviors) {
+  if (aAllowedTouchBehaviors) {
+    EXPECT_EQ(2UL, aAllowedTouchBehaviors->Length());
     aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors);
+  } else if (gfxPrefs::TouchActionEnabled()) {
+    SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId, 2);
   }
 
   MultiTouchInput mtiMove1 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
   mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocusX - pinchLength, aFocusY));
   mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocusX + pinchLength, aFocusY));
   status = aTarget->ReceiveInputEvent(mtiMove1, nullptr);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[1] = status;
@@ -684,20 +722,22 @@ class APZCPinchGestureDetectorTester : p
 public:
   APZCPinchGestureDetectorTester()
     : APZCPinchTester(AsyncPanZoomController::USE_GESTURE_DETECTOR)
   {
   }
 };
 
 TEST_F(APZCPinchTester, Pinch_DefaultGestures_NoTouchAction) {
+  SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
   DoPinchTest(true);
 }
 
 TEST_F(APZCPinchGestureDetectorTester, Pinch_UseGestureDetector_NoTouchAction) {
+  SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
   DoPinchTest(true);
 }
 
 TEST_F(APZCPinchGestureDetectorTester, Pinch_UseGestureDetector_TouchActionNone) {
   SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
   nsTArray<uint32_t> behaviors;
   behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::NONE);
   behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::NONE);
@@ -953,16 +993,17 @@ protected:
     EXPECT_EQ(ParentLayerPoint(), pointOut);
     EXPECT_EQ(ViewTransform(), viewTransformOut);
 
     apzc->AssertStateIsReset();
   }
 };
 
 TEST_F(APZCPanningTester, Pan) {
+  SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
   DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::NONE);
 }
 
 // In the each of the following 4 pan tests we are performing two pan gestures: vertical pan from top
 // to bottom and back - from bottom to top.
 // According to the pointer-events/touch-action spec AUTO and PAN_Y touch-action values allow vertical
 // scrolling while NONE and PAN_X forbid it. The first parameter of DoPanTest method specifies this
 // behavior.
@@ -1446,27 +1487,29 @@ protected:
     EXPECT_EQ(ParentLayerPoint(), pointOut);
     EXPECT_EQ(ViewTransform(), viewTransformOut);
 
     apzc->AssertStateIsReset();
   }
 };
 
 TEST_F(APZCLongPressTester, LongPress) {
+  SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
   DoLongPressTest(mozilla::layers::AllowedTouchBehavior::NONE);
 }
 
 TEST_F(APZCLongPressTester, LongPressWithTouchAction) {
   SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
   DoLongPressTest(mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
                   | mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
                   | mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
 }
 
 TEST_F(APZCLongPressTester, LongPressPreventDefault) {
+  SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
   DoLongPressPreventDefaultTest(mozilla::layers::AllowedTouchBehavior::NONE);
 }
 
 TEST_F(APZCLongPressTester, LongPressPreventDefaultWithTouchAction) {
   SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
   DoLongPressPreventDefaultTest(mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
                                 | mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
                                 | mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
@@ -1481,29 +1524,41 @@ DoubleTap(const nsRefPtr<InputReceiver>&
   nsEventStatus status = TouchDown(aTarget, aX, aY, aTime, &blockId);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[0] = status;
   }
   if (aOutInputBlockIds) {
     (*aOutInputBlockIds)[0] = blockId;
   }
   aTime += 10;
+
+  // If touch-action is enabled then simulate the allowed touch behaviour
+  // notification that the main thread is supposed to deliver.
+  if (gfxPrefs::TouchActionEnabled()) {
+    SetDefaultAllowedTouchBehavior(aTarget, blockId);
+  }
+
   status = TouchUp(aTarget, aX, aY, aTime);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[1] = status;
   }
   aTime += 10;
   status = TouchDown(aTarget, aX, aY, aTime, &blockId);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[2] = status;
   }
   if (aOutInputBlockIds) {
     (*aOutInputBlockIds)[1] = blockId;
   }
   aTime += 10;
+
+  if (gfxPrefs::TouchActionEnabled()) {
+    SetDefaultAllowedTouchBehavior(aTarget, blockId);
+  }
+
   status = TouchUp(aTarget, aX, aY, aTime);
   if (aOutEventStatuses) {
     (*aOutEventStatuses)[3] = status;
   }
 }
 
 template<class InputReceiver> static void
 DoubleTapAndCheckStatus(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY, int& aTime, uint64_t (*aOutInputBlockIds)[2] = nullptr)
@@ -2128,16 +2183,18 @@ TEST_F(APZHitTestingTester, ComplexMulti
   EXPECT_EQ(ApzcOf(layers[1]), hit.get());
   hit = GetTargetAPZC(ScreenPoint(275, 375));
   EXPECT_EQ(ApzcOf(layers[9]), hit.get());
   hit = GetTargetAPZC(ScreenPoint(250, 100));
   EXPECT_EQ(ApzcOf(layers[7]), hit.get());
 }
 
 TEST_F(APZHitTestingTester, TestRepaintFlushOnNewInputBlock) {
+  SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
+
   // The main purpose of this test is to verify that touch-start events (or anything
   // that starts a new input block) don't ever get untransformed. This should always
   // hold because the APZ code should flush repaints when we start a new input block
   // and the transform to gecko space should be empty.
 
   CreateSimpleScrollingLayer();
   ScopedLayerTreeRegistration registration(0, root, mcc);
   manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -858,24 +858,22 @@ SetAlarm(int32_t aSeconds, int32_t aNano
   // It's pointless to program an alarm nothing is going to observe ...
   MOZ_ASSERT(sAlarmObserver);
   RETURN_PROXY_IF_SANDBOXED(SetAlarm(aSeconds, aNanoseconds), false);
 }
 
 void
 SetProcessPriority(int aPid,
                    ProcessPriority aPriority,
-                   ProcessCPUPriority aCPUPriority,
                    uint32_t aBackgroundLRU)
 {
   // n.b. The sandboxed implementation crashes; SetProcessPriority works only
   // from the main process.
   MOZ_ASSERT(aBackgroundLRU == 0 || aPriority == PROCESS_PRIORITY_BACKGROUND);
-  PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority, aCPUPriority,
-                                        aBackgroundLRU));
+  PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority, aBackgroundLRU));
 }
 
 void
 SetCurrentThreadPriority(hal::ThreadPriority aThreadPriority)
 {
   PROXY_IF_SANDBOXED(SetCurrentThreadPriority(aThreadPriority));
 }
 
@@ -915,99 +913,16 @@ ThreadPriorityToString(ThreadPriority aP
     case THREAD_PRIORITY_COMPOSITOR:
       return "COMPOSITOR";
     default:
       MOZ_ASSERT(false);
       return "???";
   }
 }
 
-// From HalTypes.h.
-const char*
-ProcessPriorityToString(Process