Merge m-c to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 01 Oct 2014 15:37:54 +0200
changeset 208171 a68bd654661c3942a1e84147cd2c75c60bdc89b1
parent 208170 5b0fb54a17c62c8fe4ac463e1b2b9e498b6d53cd (current diff)
parent 208159 835ef55e175e82b47aa5fd1f71aeda7e89d5ebd6 (diff)
child 208172 b2d50b8f8b5a96c4dcdb3921545d32cfe0d43a53
push id27579
push userkwierso@gmail.com
push dateWed, 01 Oct 2014 23:02:13 +0000
treeherderautoland@f771fd927304 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone35.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
accessible/ipc/DocAccessibleChild.cpp
accessible/ipc/DocAccessibleChild.h
accessible/ipc/DocAccessibleParent.cpp
accessible/ipc/DocAccessibleParent.h
accessible/ipc/PDocAccessible.ipdl
accessible/ipc/ProxyAccessible.cpp
accessible/ipc/ProxyAccessible.h
accessible/ipc/moz.build
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
media/libnestegg/README
testing/web-platform/meta/performance-timeline/idlharness.html.ini
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -7,26 +7,24 @@
 #include "AccessibleWrap.h"
 
 #include "Accessible-inl.h"
 #include "ApplicationAccessibleWrap.h"
 #include "InterfaceInitFuncs.h"
 #include "nsAccUtils.h"
 #include "nsIAccessibleRelation.h"
 #include "nsIAccessibleTable.h"
-#include "ProxyAccessible.h"
 #include "RootAccessible.h"
 #include "nsIAccessibleValue.h"
 #include "nsMai.h"
 #include "nsMaiHyperlink.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "prprf.h"
 #include "nsStateMap.h"
-#include "mozilla/a11y/Platform.h"
 #include "Relation.h"
 #include "RootAccessible.h"
 #include "States.h"
 #include "nsISimpleEnumerator.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "nsXPCOMStrings.h"
 #include "nsComponentManagerUtils.h"
@@ -130,23 +128,19 @@ static const GInterfaceInfo atk_if_infos
  */
 struct MaiAtkObject
 {
   AtkObject parent;
   /*
    * The AccessibleWrap whose properties and features are exported
    * via this object instance.
    */
-  uintptr_t accWrap;
+  AccessibleWrap* accWrap;
 };
 
-// This is or'd with the pointer in MaiAtkObject::accWrap if the wrap-ee is a
-// proxy.
-static const uintptr_t IS_PROXY = 1;
-
 struct MaiAtkObjectClass
 {
     AtkObjectClass parent_class;
 };
 
 static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
 
 static void MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName);
@@ -249,17 +243,17 @@ AccessibleWrap::~AccessibleWrap()
     NS_ASSERTION(!mAtkObject, "ShutdownAtkObject() is not called");
 }
 
 void
 AccessibleWrap::ShutdownAtkObject()
 {
     if (mAtkObject) {
         if (IS_MAI_OBJECT(mAtkObject)) {
-            MAI_ATK_OBJECT(mAtkObject)->accWrap = 0;
+            MAI_ATK_OBJECT(mAtkObject)->accWrap = nullptr;
         }
         SetMaiHyperlink(nullptr);
         g_object_unref(mAtkObject);
         mAtkObject = nullptr;
     }
 }
 
 void
@@ -583,25 +577,26 @@ initializeCB(AtkObject *aAtkObj, gpointe
     /* AtkObjectClass has not a "initialize" function now,
      * maybe it has later
      */
 
     if (ATK_OBJECT_CLASS(parent_class)->initialize)
         ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
 
   /* initialize object */
-  MAI_ATK_OBJECT(aAtkObj)->accWrap = reinterpret_cast<uintptr_t>(aData);
+  MAI_ATK_OBJECT(aAtkObj)->accWrap =
+    static_cast<AccessibleWrap*>(aData);
 }
 
 void
 finalizeCB(GObject *aObj)
 {
     if (!IS_MAI_OBJECT(aObj))
         return;
-    NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == 0, "AccWrap NOT null");
+    NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == nullptr, "AccWrap NOT null");
 
     // call parent finalize function
     // finalize of GObjectClass will unref the accessible parent if has
     if (G_OBJECT_CLASS (parent_class)->finalize)
         G_OBJECT_CLASS (parent_class)->finalize(aObj);
 }
 
 const gchar*
@@ -663,43 +658,35 @@ getDescriptionCB(AtkObject *aAtkObj)
                                    NS_ConvertUTF16toUTF8(uniDesc).get());
 
     return aAtkObj->description;
 }
 
 AtkRole
 getRoleCB(AtkObject *aAtkObj)
 {
+  AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+  if (!accWrap)
+    return ATK_ROLE_INVALID;
+
+#ifdef DEBUG
+  NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
+      "Does not support nsIAccessibleText when it should");
+#endif
+
   if (aAtkObj->role != ATK_ROLE_INVALID)
     return aAtkObj->role;
 
-  AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
-  a11y::role role;
-  if (!accWrap) {
-    ProxyAccessible* proxy = GetProxy(aAtkObj);
-    if (!proxy)
-      return ATK_ROLE_INVALID;
-
-    role = proxy->Role();
-  } else {
-#ifdef DEBUG
-    NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
-                 "Does not support nsIAccessibleText when it should");
-#endif
-
-    role = accWrap->Role();
-  }
-
 #define ROLE(geckoRole, stringRole, atkRole, macRole, \
              msaaRole, ia2Role, nameRule) \
   case roles::geckoRole: \
     aAtkObj->role = atkRole; \
     break;
 
-  switch (role) {
+  switch (accWrap->Role()) {
 #include "RoleMap.h"
     default:
       MOZ_CRASH("Unknown role.");
   };
 
 #undef ROLE
 
   if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1))
@@ -954,80 +941,31 @@ refRelationSetCB(AtkObject *aAtkObj)
 }
 
 // Check if aAtkObj is a valid MaiAtkObject, and return the AccessibleWrap
 // for it.
 AccessibleWrap*
 GetAccessibleWrap(AtkObject* aAtkObj)
 {
   NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nullptr);
-
-  // Make sure its native is an AccessibleWrap not a proxy.
-  if (MAI_ATK_OBJECT(aAtkObj)->accWrap & IS_PROXY)
-    return nullptr;
-
-    AccessibleWrap* accWrap =
-      reinterpret_cast<AccessibleWrap*>(MAI_ATK_OBJECT(aAtkObj)->accWrap);
+  AccessibleWrap* accWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap;
 
   // Check if the accessible was deconstructed.
   if (!accWrap)
     return nullptr;
 
   NS_ENSURE_TRUE(accWrap->GetAtkObject() == aAtkObj, nullptr);
 
   AccessibleWrap* appAccWrap = ApplicationAcc();
   if (appAccWrap != accWrap && !accWrap->IsValidObject())
     return nullptr;
 
   return accWrap;
 }
 
-ProxyAccessible*
-GetProxy(AtkObject* aObj)
-{
-  if (!aObj || !(MAI_ATK_OBJECT(aObj)->accWrap & IS_PROXY))
-    return nullptr;
-
-  return reinterpret_cast<ProxyAccessible*>(MAI_ATK_OBJECT(aObj)->accWrap
-      & ~IS_PROXY);
-}
-
-static uint16_t
-GetInterfacesForProxy(ProxyAccessible* aProxy)
-{
-  return MAI_INTERFACE_COMPONENT;
-}
-
-void
-a11y::ProxyCreated(ProxyAccessible* aProxy)
-{
-  GType type = GetMaiAtkType(GetInterfacesForProxy(aProxy));
-  NS_ASSERTION(type, "why don't we have a type!");
-
-  AtkObject* obj =
-    reinterpret_cast<AtkObject *>
-    (g_object_new(type, nullptr));
-  if (!obj)
-    return;
-
-  atk_object_initialize(obj, aProxy);
-  obj->role = ATK_ROLE_INVALID;
-  obj->layer = ATK_LAYER_INVALID;
-  aProxy->SetWrapper(reinterpret_cast<uintptr_t>(obj) | IS_PROXY);
-}
-
-void
-a11y::ProxyDestroyed(ProxyAccessible* aProxy)
-{
-  auto obj = reinterpret_cast<MaiAtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
-  obj->accWrap = 0;
-  g_object_unref(obj);
-  aProxy->SetWrapper(0);
-}
-
 nsresult
 AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
 {
   nsresult rv = Accessible::HandleAccEvent(aEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
     Accessible* accessible = aEvent->GetAccessible();
     NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
--- a/accessible/atk/AccessibleWrap.h
+++ b/accessible/atk/AccessibleWrap.h
@@ -92,15 +92,15 @@ private:
   enum EAvailableAtkSignals {
     eUnknown,
     eHaveNewAtkTextSignals,
     eNoNewAtkSignals
   };
 
   static EAvailableAtkSignals gAvailableAtkSignals;
 
-  uint16_t CreateMaiInterfaces();
+  uint16_t CreateMaiInterfaces(void);
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif /* __NS_ACCESSIBLE_WRAP_H__ */
--- a/accessible/atk/moz.build
+++ b/accessible/atk/moz.build
@@ -30,17 +30,16 @@ SOURCES += [
     'RootAccessibleWrap.cpp',
     'UtilInterface.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/accessible/base',
     '/accessible/generic',
     '/accessible/html',
-    '/accessible/ipc',
     '/accessible/xpcom',
     '/accessible/xul',
     '/other-licenses/atk-1.0',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['MOZ_ENABLE_GTK']:
--- a/accessible/atk/nsMai.h
+++ b/accessible/atk/nsMai.h
@@ -8,39 +8,32 @@
 #define __NS_MAI_H__
 
 #include <atk/atk.h>
 #include <glib.h>
 #include <glib-object.h>
 
 #include "AccessibleWrap.h"
 
-namespace mozilla {
-namespace a11y {
-class ProxyAccessible;
-}
-}
-
 #define MAI_TYPE_ATK_OBJECT             (mai_atk_object_get_type ())
 #define MAI_ATK_OBJECT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
                                          MAI_TYPE_ATK_OBJECT, MaiAtkObject))
 #define MAI_ATK_OBJECT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), \
                                          MAI_TYPE_ATK_OBJECT, \
                                          MaiAtkObjectClass))
 #define IS_MAI_OBJECT(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
                                          MAI_TYPE_ATK_OBJECT))
 #define IS_MAI_OBJECT_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), \
                                          MAI_TYPE_ATK_OBJECT))
 #define MAI_ATK_OBJECT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), \
                                          MAI_TYPE_ATK_OBJECT, \
                                          MaiAtkObjectClass))
 GType mai_atk_object_get_type(void);
 GType mai_util_get_type();
 mozilla::a11y::AccessibleWrap* GetAccessibleWrap(AtkObject* aAtkObj);
-mozilla::a11y::ProxyAccessible* GetProxy(AtkObject* aAtkObj);
 
 extern int atkMajorVersion, atkMinorVersion;
 
 /**
  * Return true if the loaded version of libatk-1.0.so is at least
  * aMajor.aMinor.0.
  */
 static inline bool
--- a/accessible/base/AccEvent.h
+++ b/accessible/base/AccEvent.h
@@ -227,18 +227,16 @@ public:
   {
     return AccEvent::GetEventGroups() | (1U << eMutationEvent);
   }
 
   // MutationEvent
   bool IsShow() const { return mEventType == nsIAccessibleEvent::EVENT_SHOW; }
   bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; }
 
-  Accessible* Parent() const { return mParent; }
-
 protected:
   nsCOMPtr<nsINode> mNode;
   nsRefPtr<Accessible> mParent;
   nsRefPtr<AccTextChangeEvent> mTextChangeEvent;
 
   friend class EventQueue;
 };
 
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DocManager.h"
 
 #include "ApplicationAccessible.h"
 #include "ARIAMap.h"
 #include "DocAccessible-inl.h"
-#include "DocAccessibleChild.h"
 #include "nsAccessibilityService.h"
 #include "RootAccessibleWrap.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 #include "mozilla/EventListenerManager.h"
@@ -23,18 +22,16 @@
 #include "nsIChannel.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIWebNavigation.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIWebProgress.h"
 #include "nsCoreUtils.h"
-#include "nsXULAppAPI.h"
-#include "mozilla/dom/ContentChild.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using namespace mozilla::dom;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager
 ////////////////////////////////////////////////////////////////////////////////
@@ -416,22 +413,16 @@ DocManager::CreateDocOrRootAccessible(ns
     // the tree. The reorder event is delivered after the document tree is
     // constructed because event processing and tree construction are done by
     // the same document.
     // Note: don't use AccReorderEvent to avoid coalsecense and special reorder
     // events processing.
     docAcc->FireDelayedEvent(nsIAccessibleEvent::EVENT_REORDER,
                              ApplicationAcc());
 
-    if (XRE_GetProcessType() != GeckoProcessType_Default) {
-      DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
-      docAcc->SetIPCDoc(ipcDoc);
-    auto contentChild = dom::ContentChild::GetSingleton();
-    contentChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
-    }
   } else {
     parentDocAcc->BindChildDocument(docAcc);
   }
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eDocCreate)) {
     logging::DocCreate("document creation finished", aDocument);
     logging::Stack();
--- a/accessible/base/DocManager.h
+++ b/accessible/base/DocManager.h
@@ -12,17 +12,16 @@
 #include "nsWeakReference.h"
 #include "nsIPresShell.h"
 
 namespace mozilla {
 namespace a11y {
 
 class Accessible;
 class DocAccessible;
-class DocAccessibleParent;
 
 /**
  * Manage the document accessible life cycle.
  */
 class DocManager : public nsIWebProgressListener,
                    public nsIDOMEventListener,
                    public nsSupportsWeakReference
 {
@@ -61,35 +60,16 @@ public:
    * Called by document accessible when it gets shutdown.
    */
   inline void NotifyOfDocumentShutdown(nsIDocument* aDocument)
   {
     mDocAccessibleCache.Remove(aDocument);
     RemoveListeners(aDocument);
   }
 
-  /*
-   * Notification that a top level document in a content process has gone away.
-   */
-  void RemoteDocShutdown(DocAccessibleParent* aDoc)
-  {
-    DebugOnly<bool> result = mRemoteDocuments.RemoveElement(aDoc);
-    MOZ_ASSERT(result, "Why didn't we find the document!");
-  }
-
-  /*
-   * Notify of a new top level document in a content process.
-   */
-  void RemoteDocAdded(DocAccessibleParent* aDoc)
-  {
-    MOZ_ASSERT(!mRemoteDocuments.Contains(aDoc),
-               "How did we already have the doc!");
-    mRemoteDocuments.AppendElement(aDoc);
-  }
-
 #ifdef DEBUG
   bool IsProcessingRefreshDriverNotification() const;
 #endif
 
 protected:
   DocManager();
   virtual ~DocManager() { }
 
@@ -159,21 +139,16 @@ private:
 
 #ifdef DEBUG
   static PLDHashOperator
     SearchIfDocIsRefreshing(const nsIDocument* aKey,
                             DocAccessible* aDocAccessible, void* aUserArg);
 #endif
 
   DocAccessibleHashtable mDocAccessibleCache;
-
-  /*
-   * The list of remote top level documents.
-   */
-  nsTArray<DocAccessibleParent*> mRemoteDocuments;
 };
 
 /**
  * Return the existing document accessible for the document if any.
  * Note this returns the doc accessible for the primary pres shell if there is
  * more than one.
  */
 inline DocAccessible*
--- a/accessible/base/EventQueue.cpp
+++ b/accessible/base/EventQueue.cpp
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "EventQueue.h"
 
 #include "Accessible-inl.h"
 #include "nsEventShell.h"
 #include "DocAccessible.h"
-#include "DocAccessibleChild.h"
 #include "nsAccessibilityService.h"
 #include "nsTextEquivUtils.h"
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::a11y;
@@ -551,20 +550,10 @@ EventQueue::ProcessEventQueue()
       }
     }
 
     if (event->mEventType == nsIAccessibleEvent::EVENT_HIDE)
       mDocument->ShutdownChildrenInSubtree(event->mAccessible);
 
     if (!mDocument)
       return;
-
-    if (XRE_GetProcessType() != GeckoProcessType_Default) {
-    DocAccessibleChild* ipcDoc = mDocument->IPCDoc();
-      if (event->mEventType == nsIAccessibleEvent::EVENT_SHOW)
-        ipcDoc->ShowEvent(downcast_accEvent(event));
-      else if (event->mEventType == nsIAccessibleEvent::EVENT_HIDE)
-        ipcDoc->SendHideEvent(reinterpret_cast<uintptr_t>(event->GetAccessible()));
-      else
-        ipcDoc->SendEvent(event->GetEventType());
-    }
   }
 }
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -1,21 +1,19 @@
 /* -*- 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 "NotificationController.h"
 
 #include "DocAccessible-inl.h"
-#include "DocAccessibleChild.h"
 #include "TextLeafAccessible.h"
 #include "TextUpdater.h"
 
-#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Telemetry.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector
@@ -214,29 +212,18 @@ NotificationController::WillRefresh(mozi
     if (childDoc->IsDefunct())
       continue;
 
     nsIContent* ownerContent = mDocument->DocumentNode()->
       FindContentForSubDocument(childDoc->DocumentNode());
     if (ownerContent) {
       Accessible* outerDocAcc = mDocument->GetAccessible(ownerContent);
       if (outerDocAcc && outerDocAcc->AppendChild(childDoc)) {
-        if (mDocument->AppendChildDocument(childDoc)) {
-          if (XRE_GetProcessType() != GeckoProcessType_Default) {
-            DocAccessibleChild* ipcDoc = new DocAccessibleChild(childDoc);
-            childDoc->SetIPCDoc(ipcDoc);
-            auto contentChild = dom::ContentChild::GetSingleton();
-            DocAccessibleChild* parentIPCDoc = mDocument->IPCDoc();
-            uint64_t id = reinterpret_cast<uintptr_t>(outerDocAcc->UniqueID());
-            contentChild->SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc,
-                                                        id);
-          }
-
+        if (mDocument->AppendChildDocument(childDoc))
           continue;
-        }
 
         outerDocAcc->RemoveChild(childDoc);
       }
 
       // Failed to bind the child document, destroy it.
       childDoc->Shutdown();
     }
   }
--- a/accessible/base/Platform.h
+++ b/accessible/base/Platform.h
@@ -2,18 +2,16 @@
 /* vim: set ts=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/. */
 
 namespace mozilla {
 namespace a11y {
 
-class ProxyAccessible;
-
 enum EPlatformDisabledState {
   ePlatformIsForceEnabled = -1,
   ePlatformIsEnabled = 0,
   ePlatformIsDisabled = 1
 };
 
 /**
  * Return the platform disabled state.
@@ -44,22 +42,11 @@ bool ShouldA11yBeEnabled();
 void PlatformInit();
 
 /**
  * Shutdown platform accessibility.
  * Note this is called before internal accessibility support is shutdown.
  */
 void PlatformShutdown();
 
-/**
- * called when a new ProxyAccessible is created, so the platform may setup a
- * wrapper for it, or take other action.
- */
-void ProxyCreated(ProxyAccessible*);
-
-/**
- * Called just before a ProxyAccessible is destroyed so its wrapper can be
- * disposed of and other action taken.
- */
-void ProxyDestroyed(ProxyAccessible*);
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/base/Role.h
+++ b/accessible/base/Role.h
@@ -778,19 +778,17 @@ enum Role {
   /**
    * Represent a definition in a definition list (dd in HTML)
    */
   DEFINITION = 128,
 
   /**
    * Represent a keyboard or keypad key (ARIA role "key").
    */
-  KEY = 129,
-
-  LAST_ROLE = KEY
+  KEY = 129
 };
 
 } // namespace role
 
 typedef enum mozilla::a11y::roles::Role role;
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/base/moz.build
+++ b/accessible/base/moz.build
@@ -55,17 +55,16 @@ UNIFIED_SOURCES += [
 if CONFIG['A11Y_LOG']:
     UNIFIED_SOURCES += [
         'Logging.cpp',
     ]
 
 LOCAL_INCLUDES += [
     '/accessible/generic',
     '/accessible/html',
-    '/accessible/ipc',
     '/accessible/xpcom',
     '/accessible/xul',
     '/dom/xbl',
     '/ipc/chromium/src',
     '/layout/generic',
     '/layout/style',
     '/layout/svg',
     '/layout/xul',
@@ -89,10 +88,8 @@ else:
     LOCAL_INCLUDES += [
         '/accessible/other',
     ]
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['MOZ_ENABLE_GTK']:
     CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
-
-include('/ipc/chromium/chromium-config.mozbuild')
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Accessible-inl.h"
 #include "AccIterator.h"
 #include "DocAccessible-inl.h"
-#include "DocAccessibleChild.h"
 #include "HTMLImageMapAccessible.h"
 #include "nsAccCache.h"
 #include "nsAccessiblePivot.h"
 #include "nsAccUtils.h"
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
 #include "Role.h"
 #include "RootAccessible.h"
@@ -79,17 +78,17 @@ DocAccessible::
   HyperTextAccessibleWrap(aRootContent, this), xpcAccessibleDocument(),
   // XXX aaronl should we use an algorithm for the initial cache size?
   mAccessibleCache(kDefaultCacheLength),
   mNodeToAccessibleMap(kDefaultCacheLength),
   mDocumentNode(aDocument),
   mScrollPositionChangedTicks(0),
   mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0),
   mVirtualCursor(nullptr),
-  mPresShell(aPresShell), mIPCDoc(nullptr)
+  mPresShell(aPresShell)
 {
   mGenericTypes |= eDocument;
   mStateFlags |= eNotNodeMapEntry;
 
   MOZ_ASSERT(mPresShell, "should have been given a pres shell");
   mPresShell->SetDocAccessible(this);
 
   // If this is a XUL Document, it should not implement nsHyperText
@@ -469,22 +468,16 @@ DocAccessible::Shutdown()
   // Walk the array backwards because child documents remove themselves from the
   // array as they are shutdown.
   int32_t childDocCount = mChildDocuments.Length();
   for (int32_t idx = childDocCount - 1; idx >= 0; idx--)
     mChildDocuments[idx]->Shutdown();
 
   mChildDocuments.Clear();
 
-  // XXX thinking about ordering?
-  if (XRE_GetProcessType() != GeckoProcessType_Default) {
-    DocAccessibleChild::Send__delete__(mIPCDoc);
-    MOZ_ASSERT(!mIPCDoc);
-  }
-
   if (mVirtualCursor) {
     mVirtualCursor->RemoveObserver(this);
     mVirtualCursor = nullptr;
   }
 
   mPresShell->SetDocAccessible(nullptr);
   mPresShell = nullptr;  // Avoid reentrancy
 
@@ -1438,23 +1431,16 @@ DocAccessible::DoInitialUpdate()
   // Fire reorder event after the document tree is constructed. Note, since
   // this reorder event is processed by parent document then events targeted to
   // this document may be fired prior to this reorder event. If this is
   // a problem then consider to keep event processing per tab document.
   if (!IsRoot()) {
     nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent());
     ParentDocument()->FireDelayedEvent(reorderEvent);
   }
-
-  uint32_t childCount = ChildCount();
-  for (uint32_t i = 0; i < childCount; i++) {
-    Accessible* child = GetChildAt(i);
-    nsRefPtr<AccShowEvent> event = new AccShowEvent(child, child->GetContent());
-  FireDelayedEvent(event);
-  }
 }
 
 void
 DocAccessible::ProcessLoad()
 {
   mLoadState |= eCompletelyLoaded;
 
 #ifdef A11Y_LOG
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -28,17 +28,16 @@ class nsIScrollableView;
 
 const uint32_t kDefaultCacheLength = 128;
 
 namespace mozilla {
 namespace a11y {
 
 class DocManager;
 class NotificationController;
-class DocAccessibleChild;
 class RelatedAccIterator;
 template<class Class, class Arg>
 class TNotification;
 
 class DocAccessible : public HyperTextAccessibleWrap,
                       public xpcAccessibleDocument,
                       public nsIDocumentObserver,
                       public nsIObserver,
@@ -516,30 +515,16 @@ protected:
    * Rules: The root chrome document accessible is never an event target
    * (for example, Firefox UI window). If the sub document is loaded within its
    * parent document then the parent document is a target only (aka events
    * coalescence).
    */
   bool IsLoadEventTarget() const;
 
   /**
-   * If this document is in a content process return the object responsible for
-   * communicating with the main process for it.
-   */
-  DocAccessibleChild* IPCDoc() const { return mIPCDoc; }
-
-  /*
-   * Set the object responsible for communicating with the main process on
-   * behalf of this document.
-   */
-  void SetIPCDoc(DocAccessibleChild* aIPCDoc) { mIPCDoc = aIPCDoc; }
-
-  friend class DocAccessibleChild;
-
-  /**
    * Used to fire scrolling end event after page scroll.
    *
    * @param aTimer    [in] the timer object
    * @param aClosure  [in] the document accessible where scrolling happens
    */
   static void ScrollTimerCallback(nsITimer* aTimer, void* aClosure);
 
 protected:
@@ -652,19 +637,16 @@ protected:
    */
   nsRefPtr<NotificationController> mNotificationController;
   friend class EventQueue;
   friend class NotificationController;
 
 private:
 
   nsIPresShell* mPresShell;
-
-  // Exclusively owned by IPDL so don't manually delete it!
-  DocAccessibleChild* mIPCDoc;
 };
 
 inline DocAccessible*
 Accessible::AsDoc()
 {
   return IsDoc() ? static_cast<DocAccessible*>(this) : nullptr;
 }
 
--- a/accessible/generic/moz.build
+++ b/accessible/generic/moz.build
@@ -23,17 +23,16 @@ UNIFIED_SOURCES += [
     'RootAccessible.cpp',
     'TableCellAccessible.cpp',
     'TextLeafAccessible.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/accessible/base',
     '/accessible/html',
-    '/accessible/ipc',
     '/accessible/xpcom',
     '/accessible/xul',
     '/content/base/src',
     '/layout/generic',
     '/layout/xul',
 ]
 
 if CONFIG['MOZ_ENABLE_GTK']:
@@ -50,10 +49,8 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co
         '/accessible/mac',
     ]
 else:
     LOCAL_INCLUDES += [
         '/accessible/other',
     ]
 
 FINAL_LIBRARY = 'xul'
-
-include('/ipc/chromium/chromium-config.mozbuild')
deleted file mode 100644
--- a/accessible/ipc/DocAccessibleChild.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=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 "DocAccessibleChild.h"
-
-#include "Accessible-inl.h"
-
-namespace mozilla {
-namespace a11y {
-
-void
-SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree)
-{
-  uint64_t id = reinterpret_cast<uint64_t>(aRoot->UniqueID());
-  uint32_t role = aRoot->Role();
-  uint32_t childCount = aRoot->ChildCount();
-
-  nsString name;
-  aRoot->Name(name);
-  aTree.AppendElement(AccessibleData(id, role, childCount, name));
-  for (uint32_t i = 0; i < childCount; i++)
-    SerializeTree(aRoot->GetChildAt(i), aTree);
-}
-
-void
-DocAccessibleChild::ShowEvent(AccShowEvent* aShowEvent)
-{
-  Accessible* parent = aShowEvent->Parent();
-  uint64_t parentID = parent->IsDoc() ? 0 : reinterpret_cast<uint64_t>(parent->UniqueID());
-  uint32_t idxInParent = aShowEvent->GetAccessible()->IndexInParent();
-  nsTArray<AccessibleData> shownTree;
-  ShowEventData data(parentID, idxInParent, shownTree);
-  SerializeTree(aShowEvent->GetAccessible(), data.NewTree());
-  SendShowEvent(data);
-}
-}
-}
deleted file mode 100644
--- a/accessible/ipc/DocAccessibleChild.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=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/. */
-
-#ifndef mozilla_a11y_DocAccessibleChild_h
-#define mozilla_a11y_DocAccessibleChild_h
-
-#include "mozilla/a11y/DocAccessible.h"
-#include "mozilla/a11y/PDocAccessibleChild.h"
-#include "nsISupportsImpl.h"
-
-namespace mozilla {
-namespace a11y {
-class AccShowEvent;
-
-  /*
-   * These objects handle content side communication for an accessible document,
-   * and their lifetime is the same as the document they represent.
-   */
-class DocAccessibleChild : public PDocAccessibleChild
-{
-public:
-  DocAccessibleChild(DocAccessible* aDoc) :
-    mDoc(aDoc)
-  { MOZ_COUNT_CTOR(DocAccessibleChild); }
-  ~DocAccessibleChild()
-  {
-    mDoc->SetIPCDoc(nullptr);
-    MOZ_COUNT_DTOR(DocAccessibleChild);
-  }
-
-  void ShowEvent(AccShowEvent* aShowEvent);
-
-private:
-  DocAccessible* mDoc;
-};
-
-}
-}
-
-#endif
deleted file mode 100644
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=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 "DocAccessibleParent.h"
-#include "nsAutoPtr.h"
-#include "mozilla/a11y/Platform.h"
-
-namespace mozilla {
-namespace a11y {
-
-bool
-DocAccessibleParent::RecvShowEvent(const ShowEventData& aData)
-{
-  if (aData.NewTree().IsEmpty()) {
-    NS_ERROR("no children being added");
-    return false;
-  }
-
-  ProxyAccessible* parent = nullptr;
-  if (aData.ID()) {
-    ProxyEntry* e = mAccessibles.GetEntry(aData.ID());
-    if (e)
-      parent = e->mProxy;
-  } else {
-    parent = this;
-  }
-
-  // XXX This should really never happen, but sometimes we fail to fire the
-  // required show events.
-  if (!parent) {
-    NS_ERROR("adding child to unknown accessible");
-    return false;
-  }
-
-  uint32_t newChildIdx = aData.Idx();
-  if (newChildIdx > parent->ChildrenCount()) {
-    NS_ERROR("invalid index to add child at");
-    return false;
-  }
-
-  uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
-  MOZ_ASSERT(consumed == aData.NewTree().Length());
-  for (uint32_t i = 0; i < consumed; i++) {
-    uint64_t id = aData.NewTree()[i].ID();
-    MOZ_ASSERT(mAccessibles.GetEntry(id));
-  }
-
-  return consumed;
-}
-
-uint32_t
-DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
-                                const nsTArray<a11y::AccessibleData>& aNewTree,
-                                uint32_t aIdx, uint32_t aIdxInParent)
-{
-  if (aNewTree.Length() <= aIdx) {
-    NS_ERROR("bad index in serialized tree!");
-    return 0;
-  }
-
-  const AccessibleData& newChild = aNewTree[aIdx];
-  if (newChild.Role() > roles::LAST_ROLE) {
-    NS_ERROR("invalid role");
-    return 0;
-  }
-
-  auto role = static_cast<a11y::role>(newChild.Role());
-  ProxyAccessible* newProxy =
-    new ProxyAccessible(newChild.ID(), aParent, this, role, newChild.Name());
-  aParent->AddChildAt(aIdxInParent, newProxy);
-  mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy;
-  ProxyCreated(newProxy);
-
-  uint32_t accessibles = 1;
-  uint32_t kids = newChild.ChildrenCount();
-  for (uint32_t i = 0; i < kids; i++) {
-    uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i);
-    if (!consumed)
-      return 0;
-
-    accessibles += consumed;
-  }
-
-  MOZ_ASSERT(newProxy->ChildrenCount() == kids);
-
-  return accessibles;
-}
-
-bool
-DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID)
-{
-  ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
-  if (!rootEntry) {
-    NS_ERROR("invalid root being removed!");
-    return true;
-  }
-
-  ProxyAccessible* root = rootEntry->mProxy;
-  if (!root) {
-    NS_ERROR("invalid root being removed!");
-    return true;
-  }
-
-  root->Shutdown();
-
-  return true;
-}
-}
-}
deleted file mode 100644
--- a/accessible/ipc/DocAccessibleParent.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=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/. */
-
-#ifndef mozilla_a11y_DocAccessibleParent_h
-#define mozilla_a11y_DocAccessibleParent_h
-
-#include "nsAccessibilityService.h"
-#include "ProxyAccessible.h"
-#include "mozilla/a11y/PDocAccessibleParent.h"
-#include "nsClassHashtable.h"
-#include "nsHashKeys.h"
-#include "nsISupportsImpl.h"
-
-namespace mozilla {
-namespace a11y {
-
-/*
- * These objects live in the main process and comunicate with and represent
- * an accessible document in a content process.
- */
-class DocAccessibleParent : public ProxyAccessible,
-    public PDocAccessibleParent
-{
-public:
-  DocAccessibleParent() :
-    mParentDoc(nullptr)
-  { MOZ_COUNT_CTOR_INHERITED(DocAccessibleParent, ProxyAccessible); }
-  ~DocAccessibleParent()
-  {
-    MOZ_COUNT_DTOR_INHERITED(DocAccessibleParent, ProxyAccessible);
-    MOZ_ASSERT(mChildDocs.Length() == 0);
-    MOZ_ASSERT(!mParentDoc);
-  }
-
-  /*
-   * Called when a message from a document in a child process notifies the main
-   * process it is firing an event.
-   */
-  virtual bool RecvEvent(const uint32_t& aType) MOZ_OVERRIDE
-  {
-    return true;
-  }
-
-  virtual bool RecvShowEvent(const ShowEventData& aData) MOZ_OVERRIDE;
-  virtual bool RecvHideEvent(const uint64_t& aRootID) MOZ_OVERRIDE;
-
-  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE
-  {
-    MOZ_ASSERT(mChildDocs.IsEmpty(),
-               "why wheren't the child docs destroyed already?");
-    mParentDoc ? mParentDoc->RemoveChildDoc(this)
-      : GetAccService()->RemoteDocShutdown(this);
-  }
-
-  /*
-   * Return the main processes representation of the parent document (if any)
-   * of the document this object represents.
-   */
-  DocAccessibleParent* Parent() const { return mParentDoc; }
-
-  /*
-   * Called when a document in a content process notifies the main process of a
-   * new child document.
-   */
-  bool AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID)
-  {
-    ProxyAccessible* outerDoc = mAccessibles.GetEntry(aParentID)->mProxy;
-    if (!outerDoc)
-      return false;
-
-    aChildDoc->mParent = outerDoc;
-    outerDoc->SetChildDoc(aChildDoc);
-    mChildDocs.AppendElement(aChildDoc);
-    aChildDoc->mParentDoc = this;
-    return true;
-  }
-
-  /*
-   * Called when the document in the content process this object represents
-   * notifies the main process a child document has been removed.
-   */
-  void RemoveChildDoc(DocAccessibleParent* aChildDoc)
-  {
-    aChildDoc->mParent->SetChildDoc(nullptr);
-    mChildDocs.RemoveElement(aChildDoc);
-    aChildDoc->mParentDoc = nullptr;
-    MOZ_ASSERT(aChildDoc->mChildDocs.Length() == 0);
-  }
-
-  void RemoveAccessible(ProxyAccessible* aAccessible)
-  {
-    MOZ_ASSERT(mAccessibles.GetEntry(aAccessible->ID()));
-    mAccessibles.RemoveEntry(aAccessible->ID());
-  }
-
-private:
-
-  class ProxyEntry : public PLDHashEntryHdr
-  {
-  public:
-    ProxyEntry(const void*) : mProxy(nullptr) {}
-    ProxyEntry(ProxyEntry&& aOther) :
-      mProxy(aOther.mProxy) { aOther.mProxy = nullptr; }
-    ~ProxyEntry() { delete mProxy; }
-
-    typedef uint64_t KeyType;
-    typedef const void* KeyTypePointer;
-
-    bool KeyEquals(const void* aKey) const
-    { return mProxy->ID() == (uint64_t)aKey; }
-
-    static const void* KeyToPointer(uint64_t aKey) { return (void*)aKey; }
-
-    static PLDHashNumber HashKey(const void* aKey) { return (uint64_t)aKey; }
-
-    enum { ALLOW_MEMMOVE = true };
-
-    ProxyAccessible* mProxy;
-  };
-
-  uint32_t AddSubtree(ProxyAccessible* aParent,
-                      const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
-                      uint32_t aIdxInParent);
-
-  nsTArray<DocAccessibleParent*> mChildDocs;
-  DocAccessibleParent* mParentDoc;
-
-  /*
-   * Conceptually this is a map from IDs to proxies, but we store the ID in the
-   * proxy object so we can't use a real map.
-   */
-  nsTHashtable<ProxyEntry> mAccessibles;
-};
-
-}
-}
-
-#endif
deleted file mode 100644
--- a/accessible/ipc/PDocAccessible.ipdl
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=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 protocol PContent;
-
-namespace mozilla {
-namespace a11y {
-
-struct AccessibleData
-{
-  uint64_t ID;
-  uint32_t Role;
-  uint32_t ChildrenCount;
-  nsString Name;
-};
-
-struct ShowEventData
-{
-  uint64_t ID;
-  uint32_t Idx;
-  AccessibleData[] NewTree;
-};
-
-protocol PDocAccessible
-{
-  manager PContent;
-
-parent:
-  __delete__();
-
-  /*
-   * Notify the parent process the document in the child process is firing an
-   * event.
-   */
-  Event(uint32_t type);
-  ShowEvent(ShowEventData data);
-  HideEvent(uint64_t aRootID);
-};
-
-}
-}
deleted file mode 100644
--- a/accessible/ipc/ProxyAccessible.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=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 "ProxyAccessible.h"
-#include "DocAccessibleParent.h"
-#include "mozilla/a11y/Platform.h"
-
-namespace mozilla {
-namespace a11y {
-
-void
-ProxyAccessible::Shutdown()
-{
-  MOZ_ASSERT(!mOuterDoc);
-
-  uint32_t childCount = mChildren.Length();
-  for (uint32_t idx = 0; idx < childCount; idx++)
-    mChildren[idx]->Shutdown();
-
-  mChildren.Clear();
-  ProxyDestroyed(this);
-  mDoc->RemoveAccessible(this);
-}
-
-void
-ProxyAccessible::SetChildDoc(DocAccessibleParent* aParent)
-{
-  if (aParent) {
-    MOZ_ASSERT(mChildren.IsEmpty());
-    mChildren.AppendElement(aParent);
-    mOuterDoc = true;
-  } else {
-    MOZ_ASSERT(mChildren.Length() == 1);
-    mChildren.Clear();
-    mOuterDoc = false;
-  }
-}
-}
-}
deleted file mode 100644
--- a/accessible/ipc/ProxyAccessible.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=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/. */
-
-#ifndef mozilla_a11y_ProxyAccessible_h
-#define mozilla_a11y_ProxyAccessible_h
-
-#include "mozilla/a11y/Role.h"
-#include "nsString.h"
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace a11y {
-
-class DocAccessibleParent;
-
-class ProxyAccessible
-{
-public:
-
-  ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
-                  DocAccessibleParent* aDoc, role aRole,
-                  const nsString& aName) :
-     mParent(aParent), mDoc(aDoc), mID(aID), mRole(aRole), mOuterDoc(false), mName(aName)
-  {
-    MOZ_COUNT_CTOR(ProxyAccessible);
-  }
-  ~ProxyAccessible() { MOZ_COUNT_DTOR(ProxyAccessible); }
-
-  void AddChildAt(uint32_t aIdx, ProxyAccessible* aChild)
-  { mChildren.InsertElementAt(aIdx, aChild); }
-
-  uint32_t ChildrenCount() const { return mChildren.Length(); }
-
-  void Shutdown();
-
-  void SetChildDoc(DocAccessibleParent*);
-
-  /**
-   * Get the role of the accessible we're proxying.
-   */
-  role Role() const { return mRole; }
-
-  /**
-   * Allow the platform to store a pointers worth of data on us.
-   */
-  uintptr_t GetWrapper() const { return mWrapper; }
-  void SetWrapper(uintptr_t aWrapper) { mWrapper = aWrapper; }
-
-  /*
-   * Return the ID of the accessible being proxied.
-   */
-  uint64_t ID() const { return mID; }
-
-protected:
-  ProxyAccessible() :
-    mParent(nullptr), mDoc(nullptr) { MOZ_COUNT_CTOR(ProxyAccessible); }
-
-protected:
-  ProxyAccessible* mParent;
-
-private:
-  nsTArray<ProxyAccessible*> mChildren;
-  DocAccessibleParent* mDoc;
-  uintptr_t mWrapper;
-  uint64_t mID;
-  role mRole : 31;
-  bool mOuterDoc : 1;
-  nsString mName;
-};
-
-}
-}
-
-#endif
deleted file mode 100644
--- a/accessible/ipc/moz.build
+++ /dev/null
@@ -1,28 +0,0 @@
-# -*- 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/.
-
-IPDL_SOURCES += ['PDocAccessible.ipdl']
-
-EXPORTS.mozilla.a11y += [
-    'DocAccessibleChild.h',
-    'DocAccessibleParent.h',
-    'ProxyAccessible.h'
-]
-
-SOURCES += [
-    'DocAccessibleChild.cpp',
-    'DocAccessibleParent.cpp',
-    'ProxyAccessible.cpp'
-]
-
-LOCAL_INCLUDES += [
-    '../base',
-    '../generic',
-    ]
-
-FINAL_LIBRARY = 'xul'
-
-include('/ipc/chromium/chromium-config.mozbuild')
--- a/accessible/mac/Platform.mm
+++ b/accessible/mac/Platform.mm
@@ -28,25 +28,16 @@ PlatformInit()
 {
 }
 
 void
 PlatformShutdown()
 {
 }
 
-void
-ProxyCreated(ProxyAccessible*)
-{
-}
-
-void
-ProxyDestroyed(ProxyAccessible*)
-{
-}
 }
 }
 
 @interface GeckoNSApplication(a11y)
 -(void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute;
 @end
 
 @implementation GeckoNSApplication(a11y)
--- a/accessible/moz.build
+++ b/accessible/moz.build
@@ -10,14 +10,14 @@ if CONFIG['MOZ_ENABLE_GTK']:
     DIRS += ['atk']
 elif toolkit == 'windows':
     DIRS += ['windows']
 elif toolkit == 'cocoa':
     DIRS += ['mac']
 else:
     DIRS += ['other']
 
-DIRS += ['base', 'generic', 'html', 'interfaces', 'ipc', 'jsat', 'xpcom']
+DIRS += ['base', 'generic', 'html', 'interfaces', 'jsat', 'xpcom']
 
 if CONFIG['MOZ_XUL']:
     DIRS += ['xul']
 
 TEST_DIRS += ['tests/mochitest']
--- a/accessible/other/Platform.cpp
+++ b/accessible/other/Platform.cpp
@@ -13,18 +13,8 @@ void
 a11y::PlatformInit()
 {
 }
 
 void
 a11y::PlatformShutdown()
 {
 }
-
-void
-a11y::ProxyCreated(ProxyAccessible*)
-{
-}
-
-void
-a11y::ProxyDestroyed(ProxyAccessible*)
-{
-}
--- a/accessible/windows/msaa/Platform.cpp
+++ b/accessible/windows/msaa/Platform.cpp
@@ -29,17 +29,8 @@ a11y::PlatformInit()
 void
 a11y::PlatformShutdown()
 {
   ::DestroyCaret();
 
   nsWinUtils::ShutdownWindowEmulation();
 }
 
-void
-a11y::ProxyCreated(ProxyAccessible*)
-{
-}
-
-void
-a11y::ProxyDestroyed(ProxyAccessible*)
-{
-}
--- a/b2g/config/dolphin/config.json
+++ b/b2g/config/dolphin/config.json
@@ -14,17 +14,21 @@
         "{objdir}/dist/b2g-*.tar.gz",
         "{workdir}/sources.xml"
     ],
     "zip_files": [
         ["{workdir}/out/target/product/scx15_sp7715ga/*.img", "out/target/product/scx15_sp7715ga/"],
         "{workdir}/flash.sh",
         "{workdir}/load-config.sh",
         "{workdir}/.config",
-        "{workdir}/sources.xml"
+        "{workdir}/sources.xml",
+        "{workdir}/profile.sh",
+        ["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
+        ["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
+        ["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
     ],
     "env": {
         "VARIANT": "user",
         "MOZILLA_OFFICIAL": "1"
     },
     "b2g_manifest": "dolphin.xml",
     "b2g_manifest_intree": true,
     "additional_source_tarballs": [],
--- 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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <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="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
--- 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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <!-- 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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <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"/>
--- 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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <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="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
--- 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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/config.json
+++ b/b2g/config/flame-kk/config.json
@@ -17,17 +17,21 @@
         "{objdir}/dist/b2g-update/*.mar"
     ],
     "zip_files": [
         ["{workdir}/out/target/product/flame/*.img", "out/target/product/flame/"],
         ["{workdir}/boot.img", "out/target/product/flame/"],
         "{workdir}/flash.sh",
         "{workdir}/load-config.sh",
         "{workdir}/.config",
-        "{workdir}/sources.xml"
+        "{workdir}/sources.xml",
+        "{workdir}/profile.sh",
+        ["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
+        ["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
+        ["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
     ],
     "env": {
         "VARIANT": "user",
         "MOZILLA_OFFICIAL": "1",
         "MOZ_TELEMETRY_REPORTING": "1",
         "B2G_UPDATE_CHANNEL": "nightly",
         "GAIA_KEYBOARD_LAYOUTS": "en,pt-BR,es,de,fr,pl,zh-Hans-Pinyin,zh-Hant-Zhuyin,en-Dvorak"
     },
--- 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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <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="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
--- a/b2g/config/flame/config.json
+++ b/b2g/config/flame/config.json
@@ -17,17 +17,21 @@
         "{objdir}/dist/b2g-update/*.mar"
     ],
     "zip_files": [
         ["{workdir}/out/target/product/flame/*.img", "out/target/product/flame/"],
         ["{workdir}/boot.img", "out/target/product/flame/"],
         "{workdir}/flash.sh",
         "{workdir}/load-config.sh",
         "{workdir}/.config",
-        "{workdir}/sources.xml"
+        "{workdir}/sources.xml",
+        "{workdir}/profile.sh",
+        ["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
+        ["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
+        ["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
     ],
     "env": {
         "VARIANT": "user",
         "MOZILLA_OFFICIAL": "1",
         "MOZ_TELEMETRY_REPORTING": "1",
         "B2G_UPDATE_CHANNEL": "nightly",
         "GAIA_KEYBOARD_LAYOUTS": "en,pt-BR,es,de,fr,pl,zh-Hans-Pinyin,zh-Hant-Zhuyin,en-Dvorak"
     },
--- 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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <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"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "7f097f40e32ecba580890ce1d3df2a493641bdec", 
+    "revision": "aa3ab2d389dce3ba351a897b4ae56f1fe9e1780d", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/config.json
+++ b/b2g/config/hamachi/config.json
@@ -11,16 +11,22 @@
         "{workdir}/sources.xml"
     ],
     "public_upload_files": [
         "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
         "{objdir}/dist/b2g-*.tar.gz",
         "{workdir}/sources.xml",
         "{workdir}/out/target/product/hamachi/*.mar"
     ],
+    "zip_files": [
+        "{workdir}/profile.sh",
+        ["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
+        ["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
+        ["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
+    ],
     "env": {
         "VARIANT": "user",
         "MOZILLA_OFFICIAL": "1",
         "MOZ_TELEMETRY_REPORTING": "1",
         "B2G_UPDATE_CHANNEL": "nightly"
     },
     "b2g_manifest": "hamachi.xml",
     "b2g_manifest_intree": true,
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/config.json
+++ b/b2g/config/helix/config.json
@@ -16,17 +16,21 @@
         "{workdir}/sources.xml",
         "{objdir}/dist/b2g-update/*.mar"
     ],
     "zip_files": [
         ["{workdir}/out/target/product/helix/*.img", "out/target/product/helix/"],
         "{workdir}/flash.sh",
         "{workdir}/load-config.sh",
         "{workdir}/.config",
-        "{workdir}/sources.xml"
+        "{workdir}/sources.xml",
+        "{workdir}/profile.sh",
+        ["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
+        ["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
+        ["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
     ],
     "env": {
         "VARIANT": "user",
         "MOZILLA_OFFICIAL": "1",
         "MOZ_TELEMETRY_REPORTING": "1",
         "ANDROIDFS_DIR": "{workdir}/helix-ics",
         "B2G_UPDATE_CHANNEL": "nightly"
     },
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/config.json
+++ b/b2g/config/nexus-4/config.json
@@ -17,17 +17,21 @@
         "{objdir}/dist/b2g-update/*.mar"
     ],
     "zip_files": [
         ["{workdir}/out/target/product/mako/*.img", "out/target/product/mako/"],
         ["{workdir}/boot.img", "out/target/product/mako/"],
         "{workdir}/flash.sh",
         "{workdir}/load-config.sh",
         "{workdir}/.config",
-        "{workdir}/sources.xml"
+        "{workdir}/sources.xml",
+        "{workdir}/profile.sh",
+        ["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
+        ["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
+        ["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
     ],
     "env": {
         "VARIANT": "user",
         "MOZILLA_OFFICIAL": "1",
         "MOZ_TELEMETRY_REPORTING": "1",
         "B2G_UPDATE_CHANNEL": "nightly"
     },
     "b2g_manifest": "nexus-4.xml",
--- 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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <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"/>
--- a/b2g/config/wasabi/config.json
+++ b/b2g/config/wasabi/config.json
@@ -11,17 +11,21 @@
         "{workdir}/sources.xml"
     ],
     "zip_files": [
         ["{workdir}/out/target/product/wasabi/*.img", "out/target/product/wasabi/"],
         ["{workdir}/boot.img", "out/target/product/wasabi/"],
         "{workdir}/flash.sh",
         "{workdir}/load-config.sh",
         "{workdir}/.config",
-        "{workdir}/sources.xml"
+        "{workdir}/sources.xml",
+        "{workdir}/profile.sh",
+        ["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
+        ["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
+        ["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
     ],
     "env": {
         "VARIANT": "user",
         "MOZILLA_OFFICIAL": "1",
         "MOZ_TELEMETRY_REPORTING": "1"
     },
     "b2g_manifest": "wasabi.xml",
     "b2g_manifest_intree": true,
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="0e280591881d44b80f456bc27e12d9114c218868"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a23d2c490b39c4699c9375e25c4acdf396a2fa85"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -191,17 +191,17 @@ def dumpLeakLog(leakLogFile, filter = Fa
   # Only |XPCOM_MEM_LEAK_LOG| reports can be actually filtered out.
   # Only check whether an actual leak was reported.
   if filter and not "0 TOTAL " in leakReport:
     return
 
   # Simply copy the log.
   log.info(leakReport.rstrip("\n"))
 
-def processSingleLeakFile(leakLogFileName, processType, leakThreshold):
+def processSingleLeakFile(leakLogFileName, processType, leakThreshold, ignoreMissingLeaks):
   """Process a single leak log.
   """
 
   #                  Per-Inst  Leaked      Total  Rem ...
   #   0 TOTAL              17     192  419115886    2 ...
   # 833 nsTimerImpl        60     120      24726    2 ...
   lineRe = re.compile(r"^\s*\d+\s+(?P<name>\S+)\s+"
                       r"(?P<size>-?\d+)\s+(?P<bytesLeaked>-?\d+)\s+"
@@ -268,21 +268,24 @@ def processSingleLeakFile(leakLogFileNam
 
   logAsWarning = False
 
   if totalBytesLeaked is None:
     # We didn't see a line with name 'TOTAL'
     if crashedOnPurpose:
       log.info("TEST-INFO | leakcheck | %s deliberate crash and thus no leak log"
                % processString)
+    elif ignoreMissingLeaks:
+      log.info("TEST-INFO | leakcheck | %s ignoring missing output line for total leaks"
+               % processString)
     else:
-      # TODO: This should be a TEST-UNEXPECTED-FAIL, but was changed to a warning
-      # due to too many intermittent failures (see bug 831223).
-      log.info("WARNING | leakcheck | %s missing output line for total leaks!"
+      log.info("TEST-UNEXPECTED-FAIL | leakcheck | %s missing output line for total leaks!"
                % processString)
+      log.info("TEST-INFO | leakcheck | missing output line from log file %s"
+               % leakLogFileName)
     return
 
   if totalBytesLeaked == 0:
     log.info("TEST-PASS | leakcheck | %s no leaks detected!" % processString)
     return
 
   # totalBytesLeaked was seen and is non-zero.
   if totalBytesLeaked > leakThreshold:
@@ -301,17 +304,17 @@ def processSingleLeakFile(leakLogFileNam
 
   if logAsWarning:
     log.warning("%s | leakcheck | %s %d bytes leaked (%s)"
                 % (prefix, processString, totalBytesLeaked, leakedObjectSummary))
   else:
     log.info("%s | leakcheck | %s %d bytes leaked (%s)"
              % (prefix, processString, totalBytesLeaked, leakedObjectSummary))
 
-def processLeakLog(leakLogFile, leakThresholds):
+def processLeakLog(leakLogFile, leakThresholds, ignoreMissingLeaks):
   """Process the leak log, including separate leak logs created
   by child processes.
 
   Use this function if you want an additional PASS/FAIL summary.
   It must be used with the |XPCOM_MEM_BLOAT_LOG| environment variable.
 
   The base of leakLogFile for a non-default process needs to end with
     _proctype_pid12345.log
@@ -358,17 +361,18 @@ def processLeakLog(leakLogFile, leakThre
       if m:
         processType = m.group(1)
       else:
         processType = "default"
       if not processType in knownProcessTypes:
         log.info("TEST-UNEXPECTED-FAIL | leakcheck | Leak log with unknown process type %s"
                  % processType)
       leakThreshold = leakThresholds.get(processType, 0)
-      processSingleLeakFile(thisFile, processType, leakThreshold)
+      processSingleLeakFile(thisFile, processType, leakThreshold,
+                            processType in ignoreMissingLeaks)
 
 def replaceBackSlashes(input):
   return input.replace('\\', '/')
 
 class KeyValueParseError(Exception):
   """error when parsing strings of serialized key-values"""
   def __init__(self, msg, errors=()):
     self.errors = errors
--- a/build/gyp.mozbuild
+++ b/build/gyp.mozbuild
@@ -26,17 +26,17 @@ gyp_vars = {
     'build_libvpx': 0,
     'build_libyuv': 0,
     'libyuv_dir': '/media/libyuv',
     'yuv_disable_avx2': 0 if CONFIG['HAVE_X86_AVX2'] else 1,
     # don't use openssl
     'use_openssl': 0,
 
     # saves 4MB when webrtc_trace is off
-    'enable_lazy_trace_alloc': 0,
+    'enable_lazy_trace_alloc': 1 if CONFIG['RELEASE_BUILD'] else 0,
 
     'use_x11': 1 if CONFIG['MOZ_X11'] else 0,
     'use_glib': 1 if CONFIG['GLIB_LIBS'] else 0,
 
      # turn off mandatory use of NEON and instead use NEON detection
     'arm_neon': 0,
     'arm_neon_optional': 1,
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -9173,24 +9173,16 @@ nsresult
 nsDocument::CloneDocHelper(nsDocument* clone) const
 {
   clone->mIsStaticDocument = mCreatingStaticClone;
 
   // Init document
   nsresult rv = clone->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Set URI/principal
-  clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
-  clone->SetChromeXHRDocURI(mChromeXHRDocURI);
-  // Must set the principal first, since SetBaseURI checks it.
-  clone->SetPrincipal(NodePrincipal());
-  clone->mDocumentBaseURI = mDocumentBaseURI;
-  clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI);
-
   if (mCreatingStaticClone) {
     nsCOMPtr<nsILoadGroup> loadGroup;
 
     // |mDocumentContainer| is the container of the document that is being
     // created and not the original container. See CreateStaticClone function().
     nsCOMPtr<nsIDocumentLoader> docLoader(mDocumentContainer);
     if (docLoader) {
       docLoader->GetLoadGroup(getter_AddRefs(loadGroup));
@@ -9205,16 +9197,28 @@ nsDocument::CloneDocHelper(nsDocument* c
     clone->mChannel = channel;
     if (uri) {
       clone->ResetToURI(uri, loadGroup, NodePrincipal());
     }
 
     clone->SetContainer(mDocumentContainer);
   }
 
+  // Now ensure that our clone has the same URI, base URI, and principal as us.
+  // We do this after the mCreatingStaticClone block above, because that block
+  // can set the base URI to an incorrect value in cases when base URI
+  // information came from the channel.  So we override explicitly, and do it
+  // for all these properties, in case ResetToURI messes with any of the rest of
+  // them.
+  clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
+  clone->SetChromeXHRDocURI(mChromeXHRDocURI);
+  clone->SetPrincipal(NodePrincipal());
+  clone->mDocumentBaseURI = mDocumentBaseURI;
+  clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI);
+
   // Set scripting object
   bool hasHadScriptObject = true;
   nsIScriptGlobalObject* scriptObject =
     GetScriptHandlingObject(hasHadScriptObject);
   NS_ENSURE_STATE(scriptObject || !hasHadScriptObject);
   if (scriptObject) {
     clone->SetScriptHandlingObject(scriptObject);
   } else {
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -791,51 +791,58 @@ GK_ATOM(onmozfullscreenchange, "onmozful
 GK_ATOM(onmozfullscreenerror, "onmozfullscreenerror")
 GK_ATOM(onmozpointerlockchange, "onmozpointerlockchange")
 GK_ATOM(onmozpointerlockerror, "onmozpointerlockerror")
 GK_ATOM(onmoztimechange, "onmoztimechange")
 GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll")
 GK_ATOM(onMozScrolledAreaChanged, "onMozScrolledAreaChanged")
 GK_ATOM(onmoznetworkupload, "onmoznetworkupload")
 GK_ATOM(onmoznetworkdownload, "onmoznetworkdownload")
+GK_ATOM(onnewrdsgroup, "onnewrdsgroup")
 GK_ATOM(onnoupdate, "onnoupdate")
 GK_ATOM(onobsolete, "onobsolete")
 GK_ATOM(ononline, "ononline")
 GK_ATOM(onoffline, "onoffline")
 GK_ATOM(onopen, "onopen")
 GK_ATOM(onotastatuschange, "onotastatuschange")
 GK_ATOM(onoverflow, "onoverflow")
 GK_ATOM(onoverflowchanged, "onoverflowchanged")
 GK_ATOM(onpagehide, "onpagehide")
 GK_ATOM(onpageshow, "onpageshow")
 GK_ATOM(onpaint, "onpaint")
 GK_ATOM(onpairedstatuschanged, "onpairedstatuschanged")
 GK_ATOM(onpairingconfirmationreq, "onpairingconfirmationreq")
 GK_ATOM(onpairingconsentreq, "onpairingconsentreq")
 GK_ATOM(onpaste, "onpaste")
 GK_ATOM(onpendingchange, "onpendingchange")
+GK_ATOM(onpichange, "onpichange")
 GK_ATOM(onpopuphidden, "onpopuphidden")
 GK_ATOM(onpopuphiding, "onpopuphiding")
 GK_ATOM(onpopupshowing, "onpopupshowing")
 GK_ATOM(onpopupshown, "onpopupshown")
+GK_ATOM(onpschange, "onpschange")
+GK_ATOM(onptychange, "onptychange")
 GK_ATOM(onradiostatechange, "onradiostatechange")
+GK_ATOM(onrdsdisabled, "onrdsdisabled")
+GK_ATOM(onrdsenabled, "onrdsenabled")
 GK_ATOM(onreaderror, "onreaderror")
 GK_ATOM(onreadsuccess, "onreadsuccess")
 GK_ATOM(onready, "onready")
 GK_ATOM(onreadystatechange, "onreadystatechange")
 GK_ATOM(onreceived, "onreceived")
 GK_ATOM(onremoteheld, "onremoteheld")
 GK_ATOM(onremoteresumed, "onremoteresumed")
 GK_ATOM(onresourcetimingbufferfull, "onresourcetimingbufferfull")
 GK_ATOM(onretrieving, "onretrieving")
 GK_ATOM(onRequest, "onRequest")
 GK_ATOM(onrequestmediaplaystatus, "onrequestmediaplaystatus")
 GK_ATOM(onreset, "onreset")
 GK_ATOM(onresuming, "onresuming")
 GK_ATOM(onresize, "onresize")
+GK_ATOM(onrtchange, "onrtchange")
 GK_ATOM(onscostatuschanged, "onscostatuschanged")
 GK_ATOM(onscroll, "onscroll")
 GK_ATOM(onselect, "onselect")
 GK_ATOM(onsending, "onsending")
 GK_ATOM(onsent, "onsent")
 GK_ATOM(onset, "onset")
 GK_ATOM(onshow, "onshow")
 GK_ATOM(onstatechange, "onstatechange")
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1085,17 +1085,17 @@ nsXMLHttpRequest::GetResponseURL(nsAStri
   nsCOMPtr<nsIURI> responseUrl;
   mChannel->GetURI(getter_AddRefs(responseUrl));
 
   if (!responseUrl) {
     return;
   }
 
   nsAutoCString temp;
-  responseUrl->GetSpec(temp);
+  responseUrl->GetSpecIgnoringRef(temp);
   CopyUTF8toUTF16(temp, aUrl);
 }
 
 /* readonly attribute unsigned long status; */
 NS_IMETHODIMP
 nsXMLHttpRequest::GetStatus(uint32_t *aStatus)
 {
   *aStatus = Status();
--- a/content/base/test/file_XHRResponseURL.js
+++ b/content/base/test/file_XHRResponseURL.js
@@ -184,16 +184,21 @@ function testSuccessResponse() {
     },
     {
       message: "request to cross-origin redirects to another cross-origin and finally go to the other cross-origin URL",
       requestURL: "http://example.com/tests/content/base/test/file_XHRResponseURL.sjs?url=" + encodeURIComponent("http://example.org/tests/content/base/test/file_XHRResponseURL.sjs?url=http://test1.example.com/tests/content/base/test/file_XHRResponseURL.text"),
       responseURL: "http://test1.example.com/tests/content/base/test/file_XHRResponseURL.text",
       skip: isInWorker(),
       reason: "cross-origin redirect request not works on Workers, see bug 882458"
     },
+    {
+      message: "request URL has fragment",
+      requestURL: "http://mochi.test:8888/tests/content/base/test/file_XHRResponseURL.text#fragment",
+      responseURL: "http://mochi.test:8888/tests/content/base/test/file_XHRResponseURL.text"
+    },
 
     // tests for non-http(s) URL
     {
       message: "request to data: URL",
       requestURL: "data:text/plain,data",
       responseURL: "data:text/plain,data"
     },
     {
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -58,17 +58,17 @@ PRLogModuleInfo* gMediaStreamGraphLog;
 #  endif
 #else
 #  define LIFECYCLE_LOG(...)
 #endif
 
 /**
  * The singleton graph instance.
  */
-static MediaStreamGraphImpl* gGraph;
+static nsDataHashtable<nsUint32HashKey, MediaStreamGraphImpl*> gGraphs;
 
 MediaStreamGraphImpl::~MediaStreamGraphImpl()
 {
   NS_ASSERTION(IsEmpty(),
                "All streams should have been destroyed by messages from the main thread");
   STREAM_LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p destroyed", this));
   LIFECYCLE_LOG("MediaStreamGraphImpl::~MediaStreamGraphImpl\n");
 }
@@ -1628,19 +1628,20 @@ MediaStreamGraphImpl::RunInStableState(b
         // synchronously because it spins the event loop waiting for threads
         // to shut down, and we don't want to do that in a stable state handler.
         mLifecycleState = LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN;
         LIFECYCLE_LOG("Sending MediaStreamGraphShutDownRunnable %p", this);
         nsCOMPtr<nsIRunnable> event = new MediaStreamGraphShutDownRunnable(this );
         NS_DispatchToMainThread(event);
 
         LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this);
-        if (this == gGraph) {
+        MediaStreamGraphImpl* graph;
+        if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
           // null out gGraph if that's the graph being shut down
-          gGraph = nullptr;
+          gGraphs.Remove(mAudioChannel);
         }
       }
     } else {
       if (mLifecycleState <= LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) {
         MessageBlock* block = mBackMessageQueue.AppendElement();
         block->mMessages.SwapElements(mCurrentTaskMessageQueue);
         block->mGraphUpdateIndex = mNextGraphUpdateIndex;
         ++mNextGraphUpdateIndex;
@@ -1781,19 +1782,22 @@ MediaStreamGraphImpl::AppendMessage(Cont
 #endif
     aMessage->RunDuringShutdown();
 #ifdef DEBUG
     mCanRunMessagesSynchronously = true;
 #endif
     delete aMessage;
     if (IsEmpty() &&
         mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) {
-      if (gGraph == this) {
-        gGraph = nullptr;
+
+      MediaStreamGraphImpl* graph;
+      if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
+        gGraphs.Remove(mAudioChannel);
       }
+
       Destroy();
     }
     return;
   }
 
   mCurrentTaskMessageQueue.AppendElement(aMessage);
   EnsureRunInStableState();
 }
@@ -2731,16 +2735,17 @@ MediaStreamGraphImpl::MediaStreamGraphIm
 #endif
   , mMemoryReportMonitor("MSGIMemory")
   , mSelfRef(MOZ_THIS_IN_INITIALIZER_LIST())
   , mAudioStreamSizes()
   , mNeedsMemoryReport(false)
 #ifdef DEBUG
   , mCanRunMessagesSynchronously(false)
 #endif
+  , mAudioChannel(static_cast<uint32_t>(aChannel))
 {
 #ifdef PR_LOGGING
   if (!gMediaStreamGraphLog) {
     gMediaStreamGraphLog = PR_NewLogModule("MediaStreamGraph");
   }
 #endif
 
   if (mRealtime) {
@@ -2769,50 +2774,65 @@ MediaStreamGraphImpl::Destroy()
   // Clear the self reference which will destroy this instance.
   mSelfRef = nullptr;
 }
 
 NS_IMPL_ISUPPORTS(MediaStreamGraphShutdownObserver, nsIObserver)
 
 static bool gShutdownObserverRegistered = false;
 
+namespace {
+
+PLDHashOperator
+ForceShutdownEnumerator(const uint32_t& /* aAudioChannel */,
+                        MediaStreamGraphImpl* aGraph,
+                        void* /* aUnused */)
+{
+  aGraph->ForceShutDown();
+  return PL_DHASH_NEXT;
+}
+
+} // anonymous namespace
+
 NS_IMETHODIMP
 MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject,
                                           const char *aTopic,
                                           const char16_t *aData)
 {
   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
-    if (gGraph) {
-      gGraph->ForceShutDown();
-    }
+    gGraphs.EnumerateRead(ForceShutdownEnumerator, nullptr);
     nsContentUtils::UnregisterShutdownObserver(this);
     gShutdownObserverRegistered = false;
   }
   return NS_OK;
 }
 
 MediaStreamGraph*
 MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioChannel aChannel)
 {
   NS_ASSERTION(NS_IsMainThread(), "Main thread only");
 
-  if (!gGraph) {
+  uint32_t channel = static_cast<uint32_t>(aChannel);
+  MediaStreamGraphImpl* graph = nullptr;
+
+  if (!gGraphs.Get(channel, &graph)) {
     if (!gShutdownObserverRegistered) {
       gShutdownObserverRegistered = true;
       nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
     }
 
     CubebUtils::InitPreferredSampleRate();
 
-    gGraph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
+    graph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
+    gGraphs.Put(channel, graph);
 
-    STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph));
+    STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", graph));
   }
 
-  return gGraph;
+  return graph;
 }
 
 MediaStreamGraph*
 MediaStreamGraph::CreateNonRealtimeInstance(TrackRate aSampleRate)
 {
   NS_ASSERTION(NS_IsMainThread(), "Main thread only");
 
   MediaStreamGraphImpl* graph = new MediaStreamGraphImpl(false, aSampleRate);
@@ -2973,17 +2993,20 @@ MediaStreamGraph::CreateAudioNodeStream(
   }
   graph->AppendMessage(new CreateMessage(stream));
   return stream;
 }
 
 bool
 MediaStreamGraph::IsNonRealtime() const
 {
-  return this != gGraph;
+  const MediaStreamGraphImpl* impl = static_cast<const MediaStreamGraphImpl*>(this);
+  MediaStreamGraphImpl* graph;
+
+  return !gGraphs.Get(impl->AudioChannel(), &graph) || graph != impl;
 }
 
 void
 MediaStreamGraph::StartNonRealtimeProcessing(TrackRate aRate, uint32_t aTicksToProcess)
 {
   NS_ASSERTION(NS_IsMainThread(), "main thread only");
 
   MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(this);
--- a/content/media/MediaStreamGraphImpl.h
+++ b/content/media/MediaStreamGraphImpl.h
@@ -649,16 +649,18 @@ public:
    * Hold a ref to the Latency logger
    */
   nsRefPtr<AsyncLatencyLogger> mLatencyLog;
   AudioMixer mMixer;
 #ifdef MOZ_WEBRTC
   nsRefPtr<AudioOutputObserver> mFarendObserverRef;
 #endif
 
+  uint32_t AudioChannel() const { return mAudioChannel; }
+
 private:
   virtual ~MediaStreamGraphImpl();
 
   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
 
   /**
    * Used to signal that a memory report has been requested.
    */
@@ -682,13 +684,16 @@ private:
 
 #ifdef DEBUG
   /**
    * Used to assert when AppendMessage() runs ControlMessages synchronously.
    */
   bool mCanRunMessagesSynchronously;
 #endif
 
+  // We use uint32_t instead AudioChannel because this is just used as key for
+  // the hashtable gGraphs.
+  uint32_t mAudioChannel;
 };
 
 }
 
 #endif /* MEDIASTREAMGRAPHIMPL_H_ */
--- a/content/media/VideoUtils.h
+++ b/content/media/VideoUtils.h
@@ -163,19 +163,21 @@ static const int32_t MAX_VIDEO_WIDTH = 4
 static const int32_t MAX_VIDEO_HEIGHT = 3000;
 
 // Scales the display rect aDisplay by aspect ratio aAspectRatio.
 // Note that aDisplay must be validated by IsValidVideoRegion()
 // before being used!
 void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio);
 
 // The amount of virtual memory reserved for thread stacks.
-#if (defined(XP_WIN) || defined(LINUX)) && !defined(MOZ_ASAN)
-#define MEDIA_THREAD_STACK_SIZE (128 * 1024)
-#elif defined(XP_MACOSX) && !defined(MOZ_ASAN)
+#if defined(MOZ_ASAN)
+// Use the system default in ASAN builds, because the default is assumed to be
+// larger than the size we want to use and is hopefully sufficient for ASAN.
+#define MEDIA_THREAD_STACK_SIZE nsIThreadManager::DEFAULT_STACK_SIZE
+#elif defined(XP_WIN) || defined(XP_MACOSX) || defined(LINUX)
 #define MEDIA_THREAD_STACK_SIZE (256 * 1024)
 #else
 // All other platforms use their system defaults.
 #define MEDIA_THREAD_STACK_SIZE nsIThreadManager::DEFAULT_STACK_SIZE
 #endif
 
 // Downmix multichannel Audio samples to Stereo.
 // Input are the buffer contains multichannel data,
--- a/content/media/gmp/GMPChild.cpp
+++ b/content/media/gmp/GMPChild.cpp
@@ -258,18 +258,22 @@ GMPChild::LoadPluginLibrary(const std::s
     return false;
   }
 #if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
   nsAutoCString nativePath;
   libFile->GetNativePath(nativePath);
 
   // Enable sandboxing here -- we know the plugin file's path, but
   // this process's execution hasn't been affected by its content yet.
-  MOZ_ASSERT(mozilla::CanSandboxMediaPlugin());
-  mozilla::SetMediaPluginSandbox(nativePath.get());
+  if (mozilla::CanSandboxMediaPlugin()) {
+    mozilla::SetMediaPluginSandbox(nativePath.get());
+  } else {
+    printf_stderr("GMPChild::LoadPluginLibrary: Loading media plugin %s unsandboxed.\n",
+                  nativePath.get());
+  }
 #endif // XP_LINUX && MOZ_GMP_SANDBOX
 
   libFile->Load(&mLib);
 #endif // XP_MACOSX && MOZ_GMP_SANDBOX
 
   if (!mLib) {
     NS_WARNING("Failed to link Gecko Media Plugin library.");
     return false;
--- a/content/media/gmp/GMPParent.cpp
+++ b/content/media/gmp/GMPParent.cpp
@@ -13,16 +13,19 @@
 #include "nsCharSeparatedTokenizer.h"
 #include "nsThreadUtils.h"
 #include "nsIRunnable.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "mozilla/unused.h"
 #include "nsIObserverService.h"
 #include "GMPTimerParent.h"
 #include "runnable_utils.h"
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+#include "mozilla/Sandbox.h"
+#endif
 
 #include "mozilla/dom/CrashReporterParent.h"
 using mozilla::dom::CrashReporterParent;
 
 #ifdef MOZ_CRASHREPORTER
 using CrashReporter::AnnotationTable;
 using CrashReporter::GetIDFromMinidump;
 #endif
@@ -847,16 +850,27 @@ GMPParent::ReadGMPMetaData()
         nsCCharSeparatedTokenizer tagTokens(ts, ':');
         while (tagTokens.hasMoreTokens()) {
           const nsDependentCSubstring tag(tagTokens.nextToken());
           cap->mAPITags.AppendElement(tag);
         }
       }
     }
 
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+    if (cap->mAPIName.EqualsLiteral("eme-decrypt") &&
+        !mozilla::CanSandboxMediaPlugin()) {
+      printf_stderr("GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM"
+                    " but this system can't sandbox it; not loading.\n",
+                    mDisplayName.get());
+      delete cap;
+      return NS_ERROR_FAILURE;
+    }
+#endif
+
     mCapabilities.AppendElement(cap);
   }
 
   if (mCapabilities.IsEmpty()) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
--- a/content/media/gmp/GMPService.cpp
+++ b/content/media/gmp/GMPService.cpp
@@ -430,16 +430,24 @@ GeckoMediaPluginService::GetGMPVideoEnco
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
                                          const nsAString& aOrigin,
                                          GMPDecryptorProxy** aDecryptor)
 {
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+  if (!mozilla::CanSandboxMediaPlugin()) {
+    NS_WARNING("GeckoMediaPluginService::GetGMPDecryptor: "
+               "EME decryption not available without sandboxing support.");
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+#endif
+
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
   NS_ENSURE_ARG(aDecryptor);
 
   if (mShuttingDownOnGMPThread) {
     return NS_ERROR_FAILURE;
   }
 
@@ -620,21 +628,16 @@ GeckoMediaPluginService::PathRunnable::R
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory)
 {
   MOZ_ASSERT(NS_IsMainThread());
-#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
-  if (!mozilla::CanSandboxMediaPlugin()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-#endif
   nsCOMPtr<nsIThread> thread;
   nsresult rv = GetThread(getter_AddRefs(thread));
   if (NS_FAILED(rv)) {
     return rv;
   }
   nsCOMPtr<nsIRunnable> r = new PathRunnable(this, aDirectory, true);
   thread->Dispatch(r, NS_DISPATCH_NORMAL);
   return NS_OK;
--- a/content/media/gtest/TestWebMWriter.cpp
+++ b/content/media/gtest/TestWebMWriter.cpp
@@ -235,18 +235,17 @@ struct WebMioData {
 
 static int webm_read(void* aBuffer, size_t aLength, void* aUserData)
 {
   NS_ASSERTION(aUserData, "aUserData must point to a valid WebMioData");
   WebMioData* ioData = static_cast<WebMioData*>(aUserData);
 
   // Check the read length.
   if (aLength > ioData->data.Length()) {
-    NS_ERROR("Invalid read length");
-    return -1;
+    return 0;
   }
 
   // Check eos.
   if (ioData->offset.value() >= ioData->data.Length()) {
     return 0;
   }
 
   size_t oldOffset = ioData->offset.value();
@@ -287,17 +286,17 @@ static int webm_seek(int64_t aOffset, in
       return -1;
   }
 
   if (!ioData->offset.isValid()) {
     NS_ERROR("Invalid offset");
     return -1;
   }
 
-  return 1;
+  return 0;
 }
 
 static int64_t webm_tell(void* aUserData)
 {
   NS_ASSERTION(aUserData, "aUserData must point to a valid WebMioData");
   WebMioData* ioData = static_cast<WebMioData*>(aUserData);
   return ioData->offset.isValid() ? ioData->offset.value() : -1;
 }
--- a/content/media/mediasource/SourceBuffer.cpp
+++ b/content/media/mediasource/SourceBuffer.cpp
@@ -284,17 +284,25 @@ SourceBuffer::StartUpdating()
   mUpdating = true;
   QueueAsyncSimpleEvent("updatestart");
 }
 
 void
 SourceBuffer::StopUpdating()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mUpdating);
+  if (!mUpdating) {
+    // The buffer append algorithm has been interrupted by abort().
+    //
+    // If the sequence appendBuffer(), abort(), appendBuffer() occurs before
+    // the first StopUpdating() runnable runs, then a second StopUpdating()
+    // runnable will be scheduled, but still only one (the first) will queue
+    // events.
+    return;
+  }
   mUpdating = false;
   QueueAsyncSimpleEvent("update");
   QueueAsyncSimpleEvent("updateend");
 }
 
 void
 SourceBuffer::AbortUpdating()
 {
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -643,22 +643,16 @@ AudioContext::Unmute() const
 }
 
 AudioChannel
 AudioContext::MozAudioChannelType() const
 {
   return mDestination->MozAudioChannelType();
 }
 
-void
-AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
-{
-  mDestination->SetMozAudioChannelType(aValue, aRv);
-}
-
 AudioChannel
 AudioContext::TestAudioChannelInAudioNodeStream()
 {
   MediaStream* stream = mDestination->Stream();
   MOZ_ASSERT(stream);
 
   return stream->AudioChannelType();
 }
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -217,17 +217,16 @@ public:
   uint32_t MaxChannelCount() const;
 
   void Mute() const;
   void Unmute() const;
 
   JSObject* GetGlobalJSObject() const;
 
   AudioChannel MozAudioChannelType() const;
-  void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
 
   AudioChannel TestAudioChannelInAudioNodeStream();
 
   void UpdateNodeCount(int32_t aDelta);
 
   double DOMTimeToStreamTime(double aTime) const
   {
     return aTime - ExtraCurrentTime();
--- a/content/media/webaudio/OscillatorNode.cpp
+++ b/content/media/webaudio/OscillatorNode.cpp
@@ -371,40 +371,43 @@ public:
                      uint32_t aEnd)
   {
     MOZ_ASSERT(mPeriodicWave, "No custom waveform data");
 
     uint32_t periodicWaveSize = mPeriodicWave->periodicWaveSize();
     float* higherWaveData = nullptr;
     float* lowerWaveData = nullptr;
     float tableInterpolationFactor;
-    float rate = 1.0 / mSource->SampleRate();
- 
+    // Phase increment at frequency of 1 Hz.
+    // mPhase runs [0,periodicWaveSize) here instead of [0,2*M_PI).
+    float basePhaseIncrement =
+      static_cast<float>(periodicWaveSize) / mSource->SampleRate();
+
     for (uint32_t i = aStart; i < aEnd; ++i) {
       UpdateParametersIfNeeded(ticks, i);
       mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
                                                      lowerWaveData,
                                                      higherWaveData,
                                                      tableInterpolationFactor);
-      // mPhase runs 0..periodicWaveSize here instead of 0..2*M_PI.
-      mPhase += periodicWaveSize * mFinalFrequency * rate;
       mPhase = fmod(mPhase, periodicWaveSize);
       // Bilinear interpolation between adjacent samples in each table.
       uint32_t j1 = floor(mPhase);
       uint32_t j2 = j1 + 1;
       if (j2 >= periodicWaveSize) {
         j2 -= periodicWaveSize;
       }
       float sampleInterpolationFactor = mPhase - j1;
-      float lower = sampleInterpolationFactor * lowerWaveData[j1] +
-                    (1 - sampleInterpolationFactor) * lowerWaveData[j2];
-      float higher = sampleInterpolationFactor * higherWaveData[j1] +
-                    (1 - sampleInterpolationFactor) * higherWaveData[j2];
-      aOutput[i] = tableInterpolationFactor * lower +
-                   (1 - tableInterpolationFactor) * higher;
+      float lower = (1.0f - sampleInterpolationFactor) * lowerWaveData[j1] +
+                    sampleInterpolationFactor * lowerWaveData[j2];
+      float higher = (1.0f - sampleInterpolationFactor) * higherWaveData[j1] +
+                    sampleInterpolationFactor * higherWaveData[j2];
+      aOutput[i] = (1.0f - tableInterpolationFactor) * lower +
+                   tableInterpolationFactor * higher;
+
+      mPhase += basePhaseIncrement * mFinalFrequency;
     }
   }
 
   void ComputeSilence(AudioChunk *aOutput)
   {
     aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
   }
 
--- a/content/media/webaudio/test/test_mozaudiochannel.html
+++ b/content/media/webaudio/test/test_mozaudiochannel.html
@@ -13,37 +13,33 @@
 
 function test_basic() {
   var ac = new AudioContext();
   ok(ac, "AudioContext created");
 
   // Default
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  // random wrong channel
-  ac.mozAudioChannelType = "foo";
+  // Unpermitted channels
+  ac = new AudioContext("content");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  // Unpermitted channels
-  ac.mozAudioChannelType = "content";
-  is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
-
-  ac.mozAudioChannelType = "notification";
+  ac = new AudioContext("notification");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  ac.mozAudioChannelType = "alarm";
+  ac = new AudioContext("alarm");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  ac.mozAudioChannelType = "telephony";
+  ac = new AudioContext("telephony");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  ac.mozAudioChannelType = "ringer";
+  ac = new AudioContext("ringer");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  ac.mozAudioChannelType = "publicnotification";
+  ac = new AudioContext("publicnotification");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
   runTest();
 }
 
 function test_permission(aChannel) {
   var ac = new AudioContext();
   ok(ac, "AudioContext created");
@@ -51,17 +47,17 @@ function test_permission(aChannel) {
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
   var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
   is(channel, "normal", "AudioNodeStream is using the correct default audio channel.");
 
   SpecialPowers.pushPermissions(
     [{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }],
     function() {
-      ac.mozAudioChannelType = aChannel;
+      var ac = new AudioContext(aChannel);
       is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
 
       var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
       is(channel, aChannel, "AudioNodeStream is using the correct new audio channel.");
 
       runTest();
     }
   );
--- a/content/media/webaudio/test/test_periodicWave.html
+++ b/content/media/webaudio/test/test_periodicWave.html
@@ -6,29 +6,89 @@
   <script type="text/javascript" src="webaudio.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
+
+// real and imag are used in separate PeriodicWaves to make their peak values
+// easy to determine.
+const realMax = 99;
+var real = new Float32Array(realMax + 1);
+real[1] = 2.0; // fundamental
+real[realMax] = 3.0;
+const realPeak = real[1] + real[realMax];
+const realFundamental = 19.0;
+var imag = new Float32Array(4);
+imag[0] = 6.0; // should be ignored.
+imag[3] = 0.5;
+const imagPeak = imag[3];
+const imagFundamental = 551.0;
+
+const testLength = 4096;
+
 addLoadEvent(function() {
   var ac = new AudioContext();
-  var real = new Float32Array(4096);
-  var imag = new Float32Array(4096);
-  var table = ac.createPeriodicWave(real, imag);
+  ac.createPeriodicWave(new Float32Array(4096), new Float32Array(4096));
   expectException(function() {
     ac.createPeriodicWave(new Float32Array(512), imag);
   }, DOMException.NOT_SUPPORTED_ERR);
   expectException(function() {
     ac.createPeriodicWave(new Float32Array(0), new Float32Array(0));
   }, DOMException.NOT_SUPPORTED_ERR);
   expectException(function() {
     ac.createPeriodicWave(new Float32Array(4097), new Float32Array(4097));
   }, DOMException.NOT_SUPPORTED_ERR);
-  SimpleTest.finish();
+
+  runTest();
 });
 
+var gTest = {
+  createGraph: function(context) {
+    var merger = context.createChannelMerger();
+
+    var osc0 = context.createOscillator();
+    var osc1 = context.createOscillator();
+
+    osc0.setPeriodicWave(context.
+                         createPeriodicWave(real,
+                                            new Float32Array(real.length)));
+    osc1.setPeriodicWave(context.
+                         createPeriodicWave(new Float32Array(imag.length),
+                                            imag));
+
+    osc0.frequency.value = realFundamental;
+    osc1.frequency.value = imagFundamental;
+
+    osc0.start();
+    osc1.start();
+
+    osc0.connect(merger, 0, 0);
+    osc1.connect(merger, 0, 1);
+
+    return merger;
+  },
+  createExpectedBuffers: function(context) {
+    var buffer = context.createBuffer(2, testLength, context.sampleRate);
+
+    for (var i = 0; i < buffer.length; ++i) {
+
+      buffer.getChannelData(0)[i] = 1.0 / realPeak *
+        (real[1] * Math.cos(2 * Math.PI * realFundamental * i /
+                            context.sampleRate) +
+         real[realMax] * Math.cos(2 * Math.PI * realMax * realFundamental * i /
+                            context.sampleRate));
+
+      buffer.getChannelData(1)[i] = 1.0 / imagPeak *
+         imag[3] * Math.sin(2 * Math.PI * 3 * imagFundamental * i /
+                            context.sampleRate);
+    }
+    return buffer;
+  },
+};
+
 </script>
 </pre>
 </body>
 </html>
--- a/dom/bindings/test/TestInterfaceJS.js
+++ b/dom/bindings/test/TestInterfaceJS.js
@@ -51,11 +51,14 @@ TestInterfaceJS.prototype = {
   pingPongUnion: function(x) { return x; },
   pingPongUnionContainingNull: function(x) { return x; },
   pingPongNullableUnion: function(x) { return x; },
   returnBadUnion: function(x) { return 3; },
 
   get cachedAttr() { return this._cachedAttr; },
   setCachedAttr: function(n) { this._cachedAttr = n; },
   clearCachedAttrCache: function () { this.__DOM_IMPL__._clearCachedCachedAttrValue(); },
+
+  testSequenceOverload: function(arg) {},
+  testSequenceUnion: function(arg) {},
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS])
--- a/dom/bindings/test/mochitest.ini
+++ b/dom/bindings/test/mochitest.ini
@@ -45,8 +45,10 @@ skip-if = (toolkit == 'gonk' && debug) #
 skip-if = debug == false
 [test_scalarvaluestring.html]
 skip-if = debug == false
 [test_sequence_wrapping.html]
 [test_setWithNamedGetterNoNamedSetter.html]
 [test_throwing_method_noDCE.html]
 [test_treat_non_object_as_null.html]
 [test_traceProtos.html]
+[test_sequence_detection.html]
+skip-if = debug == false
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_sequence_detection.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1066432
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1066432</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1066432 **/
+  SimpleTest.waitForExplicitFinish();
+  SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() {
+    var testInterfaceJS = new TestInterfaceJS();
+    ok(testInterfaceJS, "got a TestInterfaceJS object");
+    try {
+      testInterfaceJS.testSequenceOverload(
+        { "@@iterator": 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] });
+      ok(false, "Should have thrown in the overload case");
+    } catch (e) {
+      ise(e.name, "TypeError", "Should get a TypeError for the overload case");
+      ok(e.message.contains("not iterable"),
+         "Should have a message about being non-iterable in the overload case");
+    }
+
+    try {
+      testInterfaceJS.testSequenceUnion(
+        { "@@iterator": 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] });
+      ok(false, "Should have thrown in the union case");
+    } catch (e) {
+      ise(e.name, "TypeError", "Should get a TypeError for the union case");
+      ok(e.message.contains("not iterable"),
+         "Should have a message about being non-iterable in the union case");
+    }
+
+    SimpleTest.finish();
+  });
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1066432">Mozilla Bug 1066432</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/bluetooth2/ipc/BluetoothServiceChildProcess.cpp
+++ b/dom/bluetooth2/ipc/BluetoothServiceChildProcess.cpp
@@ -5,16 +5,17 @@
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "BluetoothServiceChildProcess.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ipc/BlobChild.h"
 
 #include "BluetoothChild.h"
 #include "MainThreadUtils.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 namespace {
 
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -819,36 +819,36 @@ private:
     oaepParams.mgf = mMgfMechanism;
     oaepParams.hashAlg = mHashMechanism;
 
     SECItem param;
     param.type = siBuffer;
     param.data = (unsigned char*) &oaepParams;
     param.len = sizeof(oaepParams);
 
-    uint32_t outLen;
+    uint32_t outLen = 0;
     if (mEncrypt) {
       // PK11_PubEncrypt() checks the plaintext's length and fails if it is too
       // long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
       // being the length in octets of the RSA modulus n and 'hLen' being the
       // output length in octets of the chosen hash function.
       // <https://tools.ietf.org/html/rfc3447#section-7.1>
       rv = MapSECStatus(PK11_PubEncrypt(
              mPubKey.get(), CKM_RSA_PKCS_OAEP, &param,
              mResult.Elements(), &outLen, mResult.Length(),
              mData.Elements(), mData.Length(), nullptr));
     } else {
       rv = MapSECStatus(PK11_PrivDecrypt(
              mPrivKey.get(), CKM_RSA_PKCS_OAEP, &param,
              mResult.Elements(), &outLen, mResult.Length(),
              mData.Elements(), mData.Length()));
     }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
+
     mResult.SetLength(outLen);
-
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
     return NS_OK;
   }
 };
 
 class HmacTask : public WebCryptoTask
 {
 public:
   HmacTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
--- a/dom/fmradio/FMRadio.cpp
+++ b/dom/fmradio/FMRadio.cpp
@@ -8,16 +8,17 @@
 #include "nsContentUtils.h"
 #include "mozilla/Hal.h"
 #include "mozilla/HalTypes.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/FMRadioBinding.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PFMRadioChild.h"
 #include "mozilla/dom/FMRadioService.h"
+#include "mozilla/dom/TypedArray.h"
 #include "DOMRequest.h"
 #include "nsDOMClassInfo.h"
 #include "nsIDocShell.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIAudioManager.h"
 
 #undef LOG
 #define LOG(args...) FM_LOG("FMRadio", args)
@@ -100,16 +101,17 @@ private:
   FMRadioRequestArgs::Type mType;
   nsWeakPtr mFMRadio;
 };
 
 NS_IMPL_ISUPPORTS_INHERITED0(FMRadioRequest, DOMRequest)
 
 FMRadio::FMRadio()
   : mHeadphoneState(SWITCH_STATE_OFF)
+  , mRdsGroupMask(0)
   , mAudioChannelAgentEnabled(false)
   , mHasInternalAntenna(false)
   , mIsShutdown(false)
 {
   LOG("FMRadio is initialized.");
 
   SetIsDOMBinding();
 }
@@ -215,29 +217,57 @@ FMRadio::Notify(const FMRadioEventType& 
         if (mAudioChannelAgentEnabled) {
           mAudioChannelAgent->StopPlaying();
           mAudioChannelAgentEnabled = false;
         }
 
         DispatchTrustedEvent(NS_LITERAL_STRING("disabled"));
       }
       break;
+    case RDSEnabledChanged:
+      if (RdsEnabled()) {
+        DispatchTrustedEvent(NS_LITERAL_STRING("rdsenabled"));
+      } else {
+        DispatchTrustedEvent(NS_LITERAL_STRING("rdsdisabled"));
+      }
+      break;
+    case PIChanged:
+      DispatchTrustedEvent(NS_LITERAL_STRING("pichange"));
+      break;
+    case PSChanged:
+      DispatchTrustedEvent(NS_LITERAL_STRING("pschange"));
+      break;
+    case RadiotextChanged:
+      DispatchTrustedEvent(NS_LITERAL_STRING("rtchange"));
+      break;
+    case PTYChanged:
+      DispatchTrustedEvent(NS_LITERAL_STRING("ptychange"));
+      break;
+    case NewRDSGroup:
+      DispatchTrustedEvent(NS_LITERAL_STRING("newrdsgroup"));
+      break;
     default:
       MOZ_CRASH();
   }
 }
 
 /* static */
 bool
 FMRadio::Enabled()
 {
   return IFMRadioService::Singleton()->IsEnabled();
 }
 
 bool
+FMRadio::RdsEnabled()
+{
+  return IFMRadioService::Singleton()->IsRDSEnabled();
+}
+
+bool
 FMRadio::AntennaAvailable() const
 {
   return mHasInternalAntenna ? true : (mHeadphoneState != SWITCH_STATE_OFF) &&
     (mHeadphoneState != SWITCH_STATE_UNKNOWN);
 }
 
 Nullable<double>
 FMRadio::GetFrequency() const
@@ -260,16 +290,79 @@ FMRadio::FrequencyLowerBound() const
 }
 
 double
 FMRadio::ChannelWidth() const
 {
   return IFMRadioService::Singleton()->GetChannelWidth();
 }
 
+uint32_t
+FMRadio::RdsGroupMask() const
+{
+  return mRdsGroupMask;
+}
+
+void
+FMRadio::SetRdsGroupMask(uint32_t aRdsGroupMask)
+{
+  mRdsGroupMask = aRdsGroupMask;
+  IFMRadioService::Singleton()->SetRDSGroupMask(aRdsGroupMask);
+}
+
+Nullable<unsigned short>
+FMRadio::GetPi() const
+{
+  return IFMRadioService::Singleton()->GetPi();
+}
+
+Nullable<uint8_t>
+FMRadio::GetPty() const
+{
+  return IFMRadioService::Singleton()->GetPty();
+}
+
+void
+FMRadio::GetPs(DOMString& aPsname) const
+{
+  if (!IFMRadioService::Singleton()->GetPs(aPsname)) {
+    aPsname.SetNull();
+  }
+}
+
+void
+FMRadio::GetRt(DOMString& aRadiotext) const
+{
+  if (!IFMRadioService::Singleton()->GetRt(aRadiotext)) {
+    aRadiotext.SetNull();
+  }
+}
+
+void
+FMRadio::GetRdsgroup(JSContext* cx, JS::MutableHandle<JSObject*> retval)
+{
+  uint64_t group;
+  if (!IFMRadioService::Singleton()->GetRdsgroup(group)) {
+    return;
+  }
+
+  JSObject *rdsgroup = Uint16Array::Create(cx, this, 4);
+  uint16_t *data = JS_GetUint16ArrayData(rdsgroup);
+  data[3] = group & 0xFFFF;
+  group >>= 16;
+  data[2] = group & 0xFFFF;
+  group >>= 16;
+  data[1] = group & 0xFFFF;
+  group >>= 16;
+  data[0] = group & 0xFFFF;
+
+  JS::ExposeObjectToActiveJS(rdsgroup);
+  retval.set(rdsgroup);
+}
+
 already_AddRefed<DOMRequest>
 FMRadio::Enable(double aFrequency)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     return nullptr;
   }
 
@@ -345,16 +438,42 @@ FMRadio::CancelSeek()
   }
 
   nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
   IFMRadioService::Singleton()->CancelSeek(r);
 
   return r.forget();
 }
 
+already_AddRefed<DOMRequest>
+FMRadio::EnableRDS()
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    return nullptr;
+  }
+
+  nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
+  IFMRadioService::Singleton()->EnableRDS(r);
+  return r.forget();
+}
+
+already_AddRefed<DOMRequest>
+FMRadio::DisableRDS()
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    return nullptr;
+  }
+
+  nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
+  FMRadioService::Singleton()->DisableRDS(r);
+  return r.forget();
+}
+
 NS_IMETHODIMP
 FMRadio::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString type;
   aEvent->GetType(type);
 
   if (!type.EqualsLiteral("visibilitychange")) {
     return NS_ERROR_FAILURE;
--- a/dom/fmradio/FMRadio.h
+++ b/dom/fmradio/FMRadio.h
@@ -50,53 +50,81 @@ public:
   {
     return GetOwner();
   }
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   static bool Enabled();
 
+  bool RdsEnabled();
+
   bool AntennaAvailable() const;
 
   Nullable<double> GetFrequency() const;
 
   double FrequencyUpperBound() const;
 
   double FrequencyLowerBound() const;
 
   double ChannelWidth() const;
 
+  uint32_t RdsGroupMask() const;
+
+  void SetRdsGroupMask(uint32_t aRdsGroupMask);
+
+  Nullable<unsigned short> GetPi() const;
+
+  Nullable<uint8_t> GetPty() const;
+
+  void GetPs(DOMString& aPsname) const;
+
+  void GetRt(DOMString& aRadiotext) const;
+
+  void GetRdsgroup(JSContext* cx, JS::MutableHandle<JSObject*> retval);
+
   already_AddRefed<DOMRequest> Enable(double aFrequency);
 
   already_AddRefed<DOMRequest> Disable();
 
   already_AddRefed<DOMRequest> SetFrequency(double aFrequency);
 
   already_AddRefed<DOMRequest> SeekUp();
 
   already_AddRefed<DOMRequest> SeekDown();
 
   already_AddRefed<DOMRequest> CancelSeek();
 
+  already_AddRefed<DOMRequest> EnableRDS();
+
+  already_AddRefed<DOMRequest> DisableRDS();
+
   IMPL_EVENT_HANDLER(enabled);
   IMPL_EVENT_HANDLER(disabled);
+  IMPL_EVENT_HANDLER(rdsenabled);
+  IMPL_EVENT_HANDLER(rdsdisabled);
   IMPL_EVENT_HANDLER(antennaavailablechange);
   IMPL_EVENT_HANDLER(frequencychange);
+  IMPL_EVENT_HANDLER(pichange);
+  IMPL_EVENT_HANDLER(ptychange);
+  IMPL_EVENT_HANDLER(pschange);
+  IMPL_EVENT_HANDLER(rtchange);
+  IMPL_EVENT_HANDLER(newrdsgroup);
 
   // nsIDOMEventListener
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
 
 private:
   ~FMRadio();
 
   void SetCanPlay(bool aCanPlay);
   void EnableAudioChannelAgent();
 
   hal::SwitchState mHeadphoneState;
+  uint32_t mRdsGroupMask;
   bool mAudioChannelAgentEnabled;
   bool mHasInternalAntenna;
   bool mIsShutdown;
 
   nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
 };
 
 END_FMRADIO_NAMESPACE
--- a/dom/fmradio/FMRadioCommon.h
+++ b/dom/fmradio/FMRadioCommon.h
@@ -25,17 +25,23 @@
 #define END_FMRADIO_NAMESPACE \
   } /* namespace dom */ } /* namespace mozilla */
 
 BEGIN_FMRADIO_NAMESPACE
 
 enum FMRadioEventType
 {
   FrequencyChanged,
-  EnabledChanged
+  EnabledChanged,
+  RDSEnabledChanged,
+  PIChanged,
+  PSChanged,
+  PTYChanged,
+  RadiotextChanged,
+  NewRDSGroup
 };
 
 typedef mozilla::Observer<FMRadioEventType>     FMRadioEventObserver;
 typedef mozilla::ObserverList<FMRadioEventType> FMRadioEventObserverList;
 
 END_FMRADIO_NAMESPACE
 
 #endif /* FMRADIOCOMMON_H_ */
--- a/dom/fmradio/FMRadioService.cpp
+++ b/dom/fmradio/FMRadioService.cpp
@@ -21,16 +21,18 @@
 
 #define BAND_87500_108000_kHz 1
 #define BAND_76000_108000_kHz 2
 #define BAND_76000_90000_kHz  3
 
 #define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
 #define SETTING_KEY_AIRPLANEMODE_ENABLED "airplaneMode.enabled"
 
+#define DOM_PARSED_RDS_GROUPS ((0x2 << 30) | (0x3 << 4) | (0x3 << 0))
+
 using namespace mozilla::hal;
 using mozilla::Preferences;
 
 BEGIN_FMRADIO_NAMESPACE
 
 // static
 IFMRadioService*
 IFMRadioService::Singleton()
@@ -44,19 +46,36 @@ IFMRadioService::Singleton()
 
 StaticRefPtr<FMRadioService> FMRadioService::sFMRadioService;
 
 FMRadioService::FMRadioService()
   : mPendingFrequencyInKHz(0)
   , mState(Disabled)
   , mHasReadAirplaneModeSetting(false)
   , mAirplaneModeEnabled(false)
+  , mRDSEnabled(false)
   , mPendingRequest(nullptr)
   , mObserverList(FMRadioEventObserverList())
+  , mRDSGroupMask(0)
+  , mLastPI(0)
+  , mPI(0)
+  , mPTY(0)
+  , mPISet(false)
+  , mPTYSet(false)
+  , mRDSLock("FMRadioService::mRDSLock")
+  , mPSNameState(0)
+  , mRadiotextAB(false)
+  , mRDSGroupSet(false)
+  , mPSNameSet(false)
+  , mRadiotextSet(false)
 {
+  memset(mPSName, 0, sizeof(mPSName));
+  memset(mRadiotext, 0, sizeof(mRadiotext));
+  memset(mTempPSName, 0, sizeof(mTempPSName));
+  memset(mTempRadiotext, 0, sizeof(mTempRadiotext));
 
   // Read power state and frequency from Hal.
   mEnabled = IsFMRadioOn();
   if (mEnabled) {
     mPendingFrequencyInKHz = GetFMRadioFrequency();
     SetState(Enabled);
   }
 
@@ -105,20 +124,22 @@ FMRadioService::FMRadioService()
 
   if (obs && NS_FAILED(obs->AddObserver(this,
                                         MOZSETTINGS_CHANGED_ID,
                                         /* useWeak */ false))) {
     NS_WARNING("Failed to add settings change observer!");
   }
 
   RegisterFMRadioObserver(this);
+  RegisterFMRadioRDSObserver(this);
 }
 
 FMRadioService::~FMRadioService()
 {
+  UnregisterFMRadioRDSObserver(this);
   UnregisterFMRadioObserver(this);
 }
 
 class EnableRunnable MOZ_FINAL : public nsRunnable
 {
 public:
   EnableRunnable(uint32_t aUpperLimit, uint32_t aLowerLimit, uint32_t aSpaceType, uint32_t aPreemphasis)
     : mUpperLimit(aUpperLimit)
@@ -272,16 +293,31 @@ public:
 
     return NS_OK;
   }
 
 private:
   FMRadioSeekDirection mDirection;
 };
 
+class NotifyRunnable MOZ_FINAL : public nsRunnable
+{
+public:
+  NotifyRunnable(FMRadioEventType aType) : mType(aType) { }
+
+  NS_IMETHOD Run()
+  {
+    FMRadioService::Singleton()->NotifyFMRadioEvent(mType);
+    return NS_OK;
+  }
+
+private:
+  FMRadioEventType mType;
+};
+
 void
 FMRadioService::TransitionState(const FMRadioResponseType& aResponse,
                                 FMRadioState aState)
 {
   if (mPendingRequest) {
     mPendingRequest->SetReply(aResponse);
     NS_DispatchToMainThread(mPendingRequest);
   }
@@ -369,16 +405,23 @@ FMRadioService::RoundFrequency(double aF
 
 bool
 FMRadioService::IsEnabled() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   return IsFMRadioOn();
 }
 
+bool
+FMRadioService::IsRDSEnabled() const
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+  return mRDSEnabled;
+}
+
 double
 FMRadioService::GetFrequency() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   if (IsEnabled()) {
     int32_t frequencyInKHz = GetFMRadioFrequency();
     return frequencyInKHz / 1000.0;
   }
@@ -402,16 +445,64 @@ FMRadioService::GetFrequencyLowerBound()
 
 double
 FMRadioService::GetChannelWidth() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   return mChannelWidthInKHz / 1000.0;
 }
 
+Nullable<unsigned short>
+FMRadioService::GetPi() const
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+  if (!mPISet) {
+    return Nullable<unsigned short>();
+  }
+  return Nullable<unsigned short>(mPI);
+}
+
+Nullable<uint8_t>
+FMRadioService::GetPty() const
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+  if (!mPTYSet) {
+    return Nullable<uint8_t>();
+  }
+  return Nullable<uint8_t>(mPTY);
+}
+
+bool
+FMRadioService::GetPs(nsString& aPSName)
+{
+  MutexAutoLock lock(mRDSLock);
+  if (mPSNameSet) {
+    aPSName = nsString(mPSName);
+  }
+  return mPSNameSet;
+}
+
+bool
+FMRadioService::GetRt(nsString& aRadiotext)
+{
+  MutexAutoLock lock(mRDSLock);
+  if (mRadiotextSet) {
+    aRadiotext = nsString(mRadiotext);
+  }
+  return mRadiotextSet;
+}
+
+bool
+FMRadioService::GetRdsgroup(uint64_t& aRDSGroup)
+{
+  MutexAutoLock lock(mRDSLock);
+  aRDSGroup = mRDSGroup;
+  return mRDSGroupSet;
+}
+
 void
 FMRadioService::Enable(double aFrequencyInMHz,
                        FMRadioReplyRunnable* aReplyRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   MOZ_ASSERT(aReplyRunnable);
 
   switch (mState) {
@@ -674,16 +765,57 @@ FMRadioService::CancelSeek(FMRadioReplyR
 
   TransitionState(
     ErrorResponse(NS_LITERAL_STRING("Seek action is cancelled")), Enabled);
 
   aReplyRunnable->SetReply(SuccessResponse());
   NS_DispatchToMainThread(aReplyRunnable);
 }
 
+void
+FMRadioService::SetRDSGroupMask(uint32_t aRDSGroupMask)
+{
+  mRDSGroupMask = aRDSGroupMask;
+  if (IsFMRadioOn()) {
+    hal::EnableRDS(mRDSGroupMask | DOM_PARSED_RDS_GROUPS);
+  }
+}
+
+void
+FMRadioService::EnableRDS(FMRadioReplyRunnable* aReplyRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+  MOZ_ASSERT(aReplyRunnable);
+
+  mRDSEnabled = true;
+  if (IsFMRadioOn()) {
+    hal::EnableRDS(mRDSGroupMask | DOM_PARSED_RDS_GROUPS);
+  }
+
+  aReplyRunnable->SetReply(SuccessResponse());
+  NS_DispatchToMainThread(aReplyRunnable);
+  NS_DispatchToMainThread(new NotifyRunnable(RDSEnabledChanged));
+}
+
+void
+FMRadioService::DisableRDS(FMRadioReplyRunnable* aReplyRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+  MOZ_ASSERT(aReplyRunnable);
+
+  mRDSEnabled = false;
+  if (IsFMRadioOn()) {
+    hal::DisableRDS();
+  }
+
+  aReplyRunnable->SetReply(SuccessResponse());
+  NS_DispatchToMainThread(aReplyRunnable);
+  NS_DispatchToMainThread(new NotifyRunnable(RDSEnabledChanged));
+}
+
 NS_IMETHODIMP
 FMRadioService::Observe(nsISupports* aSubject,
                         const char* aTopic,
                         const char16_t* aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(sFMRadioService);
 
@@ -755,20 +887,28 @@ FMRadioService::Notify(const FMRadioOper
       // event, to make sure the FM app will get the right frequency when the
       // `EnabledChange` event is sent.
       mPendingFrequencyInKHz = GetFMRadioFrequency();
       UpdatePowerState();
 
       // The frequency was changed from '0' to some meaningful number, so we
       // should send the `FrequencyChanged` event manually.
       NotifyFMRadioEvent(FrequencyChanged);
+
+      if (mRDSEnabled) {
+        hal::EnableRDS(mRDSGroupMask | DOM_PARSED_RDS_GROUPS);
+      }
       break;
     case FM_RADIO_OPERATION_DISABLE:
       MOZ_ASSERT(mState == Disabling);
 
+      mPISet = false;
+      mPTYSet = false;
+      memset(mPSName, 0, sizeof(mPSName));
+      memset(mRadiotext, 0, sizeof(mRadiotext));
       TransitionState(SuccessResponse(), Disabled);
       UpdatePowerState();
       break;
     case FM_RADIO_OPERATION_SEEK:
 
       // Seek action might be cancelled by SetFrequency(), we need to check if
       // the current state is Seeking.
       if (mState == Seeking) {
@@ -780,16 +920,284 @@ FMRadioService::Notify(const FMRadioOper
     case FM_RADIO_OPERATION_TUNE:
       UpdateFrequency();
       break;
     default:
       MOZ_CRASH();
   }
 }
 
+/* This is defined by the RDS standard */
+static const uint16_t sRDSToUnicodeMap[256] = {
+  // The lower half differs from ASCII in 0x1F, 0x24, 0x5E, 0x7E
+  // Most control characters are replaced with 0x20 (space)
+  // 0x0-
+  0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+  0x0020, 0x0009, 0x000A, 0x000B, 0x0020, 0x00D0, 0x0020, 0x0020,
+
+  // 0x1-
+  0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+  0x0020, 0x0020, 0x0020, 0x001B, 0x0020, 0x0020, 0x0020, 0x00AD,
+
+  // 0x2-
+  0x0020, 0x0021, 0x0022, 0x0023, 0x00A4, 0x0025, 0x0026, 0x0027,
+  0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+
+  // 0x3-
+  0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+  0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+
+  // 0x4-
+  0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+  0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+
+  // 0x5-
+  0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+  0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x2015, 0x005F,
+
+  // 0x6-
+  0x2551, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+  0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+
+  // 0x7-
+  0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+  0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x00AF, 0x007F,
+
+  // 0x8-
+  0x00E1, 0x00E0, 0x00E9, 0x00E8, 0x00ED, 0x00EC, 0x00F3, 0x00F2,
+  0x00FA, 0x00F9, 0x00D1, 0x00C7, 0x015E, 0x00DF, 0x00A1, 0x0132,
+
+  // 0x9-
+  0x00E2, 0x00E4, 0x00EA, 0x00EB, 0x00EE, 0x00EF, 0x00F4, 0x00F6,
+  0x00FB, 0x00FC, 0x00F1, 0x00E7, 0x015F, 0x011F, 0x0131, 0x0133,
+
+  // 0xA-
+  0x00AA, 0x03B1, 0x00A9, 0x2030, 0x011E, 0x011B, 0x0148, 0x0151,
+  0x03C0, 0x20AC, 0x00A3, 0x0024, 0x2190, 0x2191, 0x2192, 0x2193,
+
+  // 0xB-
+  0x00BA, 0x00B9, 0x00B2, 0x00B3, 0x00B1, 0x0130, 0x0144, 0x0171,
+  0x03BC, 0x00BF, 0x00F7, 0x00B0, 0x00BC, 0x00BD, 0x00BE, 0x00A7,
+
+  // 0xC-
+  0x00C1, 0x00C0, 0x00C9, 0x00C8, 0x00CD, 0x00CC, 0x00D3, 0x00D2,
+  0x00DA, 0x00D9, 0x0158, 0x010C, 0x0160, 0x017D, 0x00D0, 0x013F,
+
+  // 0xD-
+  0x00C2, 0x00C4, 0x00CA, 0x00CB, 0x00CE, 0x00CF, 0x00D4, 0x00D6,
+  0x00DB, 0x00DC, 0x0159, 0x010D, 0x0161, 0x017E, 0x0111, 0x0140,
+
+  // 0xE-
+  0x00C3, 0x00C5, 0x00C6, 0x0152, 0x0177, 0x00DD, 0x00D5, 0x00D8,
+  0x00DE, 0x014A, 0x0154, 0x0106, 0x015A, 0x0179, 0x0166, 0x00F0,
+
+  // 0xF-
+  0x00E3, 0x00E5, 0x00E6, 0x0153, 0x0175, 0x00FD, 0x00F5, 0x00F8,
+  0x00FE, 0x014B, 0x0155, 0x0107, 0x015B, 0x017A, 0x0167, 0x0020,
+};
+
+void
+FMRadioService::Notify(const FMRadioRDSGroup& aRDSGroup)
+{
+  uint16_t blocks[4];
+  blocks[0] = aRDSGroup.blockA();
+  blocks[1] = aRDSGroup.blockB();
+  blocks[2] = aRDSGroup.blockC();
+  blocks[3] = aRDSGroup.blockD();
+
+  /* Bit 11 in block B determines whether this is a type B group. */
+  uint16_t lastPI = blocks[1] & (1 << 11) ? blocks[2] : mLastPI;
+
+  /* Update PI if it's not set or if we get two PI with the new value. */
+  if ((mPI != blocks[0] && lastPI == blocks[0]) || !mPISet) {
+    mPI = blocks[0];
+    if (!mPISet) {
+      mPSNameState = 0;
+      mRadiotextState = 0;
+      memset(mTempPSName, 0, sizeof(mTempPSName));
+      memset(mTempRadiotext, 0, sizeof(mTempRadiotext));
+    }
+    mPISet = true;
+    NS_DispatchToMainThread(new NotifyRunnable(PIChanged));
+  }
+  mLastPI = blocks[0];
+
+  /* PTY is also updated using the same logic as PI */
+  uint16_t pty = (blocks[1] >> 5) & 0x1F;
+  if ((mPTY != pty && pty == mLastPTY) || !mPTYSet) {
+    mPTY = pty;
+    mPTYSet = true;
+    NS_DispatchToMainThread(new NotifyRunnable(PTYChanged));
+  }
+  mLastPTY = pty;
+
+  uint16_t grouptype = blocks[1] >> 11;
+  switch (grouptype) {
+    case 0: // 0a
+    case 1: // 0b
+    {
+      uint16_t segmentAddr = (blocks[1] & 0x3);
+      // mPSNameState is a bitmask that lets us ensure all segments
+      // are received before updating the PS name.
+      if (!segmentAddr) {
+        mPSNameState = 1;
+      } else {
+        mPSNameState |= 1 << segmentAddr;
+      }
+
+      uint16_t offset = segmentAddr << 1;
+      mTempPSName[offset] = sRDSToUnicodeMap[blocks[3] >> 8];
+      mTempPSName[offset + 1] = sRDSToUnicodeMap[blocks[3] & 0xFF];
+
+      if (mPSNameState != 0xF) {
+        break;
+      }
+
+      mPSNameState = 0;
+      if (memcmp(mTempPSName, mPSName, sizeof(mTempPSName))) {
+        MutexAutoLock lock(mRDSLock);
+        mPSNameSet = true;
+        memcpy(mPSName, mTempPSName, sizeof(mTempPSName));
+        NS_DispatchToMainThread(new NotifyRunnable(PSChanged));
+      }
+      break;
+    }
+    case 4: // 2a Radiotext
+    {
+      uint16_t segmentAddr = (blocks[1] & 0xF);
+      bool textAB = blocks[1] & (1 << 5);
+      if (textAB != mRadiotextAB) {
+        mRadiotextState = 0;
+        memset(mTempRadiotext, 0, sizeof(mTempRadiotext));
+        mRadiotextAB = textAB;
+        MutexAutoLock lock(mRDSLock);
+        memset(mRadiotext, 0, sizeof(mRadiotext));
+        NS_DispatchToMainThread(new NotifyRunnable(RadiotextChanged));
+      }
+
+      // mRadiotextState is a bitmask that lets us ensure all segments
+      // are received before updating the radiotext.
+      if (!segmentAddr) {
+        mRadiotextState = 1;
+      } else {
+        mRadiotextState |= 1 << segmentAddr;
+      }
+
+      uint8_t segment[4];
+      segment[0] = blocks[2] >> 8;
+      segment[1] = blocks[2] & 0xFF;
+      segment[2] = blocks[3] >> 8;
+      segment[3] = blocks[3] & 0xFF;
+
+      uint16_t offset = segmentAddr << 2;
+      bool done = false;
+      for (int i = 0; i < 4; i++) {
+        if (segment[i] == '\r') {
+          mTempRadiotext[offset++] = 0;
+          done = true;
+        } else {
+          mTempRadiotext[offset++] = sRDSToUnicodeMap[segment[i]];
+        }
+      }
+      if (offset == 64) {
+        done = true;
+      }
+
+      if (!done ||
+          (mRadiotextState + 1) != (1 << ((blocks[1] & 0xF) + 1)) ||
+          !memcmp(mTempRadiotext, mRadiotext, sizeof(mTempRadiotext))) {
+        break;
+      }
+
+      MutexAutoLock lock(mRDSLock);
+      mRadiotextSet = true;
+      memcpy(mRadiotext, mTempRadiotext, sizeof(mTempRadiotext));
+      NS_DispatchToMainThread(new NotifyRunnable(RadiotextChanged));
+      break;
+    }
+    case 5: // 2b Radiotext
+    {
+      uint16_t segmentAddr = (blocks[1] & 0xF);
+      bool textAB = blocks[1] & (1 << 5);
+      if (textAB != mRadiotextAB) {
+        mRadiotextState = 0;
+        memset(mTempRadiotext, 0, sizeof(mTempRadiotext));
+        mRadiotextAB = textAB;
+        MutexAutoLock lock(mRDSLock);
+        memset(mRadiotext, 0, sizeof(mRadiotext));
+        NS_DispatchToMainThread(new NotifyRunnable(RadiotextChanged));
+      }
+
+      if (!segmentAddr) {
+        mRadiotextState = 1;
+      } else {
+        mRadiotextState |= 1 << segmentAddr;
+      }
+      uint8_t segment[2];
+      segment[0] = blocks[3] >> 8;
+      segment[1] = blocks[3] & 0xFF;
+
+      uint16_t offset = segmentAddr << 1;
+      bool done = false;
+      for (int i = 0; i < 2; i++) {
+        if (segment[i] == '\r') {
+          mTempRadiotext[offset++] = 0;
+          done = true;
+        } else {
+          mTempRadiotext[offset++] = sRDSToUnicodeMap[segment[i]];
+        }
+      }
+      if (offset == 32) {
+        done = true;
+      }
+
+      if (!done ||
+          (mRadiotextState + 1) != (1 << ((blocks[1] & 0xF) + 1)) ||
+          !memcmp(mTempRadiotext, mRadiotext, sizeof(mTempRadiotext))) {
+        break;
+      }
+
+      MutexAutoLock lock(mRDSLock);
+      mRadiotextSet = true;
+      memcpy(mRadiotext, mTempRadiotext, sizeof(mTempRadiotext));
+      NS_DispatchToMainThread(new NotifyRunnable(RadiotextChanged));
+      break;
+    }
+    case 31: // 15b Fast Tuning and Switching
+    {
+      uint16_t secondPty = (blocks[3] >> 5) & 0x1F;
+      if (pty == mPTY || pty != secondPty) {
+        break;
+      }
+      mPTY = pty;
+      NS_DispatchToMainThread(new NotifyRunnable(PTYChanged));
+      break;
+    }
+  }
+
+  // Only notify users of raw RDS groups that they're interested in.
+  // We always receive DOM_PARSED_RDS_GROUPS when RDS is enabled.
+  if (!(mRDSGroupMask & (1 << grouptype))) {
+    return;
+  }
+
+  uint64_t newgroup = blocks[0];
+  newgroup <<= 16;
+  newgroup |= blocks[1];
+  newgroup <<= 16;
+  newgroup |= blocks[2];
+  newgroup <<= 16;
+  newgroup |= blocks[3];
+
+  MutexAutoLock lock(mRDSLock);
+  mRDSGroup = newgroup;
+  mRDSGroupSet = true;
+  NS_DispatchToMainThread(new NotifyRunnable(NewRDSGroup));
+}
+
 void
 FMRadioService::UpdatePowerState()
 {
   bool enabled = IsFMRadioOn();
   if (enabled != mEnabled) {
     mEnabled = enabled;
     NotifyFMRadioEvent(EnabledChanged);
   }
@@ -797,16 +1205,23 @@ FMRadioService::UpdatePowerState()
 
 void
 FMRadioService::UpdateFrequency()
 {
   int32_t frequency = GetFMRadioFrequency();
   if (mPendingFrequencyInKHz != frequency) {
     mPendingFrequencyInKHz = frequency;
     NotifyFMRadioEvent(FrequencyChanged);
+    mPISet = false;
+    mPTYSet = false;
+    memset(mPSName, 0, sizeof(mPSName));
+    memset(mRadiotext, 0, sizeof(mRadiotext));
+    mRDSGroupSet = false;
+    mPSNameSet = false;
+    mRadiotextSet = false;
   }
 }
 
 // static
 FMRadioService*
 FMRadioService::Singleton()
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
--- a/dom/fmradio/FMRadioService.h
+++ b/dom/fmradio/FMRadioService.h
@@ -2,19 +2,21 @@
 /* vim: set ts=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/. */
 
 #ifndef mozilla_dom_fmradioservice_h__
 #define mozilla_dom_fmradioservice_h__
 
+#include "mozilla/dom/Nullable.h"
 #include "mozilla/dom/PFMRadioRequest.h"
 #include "FMRadioCommon.h"
 #include "mozilla/Hal.h"
+#include "mozilla/Mutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Services.h"
 #include "nsThreadUtils.h"
 #include "nsIObserver.h"
 #include "nsXULAppAPI.h"
 
 BEGIN_FMRADIO_NAMESPACE
 
@@ -90,27 +92,36 @@ protected:
  */
 class IFMRadioService
 {
 protected:
   virtual ~IFMRadioService() { }
 
 public:
   virtual bool IsEnabled() const = 0;
+  virtual bool IsRDSEnabled() const = 0;
   virtual double GetFrequency() const = 0;
   virtual double GetFrequencyUpperBound() const = 0;
   virtual double GetFrequencyLowerBound() const = 0;
   virtual double GetChannelWidth() const = 0;
+  virtual Nullable<unsigned short> GetPi() const = 0;
+  virtual Nullable<uint8_t> GetPty() const = 0;
+  virtual bool GetPs(nsString& aPsname) = 0;
+  virtual bool GetRt(nsString& aRadiotext) = 0;
+  virtual bool GetRdsgroup(uint64_t& aRDSGroup) = 0;
 
   virtual void Enable(double aFrequency, FMRadioReplyRunnable* aReplyRunnable) = 0;
   virtual void Disable(FMRadioReplyRunnable* aReplyRunnable) = 0;
   virtual void SetFrequency(double aFrequency, FMRadioReplyRunnable* aReplyRunnable) = 0;
   virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection,
                     FMRadioReplyRunnable* aReplyRunnable) = 0;
   virtual void CancelSeek(FMRadioReplyRunnable* aReplyRunnable) = 0;
+  virtual void SetRDSGroupMask(uint32_t aRDSGroupMask) = 0;
+  virtual void EnableRDS(FMRadioReplyRunnable* aReplyRunnable) = 0;
+  virtual void DisableRDS(FMRadioReplyRunnable* aReplyRunnable) = 0;
 
   /**
    * Register handler to receive the FM Radio events, including:
    *   - StateChangedEvent
    *   - FrequencyChangedEvent
    *
    * Called by FMRadio and FMRadioParent.
    */
@@ -133,50 +144,63 @@ enum FMRadioState
   Disabling,
   Enabling,
   Enabled,
   Seeking
 };
 
 class FMRadioService MOZ_FINAL : public IFMRadioService
                                , public hal::FMRadioObserver
+                               , public hal::FMRadioRDSObserver
                                , public nsIObserver
 {
   friend class ReadAirplaneModeSettingTask;
   friend class EnableRunnable;
   friend class DisableRunnable;
+  friend class NotifyRunnable;
 
 public:
   static FMRadioService* Singleton();
   virtual ~FMRadioService();
 
   NS_DECL_ISUPPORTS
 
   virtual bool IsEnabled() const MOZ_OVERRIDE;
+  virtual bool IsRDSEnabled() const MOZ_OVERRIDE;
   virtual double GetFrequency() const MOZ_OVERRIDE;
   virtual double GetFrequencyUpperBound() const MOZ_OVERRIDE;
   virtual double GetFrequencyLowerBound() const MOZ_OVERRIDE;
   virtual double GetChannelWidth() const MOZ_OVERRIDE;
+  virtual Nullable<unsigned short> GetPi() const MOZ_OVERRIDE;
+  virtual Nullable<uint8_t> GetPty() const MOZ_OVERRIDE;
+  virtual bool GetPs(nsString& aPsname) MOZ_OVERRIDE;
+  virtual bool GetRt(nsString& aRadiotext) MOZ_OVERRIDE;
+  virtual bool GetRdsgroup(uint64_t& aRDSGroup) MOZ_OVERRIDE;
 
   virtual void Enable(double aFrequency,
                       FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
   virtual void Disable(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
   virtual void SetFrequency(double aFrequency,
                             FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
   virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection,
                     FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
   virtual void CancelSeek(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
+  virtual void SetRDSGroupMask(uint32_t aRDSGroupMask) MOZ_OVERRIDE;
+  virtual void EnableRDS(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
+  virtual void DisableRDS(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
 
   virtual void AddObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE;
   virtual void RemoveObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE;
 
   virtual void EnableAudio(bool aAudioEnabled) MOZ_OVERRIDE;
 
   /* FMRadioObserver */
   void Notify(const hal::FMRadioOperationInformation& aInfo) MOZ_OVERRIDE;
+  /* FMRadioRDSObserver */
+  void Notify(const hal::FMRadioRDSGroup& aRDSGroup) MOZ_OVERRIDE;
 
   NS_DECL_NSIOBSERVER
 
 protected:
   FMRadioService();
 
 private:
   int32_t RoundFrequency(double aFrequencyInMHz);
@@ -192,26 +216,51 @@ private:
   bool mEnabled;
 
   int32_t mPendingFrequencyInKHz;
 
   FMRadioState mState;
 
   bool mHasReadAirplaneModeSetting;
   bool mAirplaneModeEnabled;
+  bool mRDSEnabled;
 
   uint32_t mUpperBoundInKHz;
   uint32_t mLowerBoundInKHz;
   uint32_t mChannelWidthInKHz;
   uint32_t mPreemphasis;
 
   nsCOMPtr<nsIThread> mTuneThread;
   nsRefPtr<FMRadioReplyRunnable> mPendingRequest;
 
   FMRadioEventObserverList mObserverList;
 
   static StaticRefPtr<FMRadioService> sFMRadioService;
+
+  uint32_t mRDSGroupMask;
+
+  uint16_t mLastPI;
+  uint16_t mLastPTY;
+  Atomic<uint32_t> mPI;
+  Atomic<uint32_t> mPTY;
+  Atomic<bool> mPISet;
+  Atomic<bool> mPTYSet;
+
+  /* Protects mPSName, mRadiotext, and mRDSGroup */
+  Mutex mRDSLock;
+  char16_t mPSName[9];
+  char16_t mRadiotext[65];
+  uint64_t mRDSGroup;
+
+  uint8_t mPSNameState;
+  uint16_t mRadiotextState;
+  uint16_t mTempPSName[8];
+  uint16_t mTempRadiotext[64];
+  bool mRadiotextAB;
+  bool mRDSGroupSet;
+  bool mPSNameSet;
+  bool mRadiotextSet;
 };
 
 END_FMRADIO_NAMESPACE
 
 #endif // mozilla_dom_fmradioservice_h__
 
--- a/dom/fmradio/ipc/FMRadioChild.cpp
+++ b/dom/fmradio/ipc/FMRadioChild.cpp
@@ -11,17 +11,23 @@
 using namespace mozilla::hal;
 
 BEGIN_FMRADIO_NAMESPACE
 
 StaticAutoPtr<FMRadioChild> FMRadioChild::sFMRadioChild;
 
 FMRadioChild::FMRadioChild()
   : mEnabled(false)
+  , mRDSEnabled(false)
+  , mRDSGroupSet(false)
+  , mPSNameSet(false)
+  , mRadiotextSet(false)
   , mFrequency(0)
+  , mRDSGroup(0)
+  , mRDSGroupMask(0)
   , mObserverList(FMRadioEventObserverList())
 {
   MOZ_COUNT_CTOR(FMRadioChild);
 
   ContentChild::GetSingleton()->SendPFMRadioConstructor(this);
 
   StatusInfo statusInfo;
   SendGetStatusInfo(&statusInfo);
@@ -39,16 +45,22 @@ FMRadioChild::~FMRadioChild()
 }
 
 bool
 FMRadioChild::IsEnabled() const
 {
   return mEnabled;
 }
 
+bool
+FMRadioChild::IsRDSEnabled() const
+{
+  return mRDSEnabled;
+}
+
 double
 FMRadioChild::GetFrequency() const
 {
   return mFrequency;
 }
 
 
 double
@@ -64,16 +76,53 @@ FMRadioChild::GetFrequencyLowerBound() c
 }
 
 double
 FMRadioChild::GetChannelWidth() const
 {
   return mChannelWidth;
 }
 
+Nullable<unsigned short>
+FMRadioChild::GetPi() const
+{
+  return mPI;
+}
+
+Nullable<uint8_t>
+FMRadioChild::GetPty() const
+{
+  return mPTY;
+}
+
+bool
+FMRadioChild::GetPs(nsString& aPSName)
+{
+  if (mPSNameSet) {
+    aPSName = mPSName;
+  }
+  return mPSNameSet;
+}
+
+bool
+FMRadioChild::GetRt(nsString& aRadiotext)
+{
+  if (mRadiotextSet) {
+    aRadiotext = mRadiotext;
+  }
+  return mRadiotextSet;
+}
+
+bool
+FMRadioChild::GetRdsgroup(uint64_t& aRDSGroup)
+{
+  aRDSGroup = mRDSGroup;
+  return mRDSGroupSet;
+}
+
 void
 FMRadioChild::Enable(double aFrequency, FMRadioReplyRunnable* aReplyRunnable)
 {
   SendRequest(aReplyRunnable, EnableRequestArgs(aFrequency));
 }
 
 void
 FMRadioChild::Disable(FMRadioReplyRunnable* aReplyRunnable)
@@ -96,16 +145,35 @@ FMRadioChild::Seek(FMRadioSeekDirection 
 }
 
 void
 FMRadioChild::CancelSeek(FMRadioReplyRunnable* aReplyRunnable)
 {
   SendRequest(aReplyRunnable, CancelSeekRequestArgs());
 }
 
+void
+FMRadioChild::SetRDSGroupMask(uint32_t aRDSGroupMask)
+{
+  mRDSGroupMask = aRDSGroupMask;
+  SendSetRDSGroupMask(aRDSGroupMask);
+}
+
+void
+FMRadioChild::EnableRDS(FMRadioReplyRunnable* aReplyRunnable)
+{
+  SendRequest(aReplyRunnable, EnableRDSArgs());
+}
+
+void
+FMRadioChild::DisableRDS(FMRadioReplyRunnable* aReplyRunnable)
+{
+  SendRequest(aReplyRunnable, DisableRDSArgs());
+}
+
 inline void
 FMRadioChild::NotifyFMRadioEvent(FMRadioEventType aType)
 {
   mObserverList.Broadcast(aType);
 }
 
 void
 FMRadioChild::AddObserver(FMRadioEventObserver* aObserver)
@@ -127,30 +195,125 @@ FMRadioChild::SendRequest(FMRadioReplyRu
   SendPFMRadioRequestConstructor(childRequest, aArgs);
 }
 
 bool
 FMRadioChild::RecvNotifyFrequencyChanged(const double& aFrequency)
 {
   mFrequency = aFrequency;
   NotifyFMRadioEvent(FrequencyChanged);
+
+  if (!mPI.IsNull()) {
+    mPI.SetNull();
+    NotifyFMRadioEvent(PIChanged);
+  }
+  if (!mPTY.IsNull()) {
+    mPTY.SetNull();
+    NotifyFMRadioEvent(PTYChanged);
+  }
+  if (mPSNameSet) {
+    mPSNameSet = false;
+    mPSName.Truncate();
+    NotifyFMRadioEvent(PSChanged);
+  }
+  if (mRadiotextSet) {
+    mRadiotextSet = false;
+    mRadiotext.Truncate();
+    NotifyFMRadioEvent(RadiotextChanged);
+  }
+  mRDSGroupSet = false;
   return true;
 }
 
 bool
 FMRadioChild::RecvNotifyEnabledChanged(const bool& aEnabled,
                                        const double& aFrequency)
 {
   mEnabled = aEnabled;
   mFrequency = aFrequency;
+  if (!mEnabled) {
+    mPI.SetNull();
+    mPTY.SetNull();
+    mPSName.Truncate();
+    mRadiotext.Truncate();
+    mRDSGroupSet = false;
+    mPSNameSet = false;
+    mRadiotextSet = false;
+  }
   NotifyFMRadioEvent(EnabledChanged);
   return true;
 }
 
 bool
+FMRadioChild::RecvNotifyRDSEnabledChanged(const bool& aEnabled)
+{
+  mRDSEnabled = aEnabled;
+  NotifyFMRadioEvent(RDSEnabledChanged);
+  return true;
+}
+
+bool
+FMRadioChild::RecvNotifyPIChanged(const bool& aValid,
+                                  const uint16_t& aCode)
+{
+  if (aValid) {
+    mPI.SetValue(aCode);
+  } else {
+    mPI.SetNull();
+  }
+  NotifyFMRadioEvent(PIChanged);
+  return true;
+}
+
+bool
+FMRadioChild::RecvNotifyPTYChanged(const bool& aValid,
+                                   const uint8_t& aPTY)
+{
+  if (aValid) {
+    mPTY.SetValue(aPTY);
+  } else {
+    mPTY.SetNull();
+  }
+  NotifyFMRadioEvent(PTYChanged);
+  return true;
+}
+
+bool
+FMRadioChild::RecvNotifyPSChanged(const nsString& aPSName)
+{
+  mPSNameSet = true;
+  mPSName = aPSName;
+  NotifyFMRadioEvent(PSChanged);
+  return true;
+}
+
+bool
+FMRadioChild::RecvNotifyRadiotextChanged(const nsString& aRadiotext)
+{
+  mRadiotextSet = true;
+  mRadiotext = aRadiotext;
+  NotifyFMRadioEvent(RadiotextChanged);
+  return true;
+}
+
+bool
+FMRadioChild::RecvNotifyNewRDSGroup(const uint64_t& aGroup)
+{
+  uint16_t grouptype = (aGroup >> 43) & 0x1F;
+  if (!(mRDSGroupMask & (1 << grouptype))) {
+    return true;
+  }
+
+  mRDSGroupSet = true;
+  mRDSGroup = aGroup;
+  NotifyFMRadioEvent(NewRDSGroup);
+  return true;
+}
+
+bool
 FMRadioChild::Recv__delete__()
 {
   return true;
 }
 
 PFMRadioRequestChild*
 FMRadioChild::AllocPFMRadioRequestChild(const FMRadioRequestArgs& aArgs)
 {
--- a/dom/fmradio/ipc/FMRadioChild.h
+++ b/dom/fmradio/ipc/FMRadioChild.h
@@ -29,29 +29,38 @@ public:
   static FMRadioChild* Singleton();
   ~FMRadioChild();
 
   void SendRequest(FMRadioReplyRunnable* aReplyRunnable,
                    FMRadioRequestArgs aArgs);
 
   /* IFMRadioService */
   virtual bool IsEnabled() const MOZ_OVERRIDE;
+  virtual bool IsRDSEnabled() const MOZ_OVERRIDE;
   virtual double GetFrequency() const MOZ_OVERRIDE;
   virtual double GetFrequencyUpperBound() const MOZ_OVERRIDE;
   virtual double GetFrequencyLowerBound() const MOZ_OVERRIDE;
   virtual double GetChannelWidth() const MOZ_OVERRIDE;
+  virtual Nullable<unsigned short> GetPi() const MOZ_OVERRIDE;
+  virtual Nullable<uint8_t> GetPty() const MOZ_OVERRIDE;
+  virtual bool GetPs(nsString& aPSName) MOZ_OVERRIDE;
+  virtual bool GetRt(nsString& aRadiotext) MOZ_OVERRIDE;
+  virtual bool GetRdsgroup(uint64_t& aRDSGroup) MOZ_OVERRIDE;
 
   virtual void Enable(double aFrequency,
                       FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
   virtual void Disable(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
   virtual void SetFrequency(double frequency,
                             FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
   virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection,
                     FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
   virtual void CancelSeek(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
+  virtual void SetRDSGroupMask(uint32_t aRDSGroupMask) MOZ_OVERRIDE;
+  virtual void EnableRDS(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
+  virtual void DisableRDS(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
 
   virtual void AddObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE;
   virtual void RemoveObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE;
 
   virtual void EnableAudio(bool aAudioEnabled) MOZ_OVERRIDE;
 
   /* PFMRadioChild */
   virtual bool
@@ -59,34 +68,64 @@ public:
 
   virtual bool
   RecvNotifyFrequencyChanged(const double& aFrequency) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyEnabledChanged(const bool& aEnabled,
                            const double& aFrequency) MOZ_OVERRIDE;
 
+  virtual bool
+  RecvNotifyRDSEnabledChanged(const bool& aEnabled) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvNotifyPIChanged(const bool& aValid,
+                      const uint16_t& aCode) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvNotifyPTYChanged(const bool& aValid,
+                       const uint8_t& aPTY) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvNotifyPSChanged(const nsString& aPSName) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvNotifyRadiotextChanged(const nsString& aRadiotext) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvNotifyNewRDSGroup(const uint64_t& aGroup) MOZ_OVERRIDE;
+
   virtual PFMRadioRequestChild*
   AllocPFMRadioRequestChild(const FMRadioRequestArgs& aArgs) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPFMRadioRequestChild(PFMRadioRequestChild* aActor) MOZ_OVERRIDE;
 
 private:
   FMRadioChild();
 
   void Init();
 
   inline void NotifyFMRadioEvent(FMRadioEventType aType);
 
   bool mEnabled;
+  bool mRDSEnabled;
+  bool mRDSGroupSet;
+  bool mPSNameSet;
+  bool mRadiotextSet;
   double mFrequency;
   double mUpperBound;
   double mLowerBound;
   double mChannelWidth;
+  Nullable<unsigned short> mPI;
+  Nullable<uint8_t> mPTY;
+  nsAutoString mPSName;
+  nsAutoString mRadiotext;
+  uint64_t mRDSGroup;
+  uint32_t mRDSGroupMask;
 
   FMRadioEventObserverList mObserverList;
 
 private:
   static StaticAutoPtr<FMRadioChild> sFMRadioChild;
 };
 
 END_FMRADIO_NAMESPACE
--- a/dom/fmradio/ipc/FMRadioParent.cpp
+++ b/dom/fmradio/ipc/FMRadioParent.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FMRadioParent.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/DebugOnly.h"
 #include "FMRadioRequestParent.h"
 #include "FMRadioService.h"
 
 BEGIN_FMRADIO_NAMESPACE
 
 FMRadioParent::FMRadioParent()
 {
   MOZ_COUNT_CTOR(FMRadioParent);
@@ -64,16 +65,22 @@ FMRadioParent::AllocPFMRadioRequestParen
       break;
     case FMRadioRequestArgs::TSeekRequestArgs:
       IFMRadioService::Singleton()->Seek(
         aArgs.get_SeekRequestArgs().direction(), requestParent);
       break;
     case FMRadioRequestArgs::TCancelSeekRequestArgs:
       IFMRadioService::Singleton()->CancelSeek(requestParent);
       break;
+    case FMRadioRequestArgs::TEnableRDSArgs:
+      IFMRadioService::Singleton()->EnableRDS(requestParent);
+      break;
+    case FMRadioRequestArgs::TDisableRDSArgs:
+      IFMRadioService::Singleton()->DisableRDS(requestParent);
+      break;
     default:
       MOZ_CRASH();
   }
 
   // Balanced in DeallocPFMRadioRequestParent
   return requestParent.forget().take();
 }
 
@@ -93,23 +100,67 @@ FMRadioParent::Notify(const FMRadioEvent
       unused << SendNotifyFrequencyChanged(
         IFMRadioService::Singleton()->GetFrequency());
       break;
     case EnabledChanged:
       unused << SendNotifyEnabledChanged(
         IFMRadioService::Singleton()->IsEnabled(),
         IFMRadioService::Singleton()->GetFrequency());
       break;
+    case RDSEnabledChanged:
+      unused << SendNotifyRDSEnabledChanged(
+        IFMRadioService::Singleton()->IsRDSEnabled());
+      break;
+    case PIChanged: {
+      Nullable<unsigned short> pi =
+        IFMRadioService::Singleton()->GetPi();
+      unused << SendNotifyPIChanged(!pi.IsNull(),
+                                    pi.IsNull() ? 0 : pi.Value());
+      break;
+    }
+    case PTYChanged: {
+      Nullable<uint8_t> pty = IFMRadioService::Singleton()->GetPty();
+      unused << SendNotifyPTYChanged(!pty.IsNull(),
+                                     pty.IsNull() ? 0 : pty.Value());
+      break;
+    }
+    case PSChanged: {
+      nsAutoString psname;
+      IFMRadioService::Singleton()->GetPs(psname);
+      unused << SendNotifyPSChanged(psname);
+      break;
+    }
+    case RadiotextChanged: {
+      nsAutoString radiotext;
+      IFMRadioService::Singleton()->GetRt(radiotext);
+      unused << SendNotifyRadiotextChanged(radiotext);
+      break;
+    }
+    case NewRDSGroup: {
+      uint64_t group;
+      DebugOnly<bool> rdsgroupset =
+        IFMRadioService::Singleton()->GetRdsgroup(group);
+      MOZ_ASSERT(rdsgroupset);
+      unused << SendNotifyNewRDSGroup(group);
+      break;
+    }
     default:
       NS_RUNTIMEABORT("not reached");
       break;
   }
 }
 
 bool
 FMRadioParent::RecvEnableAudio(const bool& aAudioEnabled)
 {
   IFMRadioService::Singleton()->EnableAudio(aAudioEnabled);
   return true;
 }
 
+bool
+FMRadioParent::RecvSetRDSGroupMask(const uint32_t& aRDSGroupMask)
+{
+  IFMRadioService::Singleton()->SetRDSGroupMask(aRDSGroupMask);
+  return true;
+}
+
 END_FMRADIO_NAMESPACE
 
--- a/dom/fmradio/ipc/FMRadioParent.h
+++ b/dom/fmradio/ipc/FMRadioParent.h
@@ -34,14 +34,17 @@ public:
   virtual bool
   DeallocPFMRadioRequestParent(PFMRadioRequestParent* aActor) MOZ_OVERRIDE;
 
   /* FMRadioEventObserver */
   virtual void Notify(const FMRadioEventType& aType) MOZ_OVERRIDE;
 
   virtual bool
   RecvEnableAudio(const bool& aAudioEnabled) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvSetRDSGroupMask(const uint32_t& aRDSGroupMask) MOZ_OVERRIDE;
 };
 
 END_FMRADIO_NAMESPACE
 
 #endif // mozilla_dom_fmradioparent_h__
 
--- a/dom/fmradio/ipc/PFMRadio.ipdl
+++ b/dom/fmradio/ipc/PFMRadio.ipdl
@@ -29,23 +29,33 @@ struct SeekRequestArgs
 {
   FMRadioSeekDirection direction;
 };
 
 struct CancelSeekRequestArgs
 {
 };
 
+struct EnableRDSArgs
+{
+};
+
+struct DisableRDSArgs
+{
+};
+
 union FMRadioRequestArgs
 {
   EnableRequestArgs;
   DisableRequestArgs;
   SetFrequencyRequestArgs;
   SeekRequestArgs;
   CancelSeekRequestArgs;
+  EnableRDSArgs;
+  DisableRDSArgs;
 };
 
 struct StatusInfo
 {
   bool enabled;
   double frequency;
   double upperBound;
   double lowerBound;
@@ -61,16 +71,40 @@ child:
   /**
    * Sent when the frequency is changed.
    */
   NotifyFrequencyChanged(double frequency);
   /**
    * Sent when the power state of FM radio HW is changed.
    */
   NotifyEnabledChanged(bool enabled, double frequency);
+  /**
+   * Sent when RDS is enabled or disabled.
+   */
+  NotifyRDSEnabledChanged(bool enabled);
+  /**
+   * Sent when we have a new PI code.
+   */
+  NotifyPIChanged(bool valid, uint16_t code);
+  /**
+   * Sent when we have a new PTY
+   */
+  NotifyPTYChanged(bool valid, uint8_t pty);
+  /**
+   * Sent when we have a new PS name.
+   */
+  NotifyPSChanged(nsString psname);
+  /**
+   * Sent when we have new radiotext.
+   */
+  NotifyRadiotextChanged(nsString radiotext);
+  /**
+   * Sent when a full RDS group is received.
+   */
+  NotifyNewRDSGroup(uint64_t data);
 
   __delete__();
 
 parent:
   /**
    * Get the current status infomation of FM radio HW synchronously.
    * Sent when the singleton object of FMRadioChild is initialized.
    */
@@ -86,13 +120,18 @@ parent:
    * is more error prone.
    */
   PFMRadioRequest(FMRadioRequestArgs requestType);
 
   /**
    * Enable/Disable audio
    */
   EnableAudio(bool audioEnabled);
+
+  /**
+   * Set RDS group mask
+   */
+  SetRDSGroupMask(uint32_t groupMask);
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -14,17 +14,16 @@
 
 #include "ContentChild.h"
 
 #include "BlobChild.h"
 #include "CrashReporterChild.h"
 #include "TabChild.h"
 
 #include "mozilla/Attributes.h"
-#include "mozilla/a11y/DocAccessibleChild.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/ContentBridgeChild.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
@@ -703,30 +702,16 @@ ContentChild::InitXPCOM()
     // This object is held alive by the observer service.
     nsRefPtr<SystemMessageHandledObserver> sysMsgObserver =
         new SystemMessageHandledObserver();
     sysMsgObserver->Init();
 
     InitOnContentProcessCreated();
 }
 
-a11y::PDocAccessibleChild*
-ContentChild::AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&)
-{
-  MOZ_ASSERT(false, "should never call this!");
-  return nullptr;
-}
-
-bool
-ContentChild::DeallocPDocAccessibleChild(a11y::PDocAccessibleChild* aChild)
-{
-  delete static_cast<mozilla::a11y::DocAccessibleChild*>(aChild);
-  return true;
-}
-
 PMemoryReportRequestChild*
 ContentChild::AllocPMemoryReportRequestChild(const uint32_t& aGeneration,
                                              const bool &aAnonymize,
                                              const bool &aMinimizeMemoryUsage,
                                              const MaybeFileDesc& aDMDFile)
 {
     MemoryReportRequestChild *actor =
         new MemoryReportRequestChild(aGeneration, aAnonymize, aDMDFile);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -375,18 +375,16 @@ public:
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
 
     virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
                                          const IPCTabContext& aContext,
                                          const uint32_t& aChromeFlags,
                                          const uint64_t& aID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
-    virtual PDocAccessibleChild* AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&) MOZ_OVERRIDE;
-    virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) MOZ_OVERRIDE;
 
 private:
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
     virtual void ProcessingError(Result what) MOZ_OVERRIDE;
 
     /**
      * Exit *now*.  Do not shut down XPCOM, do not pass Go, do not run
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -25,18 +25,16 @@
 #include <set>
 
 #include "AppProcessChecker.h"
 #include "AudioChannelService.h"
 #include "BlobParent.h"
 #include "CrashReporterParent.h"
 #include "IHistory.h"
 #include "mozIApplication.h"
-#include "mozilla/a11y/DocAccessibleParent.h"
-#include "nsAccessibilityService.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/DataStoreService.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
 #include "mozilla/dom/FileSystemRequestParent.h"
 #include "mozilla/dom/GeolocationBinding.h"
 #include "mozilla/dom/PContentBridgeParent.h"
@@ -339,16 +337,17 @@ struct nsIConsoleService::COMTypeInfo<ns
   static const nsIID kIID;
 };
 const nsIID nsIConsoleService::COMTypeInfo<nsConsoleService, void>::kIID = NS_ICONSOLESERVICE_IID;
 
 namespace mozilla {
 namespace dom {
 
 #ifdef MOZ_NUWA_PROCESS
+int32_t ContentParent::sNuwaPid = 0;
 bool ContentParent::sNuwaReady = false;
 #endif
 
 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
 
 class MemoryReportRequestParent : public PMemoryReportRequestParent
 {
 public:
@@ -584,16 +583,17 @@ ContentParent::RunNuwaProcess()
         new ContentParent(/* aApp = */ nullptr,
                           /* aOpener = */ nullptr,
                           /* aIsForBrowser = */ false,
                           /* aIsForPreallocated = */ true,
                           PROCESS_PRIORITY_BACKGROUND,
                           /* aIsNuwaProcess = */ true);
     nuwaProcess->Init();
 #ifdef MOZ_NUWA_PROCESS
+    sNuwaPid = nuwaProcess->Pid();
     sNuwaReady = false;
 #endif
     return nuwaProcess.forget();
 }
 
 // PreallocateAppProcess is called by the PreallocatedProcessManager.
 // ContentParent then takes this process back within
 // GetNewOrPreallocatedAppProcess.
@@ -1987,16 +1987,17 @@ ContentParent::~ContentParent()
         // that sAppContentParents->Get(mAppManifestURL) != this.
         MOZ_ASSERT(!sAppContentParents ||
                    sAppContentParents->Get(mAppManifestURL) != this);
     }
 
 #ifdef MOZ_NUWA_PROCESS
     if (IsNuwaProcess()) {
         sNuwaReady = false;
+        sNuwaPid = 0;
     }
 #endif
 }
 
 void
 ContentParent::InitInternal(ProcessPriority aInitialPriority,
                             bool aSetupOffMainThreadCompositing,
                             bool aSendRegisteredChrome)
@@ -2694,44 +2695,16 @@ ContentParent::Observe(nsISupports* aSub
     }
 #endif
     else if (!strcmp(aTopic, "app-theme-changed")) {
         unused << SendOnAppThemeChanged();
     }
     return NS_OK;
 }
 
-  a11y::PDocAccessibleParent*
-ContentParent::AllocPDocAccessibleParent(PDocAccessibleParent* aParent, const uint64_t&)
-{
-  return new a11y::DocAccessibleParent();
-}
-
-bool
-ContentParent::DeallocPDocAccessibleParent(PDocAccessibleParent* aParent)
-{
-  delete static_cast<a11y::DocAccessibleParent*>(aParent);
-  return true;
-}
-
-bool
-ContentParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc, PDocAccessibleParent* aParentDoc, const uint64_t& aParentID)
-{
-  auto doc = static_cast<a11y::DocAccessibleParent*>(aDoc);
-  if (aParentDoc) {
-    MOZ_ASSERT(aParentID);
-    auto parentDoc = static_cast<a11y::DocAccessibleParent*>(aParentDoc);
-    return parentDoc->AddChildDoc(doc, aParentID);
-  } else {
-    MOZ_ASSERT(!aParentID);
-    GetAccService()->RemoteDocAdded(doc);
-  }
-  return true;
-}
-
 PCompositorParent*
 ContentParent::AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
                                       base::ProcessId aOtherProcess)
 {
     return CompositorParent::Create(aTransport, aOtherProcess);
 }
 
 PImageBridgeParent*
@@ -3724,16 +3697,22 @@ ContentParent::DoSendAsyncMessage(JSCont
     ClonedMessageData data;
     if (!BuildClonedMessageDataForParent(this, aData, data)) {
         return false;
     }
     InfallibleTArray<CpowEntry> cpows;
     if (aCpows && !GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
         return false;
     }
+#ifdef MOZ_NUWA_PROCESS
+    if (IsNuwaProcess() && IsNuwaReady()) {
+        // Nuwa won't receive frame messages after it is frozen.
+        return true;
+    }
+#endif
     return SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal));
 }
 
 bool
 ContentParent::CheckPermission(const nsAString& aPermission)
 {
     return AssertAppProcessPermission(this, NS_ConvertUTF16toUTF8(aPermission).get());
 }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -74,16 +74,20 @@ class ContentParent MOZ_FINAL : public P
     typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
     typedef mozilla::ipc::PFileDescriptorSetParent PFileDescriptorSetParent;
     typedef mozilla::ipc::TestShellParent TestShellParent;
     typedef mozilla::ipc::URIParams URIParams;
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
 
 public:
 #ifdef MOZ_NUWA_PROCESS
+    static int32_t NuwaPid() {
+        return sNuwaPid;
+    }
+
     static bool IsNuwaReady() {
         return sNuwaReady;
     }
 #endif
     virtual bool IsContentParent() MOZ_OVERRIDE { return true; }
     /**
      * Start up the content-process machinery.  This might include
      * scheduling pre-launch tasks.
@@ -661,21 +665,16 @@ private:
                           const nsCString& aOrigin,
                           const nsString& aDatabaseName,
                           const int64_t& aFileId,
                           int32_t* aRefCnt,
                           int32_t* aDBRefCnt,
                           int32_t* aSliceRefCnt,
                           bool* aResult) MOZ_OVERRIDE;
 
-    virtual PDocAccessibleParent* AllocPDocAccessibleParent(PDocAccessibleParent*, const uint64_t&) MOZ_OVERRIDE;
-    virtual bool DeallocPDocAccessibleParent(PDocAccessibleParent*) MOZ_OVERRIDE;
-    virtual bool RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
-                                               PDocAccessibleParent* aParentDoc, const uint64_t& aParentID) MOZ_OVERRIDE;
-
     // If you add strong pointers to cycle collected objects here, be sure to
     // release these objects in ShutDownProcess.  See the comment there for more
     // details.
 
     GeckoChildProcessHost* mSubprocess;
     ContentParent* mOpener;
 
     uint64_t mChildID;
@@ -725,16 +724,17 @@ private:
 
 #ifdef MOZ_X11
     // Dup of child's X socket, used to scope its resources to this
     // object instead of the child process's lifetime.
     ScopedClose mChildXSocketFdDup;
 #endif
 
 #ifdef MOZ_NUWA_PROCESS
+    static int32_t sNuwaPid;
     static bool sNuwaReady;
 #endif
 };
 
 } // namespace dom
 } // namespace mozilla
 
 class ParentIdleListener : public nsIObserver {
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -9,17 +9,16 @@ include protocol PBackground;
 include protocol PBlob;
 include protocol PBluetooth;
 include protocol PBrowser;
 include protocol PCellBroadcast;
 include protocol PCompositor;
 include protocol PContentBridge;
 include protocol PCycleCollectWithLogs;
 include protocol PCrashReporter;
-include protocol PDocAccessible;
 include protocol PExternalHelperApp;
 include protocol PDeviceStorageRequest;
 include protocol PFileDescriptorSet;
 include protocol PFMRadio;
 include protocol PFileSystemRequest;
 include protocol PHal;
 include protocol PImageBridge;
 include protocol PMemoryReportRequest;
@@ -328,17 +327,16 @@ intr protocol PContent
 
     manages PAsmJSCacheEntry;
     manages PBlob;
     manages PBluetooth;
     manages PBrowser;
     manages PCellBroadcast;
     manages PCrashReporter;
     manages PCycleCollectWithLogs;
-    manages PDocAccessible;
     manages PDeviceStorageRequest;
     manages PFileSystemRequest;
     manages PExternalHelperApp;
     manages PFileDescriptorSet;
     manages PFMRadio;
     manages PHal;
     manages PMemoryReportRequest;
     manages PMobileConnection;
@@ -486,24 +484,16 @@ child:
 
     /**
      * Notify windows in the child to apply a new app style.
      */
     OnAppThemeChanged();
 
 parent:
     /**
-     * Tell the parent process a new accessible document has been created.
-     * aParentDoc is the accessible document it was created in if any, and
-     * aParentAcc is the id of the accessible in that document the new document
-     * is a child of.
-     */
-    PDocAccessible(nullable PDocAccessible aParentDoc, uint64_t aParentAcc);
-
-    /**
      * Tell the content process some attributes of itself.  This is
      * among the first information queried by content processes after
      * startup.  (The message is sync to allow the content process to
      * control when it receives the information.)
      *
      * |id| is a unique ID among all subprocesses.  When |isForApp &&
      * isForBrowser|, we're loading <browser> for an app.  When
      * |isForBrowser|, we're loading <browser>.  When |!isForApp &&
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -296,17 +296,16 @@ function RTCPeerConnection() {
   this._onGetStatsFailure = null;
   this._onReplaceTrackSender = null;
   this._onReplaceTrackWithTrack = null;
   this._onReplaceTrackSuccess = null;
   this._onReplaceTrackFailure = null;
 
   this._localType = null;
   this._remoteType = null;
-  this._trickleIce = false;
   this._peerIdentity = null;
 
   /**
    * Everytime we get a request from content, we put it in the queue. If there
    * are no pending operations though, we will execute it immediately. In
    * PeerConnectionObserver, whenever we are notified that an operation has
    * finished, we will check the queue for the next operation and execute if
    * neccesary. The _pending flag indicates whether an operation is currently in
@@ -321,17 +320,16 @@ RTCPeerConnection.prototype = {
   classDescription: "mozRTCPeerConnection",
   classID: PC_CID,
   contractID: PC_CONTRACT,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
   init: function(win) { this._win = win; },
 
   __init: function(rtcConfig) {
-    this._trickleIce = Services.prefs.getBoolPref("media.peerconnection.trickle_ice");
     if (!rtcConfig.iceServers ||
         !Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) {
       rtcConfig.iceServers =
         JSON.parse(Services.prefs.getCharPref("media.peerconnection.default_iceservers"));
     }
     this._mustValidateRTCConfiguration(rtcConfig,
         "RTCPeerConnection constructor passed invalid RTCConfiguration");
     if (_globalPCList._networkdown) {
@@ -360,18 +358,17 @@ RTCPeerConnection.prototype = {
     // Add a reference to the PeerConnection to global list (before init).
     this._winID = this._win.QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
     _globalPCList.addPC(this);
 
     this._queueOrRun({
       func: this._initialize,
       args: [rtcConfig],
-      // If not trickling, suppress start.
-      wait: !this._trickleIce
+      wait: false
     });
   },
 
   _initialize: function(rtcConfig) {
     this._impl.initialize(this._observer, this._win, rtcConfig,
                           Services.tm.currentThread);
     this._initIdp();
     _globalPCList.notifyLifecycleObservers(this, "initialized");
@@ -495,17 +492,21 @@ RTCPeerConnection.prototype = {
   // spec. See Bug 831756.
   _checkClosed: function() {
     if (this._closed) {
       throw new this._win.DOMError("", "Peer connection is closed");
     }
   },
 
   dispatchEvent: function(event) {
-    this.__DOM_IMPL__.dispatchEvent(event);
+    // PC can close while events are firing if there is an async dispatch
+    // in c++ land
+    if (!this._closed) {
+      this.__DOM_IMPL__.dispatchEvent(event);
+    }
   },
 
   // Log error message to web console and window.onerror, if present.
   logErrorAndCallOnError: function(msg, file, line) {
     this.logMsg(msg, file, line, Ci.nsIScriptError.exceptionFlag);
 
     // Safely call onerror directly if present (necessary for testing)
     try {
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -1932,16 +1932,20 @@ PeerConnectionWrapper.prototype = {
    *
    * @param {object} candidate
    *        The mozRTCIceCandidate to be added or stored
    */
   storeOrAddIceCandidate : function PCW_storeOrAddIceCandidate(candidate) {
     var self = this;
 
     self._remote_ice_candidates.push(candidate);
+    if (self.signalingstate === 'closed') {
+      info("Received ICE candidate for closed PeerConnection - discarding");
+      return;
+    }
     if (self.remoteDescriptionSet) {
       self.addIceCandidate(candidate);
     } else {
       self._ice_candidates_to_add.push(candidate);
     }
   },
 
   /**
@@ -2561,25 +2565,19 @@ PeerConnectionWrapper.prototype = {
     }
     return false;
   },
 
   /**
    * Closes the connection
    */
   close : function PCW_close() {
-    // It might be that a test has already closed the pc. In those cases
-    // we should not fail.
-    try {
-      this._pc.close();
-      info(this + ": Closed connection.");
-    }
-    catch (e) {
-      info(this + ": Failure in closing connection - " + e.message);
-    }
+    this._ice_candidates_to_add = [];
+    this._pc.close();
+    info(this + ": Closed connection.");
   },
 
   /**
    * Register all events during the setup of the data channel
    *
    * @param {Function} onDataChannelOpened
    *        Callback to execute when the data channel has been opened
    */
--- a/dom/storage/DOMStorageIPC.cpp
+++ b/dom/storage/DOMStorageIPC.cpp
@@ -584,18 +584,25 @@ DOMStorageDBParent::RecvAsyncFlush()
 
 // DOMStorageObserverSink
 
 nsresult
 DOMStorageDBParent::Observe(const char* aTopic,
                             const nsACString& aScopePrefix)
 {
   if (mIPCOpen) {
-    mozilla::unused << SendObserve(nsDependentCString(aTopic),
-                                   nsCString(aScopePrefix));
+#ifdef MOZ_NUWA_PROCESS
+    if (!(static_cast<ContentParent*>(Manager())->IsNuwaProcess() &&
+          ContentParent::IsNuwaReady())) {
+#endif
+      mozilla::unused << SendObserve(nsDependentCString(aTopic),
+                                     nsCString(aScopePrefix));
+#ifdef MOZ_NUWA_PROCESS
+    }
+#endif
   }
 
   return NS_OK;
 }
 
 namespace { // anon
 
 // Results must be sent back on the main thread
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -477,29 +477,29 @@ NetworkManager.prototype = {
     return isValid;
   },
 
   addHostRoute: function(network, host) {
     if (!this.isValidatedNetwork(network)) {
       return Promise.reject("Invalid network interface.");
     }
 
-    return this.resolveHostname(host)
+    return this.resolveHostname(network, host)
       .then((ipAddresses) => this._updateRoutes(true,
                                                 ipAddresses,
                                                 network.name,
                                                 network.getGateways()));
   },
 
   removeHostRoute: function(network, host) {
     if (!this.isValidatedNetwork(network)) {
       return Promise.reject("Invalid network interface.");
     }
 
-    return this.resolveHostname(host)
+    return this.resolveHostname(network, host)
       .then((ipAddresses) => this._updateRoutes(false,
                                                 ipAddresses,
                                                 network.name,
                                                 network.getGateways()));
   },
 
 #ifdef MOZ_B2G_RIL
   isNetworkTypeSecondaryMobile: function(type) {
@@ -589,28 +589,28 @@ NetworkManager.prototype = {
     let oldActive = this.active;
 
     if (this._overriddenActive) {
       debug("We have an override for the active network: " +
             this._overriddenActive.name);
       // The override was just set, so reconfigure the network.
       if (this.active != this._overriddenActive) {
         this.active = this._overriddenActive;
-        gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
+        this._setDefaultRouteAndDNS(this.active, oldActive);
         Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
       }
       return;
     }
 
     // The active network is already our preferred type.
     if (this.active &&
         this.active.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED &&
         this.active.type == this._preferredNetworkType) {
       debug("Active network is already our preferred type.");
-      gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
+      this._setDefaultRouteAndDNS(this.active, oldActive);
       return;
     }
 
     // Find a suitable network interface to activate.
     this.active = null;
 #ifdef MOZ_B2G_RIL
     let defaultDataNetwork;
 #endif
@@ -636,35 +636,35 @@ NetworkManager.prototype = {
       // and DNS on seconary APN.
       if (defaultDataNetwork &&
           this.isNetworkTypeSecondaryMobile(this.active.type) &&
           this.active.type != this.preferredNetworkType) {
         this.active = defaultDataNetwork;
       }
       // Don't set default route on secondary APN
       if (this.isNetworkTypeSecondaryMobile(this.active.type)) {
-        gNetworkService.setDNS(this.active);
+        gNetworkService.setDNS(this.active, function() {});
       } else {
 #endif // MOZ_B2G_RIL
-        gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
+        this._setDefaultRouteAndDNS(this.active, oldActive);
 #ifdef MOZ_B2G_RIL
       }
 #endif
     }
 
     if (this.active != oldActive) {
       Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
     }
 
     if (this._manageOfflineStatus) {
       Services.io.offline = !this.active;
     }
   },
 
-  resolveHostname: function(hostname) {
+  resolveHostname: function(network, hostname) {
     // Sanity check for null, undefined and empty string... etc.
     if (!hostname) {
       return Promise.reject(new Error("hostname is empty: " + hostname));
     }
 
     if (hostname.match(this.REGEXP_IPV4) ||
         hostname.match(this.REGEXP_IPV6)) {
       return Promise.resolve([hostname]);
@@ -689,18 +689,28 @@ NetworkManager.prototype = {
       }
 
       if (DEBUG) debug("hostname is resolved: " + hostname);
       if (DEBUG) debug("Addresses: " + JSON.stringify(retval));
 
       deferred.resolve(retval);
     };
 
+    // Bug 1058282 - Explicitly request ipv4 to get around 8.8.8.8 probe at
+    // http://androidxref.com/4.3_r2.1/xref/bionic/libc/netbsd/net/getaddrinfo.c#1923
+    //
+    // Whenever MMS connection is the only network interface, there is no
+    // default route so that any ip probe will fail.
+    let flags = 0;
+    if (network.type === Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) {
+      flags |= Ci.nsIDNSService.RESOLVE_DISABLE_IPV6;
+    }
+
     // TODO: Bug 992772 - Resolve the hostname with specified networkInterface.
-    gDNSService.asyncResolve(hostname, 0, onLookupComplete, Services.tm.mainThread);
+    gDNSService.asyncResolve(hostname, flags, onLookupComplete, Services.tm.mainThread);
 
     return deferred.promise;
   },
 
   convertConnectionType: function(network) {
     // If there is internal interface change (e.g., MOBILE_MMS, MOBILE_SUPL),
     // the function will return null so that it won't trigger type change event
     // in NetworkInformation API.
@@ -1292,17 +1302,25 @@ NetworkManager.prototype = {
     if (this._usbTetheringAction === TETHERING_STATE_ONGOING) {
       debug("Postpone the event and handle it when state is idle.");
       this.wantConnectionEvent = callback;
       return;
     }
     this.wantConnectionEvent = null;
 
     callback.call(this);
-  }
+  },
+
+  _setDefaultRouteAndDNS: function(network, oldInterface) {
+    gNetworkService.setDefaultRoute(network, oldInterface, function(success) {
+      gNetworkService.setDNS(network, function(result) {
+        gNetworkService.setNetworkProxy(network);
+      });
+    });
+  },
 };
 
 let CaptivePortalDetectionHelper = (function() {
 
   const EVENT_CONNECT = "Connect";
   const EVENT_DISCONNECT = "Disconnect";
   let _ongoingInterface = null;
   let _available = ("nsICaptivePortalDetector" in Ci);
--- a/dom/system/gonk/NetworkService.js
+++ b/dom/system/gonk/NetworkService.js
@@ -183,17 +183,16 @@ NetworkService.prototype = {
 
     let params = {
       cmd: "setNetworkInterfaceAlarm",
       ifname: networkName,
       threshold: threshold
     };
 
     params.report = true;
-    params.isAsync = true;
 
     this.controlMessage(params, function(result) {
       if (!isError(result.resultCode)) {
         callback.networkUsageAlarmResult(null);
         return;
       }
 
       this._enableNetworkInterfaceAlarm(networkName, threshold, callback);
@@ -205,17 +204,16 @@ NetworkService.prototype = {
 
     let params = {
       cmd: "enableNetworkInterfaceAlarm",
       ifname: networkName,
       threshold: threshold
     };
 
     params.report = true;
-    params.isAsync = true;
 
     this.controlMessage(params, function(result) {
       if (!isError(result.resultCode)) {
         callback.networkUsageAlarmResult(null);
         return;
       }
       callback.networkUsageAlarmResult(result.reason);
     });
@@ -225,34 +223,32 @@ NetworkService.prototype = {
     if(DEBUG) debug("disableNetworkInterfaceAlarm for " + networkName);
 
     let params = {
       cmd: "disableNetworkInterfaceAlarm",
       ifname: networkName,
     };
 
     params.report = true;
-    params.isAsync = true;
 
     this.controlMessage(params, function(result) {
       callback(result);
     });
   },
 
   setWifiOperationMode: function(interfaceName, mode, callback) {
     if(DEBUG) debug("setWifiOperationMode on " + interfaceName + " to " + mode);
 
     let params = {
       cmd: "setWifiOperationMode",
       ifname: interfaceName,
       mode: mode
     };
 
     params.report = true;
-    params.isAsync = true;
 
     this.controlMessage(params, function(result) {
       if (isError(result.resultCode)) {
         callback.wifiOperationModeResult("netd command error");
       } else {
         callback.wifiOperationModeResult(null);
       }
     });
@@ -272,42 +268,42 @@ NetworkService.prototype = {
         ifname: network.name,
         ip: ip,
         prefixLength: prefixLength
       };
       this.controlMessage(options);
     }
   },
 
-  setDNS: function(networkInterface) {
-    if(DEBUG) debug("Going DNS to " + networkInterface.name);
+  setDNS: function(networkInterface, callback) {
+    if (DEBUG) debug("Going DNS to " + networkInterface.name);
     let dnses = networkInterface.getDnses();
     let options = {
       cmd: "setDNS",
       ifname: networkInterface.name,
       domain: "mozilla." + networkInterface.name + ".doman",
       dnses: dnses
     };
-    this.controlMessage(options);
+    this.controlMessage(options, function(result) {
+      callback.setDnsResult(result.success ? null : result.reason);
+    });
   },
 
-  setDefaultRouteAndDNS: function(network, oldInterface) {
-    if(DEBUG) debug("Going to change route and DNS to " + network.name);
+  setDefaultRoute: function(network, oldInterface, callback) {
+    if (DEBUG) debug("Going to change default route to " + network.name);
     let gateways = network.getGateways();
-    let dnses = network.getDnses();
     let options = {
-      cmd: "setDefaultRouteAndDNS",
+      cmd: "setDefaultRoute",
       ifname: network.name,
       oldIfname: (oldInterface && oldInterface !== network) ? oldInterface.name : null,
-      gateways: gateways,
-      domain: "mozilla." + network.name + ".doman",
-      dnses: dnses
+      gateways: gateways
     };
-    this.controlMessage(options);
-    this.setNetworkProxy(network);
+    this.controlMessage(options, function(result) {
+      callback.nativeCommandResult(!result.error);
+    });
   },
 
   removeDefaultRoute: function(network) {
     if(DEBUG) debug("Remove default route for " + network.name);
     let gateways = network.getGateways();
     let options = {
       cmd: "removeDefaultRoute",
       ifname: network.name,
@@ -410,17 +406,16 @@ NetworkService.prototype = {
 
   // Enable/Disable DHCP server.
   setDhcpServer: function(enabled, config, callback) {
     if (null === config) {
       config = {};
     }
 
     config.cmd = "setDhcpServer";
-    config.isAsync = true;
     config.enabled = enabled;
 
     this.controlMessage(config, function setDhcpServerResult(response) {
       if (!response.success) {
         callback.dhcpServerResult('Set DHCP server error');
         return;
       }
       callback.dhcpServerResult(null);
@@ -432,17 +427,16 @@ NetworkService.prototype = {
     // config should've already contained:
     //   .ifname
     //   .internalIfname
     //   .externalIfname
     config.wifictrlinterfacename = WIFI_CTRL_INTERFACE;
     config.cmd = "setWifiTethering";
 
     // The callback function in controlMessage may not be fired immediately.
-    config.isAsync = true;
     this.controlMessage(config, function setWifiTetheringResult(data) {
       let code = data.resultCode;
       let reason = data.resultReason;
       let enable = data.enable;
       let enableString = enable ? "Enable" : "Disable";
 
       if(DEBUG) debug(enableString + " Wifi tethering result: Code " + code + " reason " + reason);
 
@@ -453,17 +447,16 @@ NetworkService.prototype = {
       }
     });
   },
 
   // Enable/disable USB tethering by sending commands to netd.
   setUSBTethering: function(enable, config, callback) {
     config.cmd = "setUSBTethering";
     // The callback function in controlMessage may not be fired immediately.
-    config.isAsync = true;
     this.controlMessage(config, function setUsbTetheringResult(data) {
       let code = data.resultCode;
       let reason = data.resultReason;
       let enable = data.enable;
       let enableString = enable ? "Enable" : "Disable";
 
       if(DEBUG) debug(enableString + " USB tethering result: Code " + code + " reason " + reason);
 
@@ -486,41 +479,99 @@ NetworkService.prototype = {
     // Ask net work to report the result when this value is set to true.
     if (callback) {
       params.report = true;
     } else {
       params.report = false;
     }
 
     // The callback function in controlMessage may not be fired immediately.
-    params.isAsync = true;
     //this._usbTetheringAction = TETHERING_STATE_ONGOING;
     this.controlMessage(params, function(data) {
       callback.enableUsbRndisResult(data.result, data.enable);
     });
   },
 
   updateUpStream: function(previous, current, callback) {
     let params = {
       cmd: "updateUpStream",
-      isAsync: true,
       preInternalIfname: previous.internalIfname,
       preExternalIfname: previous.externalIfname,
       curInternalIfname: current.internalIfname,
       curExternalIfname: current.externalIfname
     };
 
     this.controlMessage(params, function(data) {
       let code = data.resultCode;
       let reason = data.resultReason;
       if(DEBUG) debug("updateUpStream result: Code " + code + " reason " + reason);
       callback.updateUpStreamResult(!isError(code), data.curExternalIfname);
     });
   },
 
+  configureInterface: function(config, callback) {
+    let params = {
+      cmd: "configureInterface",
+      ifname: config.ifname,
+      ipaddr: config.ipaddr,
+      mask: config.mask,
+      gateway_long: config.gateway,
+      dns1_long: config.dns1,
+      dns2_long: config.dns2,
+    };
+
+    this.controlMessage(params, function(result) {
+      callback.nativeCommandResult(!result.error);
+    });
+  },
+
+  dhcpRequest: function(interfaceName, callback) {
+    let params = {
+      cmd: "dhcpRequest",
+      ifname: interfaceName
+    };
+
+    this.controlMessage(params, function(result) {
+      callback.dhcpRequestResult(!result.error, result.error ? null : result);
+    });
+  },
+
+  enableInterface: function(interfaceName, callback) {
+    let params = {
+      cmd: "enableInterface",
+      ifname: interfaceName
+    };
+
+    this.controlMessage(params, function(result) {
+      callback.nativeCommandResult(!result.error);
+    });
+  },
+
+  disableInterface: function(interfaceName, callback) {
+    let params = {
+      cmd: "disableInterface",
+      ifname: interfaceName
+    };
+
+    this.controlMessage(params, function(result) {
+      callback.nativeCommandResult(!result.error);
+    });
+  },
+
+  resetConnections: function(interfaceName, callback) {
+    let params = {
+      cmd: "resetConnections",
+      ifname: interfaceName
+    };
+
+    this.controlMessage(params, function(result) {
+      callback.nativeCommandResult(!result.error);
+    });
+  },
+
   shutdown: false,
 
   observe: function observe(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "xpcom-shutdown":
         debug("NetworkService shutdown");
         this.shutdown = true;
         Services.obs.removeObserver(this, "xpcom-shutdown");
--- a/dom/system/gonk/NetworkUtils.cpp
+++ b/dom/system/gonk/NetworkUtils.cpp
@@ -96,17 +96,24 @@ struct CurrentCommand {
 
 typedef Tuple3<NetdCommand*, CommandChain*, CommandCallback> QueueData;
 
 #define GET_CURRENT_NETD_COMMAND   (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].a)
 #define GET_CURRENT_CHAIN          (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].b)
 #define GET_CURRENT_CALLBACK       (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].c)
 #define GET_CURRENT_COMMAND        (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].a->mData)
 
-#define CNT_OF_ARRAY(a) (sizeof(a) / sizeof(a[0]))
+// A macro for native function call return value check.
+// For native function call, non-zero return value means failure.
+#define RETURN_IF_FAILED(rv) do { \
+  if (SUCCESS != rv) { \
+    return rv; \
+  } \
+} while (0);
+
 
 static NetworkUtils* gNetworkUtils;
 static nsTArray<QueueData> gCommandQueue;
 static CurrentCommand gCurrentCommand;
 static bool gPending = false;
 static nsTArray<nsCString> gReason;
 static NetworkParams *gWifiTetheringParms = 0;
 
@@ -388,16 +395,50 @@ void NetworkUtils::next(CommandChain* aC
   if (!f) {
     delete aChain;
     return;
   }
 
   (*f)(aChain, next, aResult);
 }
 
+CommandResult::CommandResult(int32_t aResultCode)
+  : mIsPending(false)
+{
+  // This is usually not a netd command. We treat the return code
+  // typical linux convention, which uses 0 to indicate success.
+  mResult.mError = (aResultCode == SUCCESS ? false : true);
+  mResult.mResultCode = aResultCode;
+  if (aResultCode != SUCCESS) {
+    // The returned value is sometimes negative, make sure we pass a positive
+    // error number to strerror.
+    enum { STRERROR_R_BUF_SIZE = 1024, };
+    char strerrorBuf[STRERROR_R_BUF_SIZE];
+    strerror_r(abs(aResultCode), strerrorBuf, STRERROR_R_BUF_SIZE);
+    mResult.mReason = NS_ConvertUTF8toUTF16(strerrorBuf);
+  }
+  mResult.mRet = true;
+}
+
+CommandResult::CommandResult(const mozilla::dom::NetworkResultOptions& aResult)
+  : mResult(aResult)
+  , mIsPending(false)
+{
+}
+
+CommandResult::CommandResult(const Pending&)
+  : mIsPending(true)
+{
+}
+
+bool CommandResult::isPending() const
+{
+  return mIsPending;
+}
+
 /**
  * Send command to netd.
  */
 void NetworkUtils::nextNetdCommand()
 {
   if (gCommandQueue.IsEmpty() || gPending) {
     return;
   }
@@ -1025,85 +1066,89 @@ NetworkUtils::NetworkUtils(MessageCallba
 
 NetworkUtils::~NetworkUtils()
 {
 }
 
 #define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aOptions.prop).get()
 #define GET_FIELD(prop) aOptions.prop
 
+// Hoist this type definition to global to avoid template
+// instantiation error on gcc 4.4 used by ICS emulator.
+typedef CommandResult (NetworkUtils::*CommandHandler)(NetworkParams&);
+struct CommandHandlerEntry
+{
+  const char* mCommandName;
+  CommandHandler mCommandHandler;
+};
+
 void NetworkUtils::ExecuteCommand(NetworkParams aOptions)
 {
-  typedef int32_t (NetworkUtils::*CommandHandler)(NetworkParams&);
-
-  const static struct {
-    const char* mCommandName;
-    CommandHandler mCommandHandler;
-  } COMMAND_HANDLER_TABLE[] = {
+  const static CommandHandlerEntry
+    COMMAND_HANDLER_TABLE[] = {
 
     // For command 'testCommand', BUILD_ENTRY(testCommand) will generate
     // {"testCommand", NetworkUtils::testCommand}
     #define BUILD_ENTRY(c) {#c, &NetworkUtils::c}
 
     BUILD_ENTRY(removeNetworkRoute),
     BUILD_ENTRY(setDNS),
-    BUILD_ENTRY(setDefaultRouteAndDNS),
+    BUILD_ENTRY(setDefaultRoute),
     BUILD_ENTRY(removeDefaultRoute),
     BUILD_ENTRY(addHostRoute),
     BUILD_ENTRY(removeHostRoute),
     BUILD_ENTRY(removeHostRoutes),
     BUILD_ENTRY(addSecondaryRoute),
     BUILD_ENTRY(removeSecondaryRoute),
     BUILD_ENTRY(setNetworkInterfaceAlarm),
     BUILD_ENTRY(enableNetworkInterfaceAlarm),
     BUILD_ENTRY(disableNetworkInterfaceAlarm),
     BUILD_ENTRY(setWifiOperationMode),
     BUILD_ENTRY(setDhcpServer),
     BUILD_ENTRY(setWifiTethering),
     BUILD_ENTRY(setUSBTethering),
     BUILD_ENTRY(enableUsbRndis),
     BUILD_ENTRY(updateUpStream),
+    BUILD_ENTRY(configureInterface),
+    BUILD_ENTRY(dhcpRequest),
+    BUILD_ENTRY(enableInterface),
+    BUILD_ENTRY(disableInterface),
+    BUILD_ENTRY(resetConnections),
 
     #undef BUILD_ENTRY
   };
 
   // Loop until we find the command name which matches aOptions.mCmd.
   CommandHandler handler = nullptr;
-  for (size_t i = 0; i < CNT_OF_ARRAY(COMMAND_HANDLER_TABLE); i++) {
+  for (size_t i = 0; i < mozilla::ArrayLength(COMMAND_HANDLER_TABLE); i++) {
     if (aOptions.mCmd.EqualsASCII(COMMAND_HANDLER_TABLE[i].mCommandName)) {
       handler = COMMAND_HANDLER_TABLE[i].mCommandHandler;
       break;
     }
   }
 
   if (!handler) {
     // Command not found in COMMAND_HANDLER_TABLE.
     WARN("unknown message: %s", NS_ConvertUTF16toUTF8(aOptions.mCmd).get());
     return;
   }
 
-  // Command matches! Dispatch to the handler.
-  int32_t ret = 0;
-  ret = (this->*handler)(aOptions);
-
-  if (!aOptions.mIsAsync) {
-    // The requested command is synchronous, which implies the actual result
-    // from netd is not important to the client. So, just notify the
-    // registered callback.
-    NetworkResultOptions result;
-    result.mError = ret == SUCCESS ? false : true;
-    result.mResultCode = ret;
-    if (ret != SUCCESS) {
-      // The returned value is sometimes negative, make sure we pass a positive
-      // error number to strerror.
-      result.mReason = NS_ConvertUTF8toUTF16(strerror(abs(ret)));
-    }
-
-    result.mRet = true;
-    postMessage(aOptions, result);
+  // The handler would return one of the following 3 values
+  // to be wrapped to CommandResult:
+  //
+  //   1) |int32_t| for mostly synchronous native function calls.
+  //   2) |NetworkResultOptions| to populate additional results. (e.g. dhcpRequest)
+  //   3) |CommandResult::Pending| to indicate the result is not
+  //      obtained yet.
+  //
+  // If the handler returns "Pending", the handler should take the
+  // responsibility for posting result to main thread.
+  CommandResult commandResult = (this->*handler)(aOptions);
+  if (!commandResult.isPending()) {
+    postMessage(aOptions, commandResult.mResult);
   }
 }
 
 /**
  * Handle received data from netd.
  */
 void NetworkUtils::onNetdMessage(NetdCommand* aCommand)
 {
@@ -1178,36 +1223,36 @@ void NetworkUtils::onNetdMessage(NetdCom
   if (isComplete(code)) {
     nextNetdCommand();
   }
 }
 
 /**
  * Start/Stop DHCP server.
  */
-int32_t NetworkUtils::setDhcpServer(NetworkParams& aOptions)
+CommandResult NetworkUtils::setDhcpServer(NetworkParams& aOptions)
 {
   if (aOptions.mEnabled) {
     aOptions.mWifiStartIp = aOptions.mStartIp;
     aOptions.mWifiEndIp = aOptions.mEndIp;
     aOptions.mIp = aOptions.mServerIp;
     aOptions.mPrefix = aOptions.mMaskLength;
     aOptions.mLink = NS_ConvertUTF8toUTF16("up");
 
     RUN_CHAIN(aOptions, sStartDhcpServerChain, setDhcpServerFail)
   } else {
     RUN_CHAIN(aOptions, sStopDhcpServerChain, setDhcpServerFail)
   }
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
 /**
  * Set DNS servers for given network interface.
  */
-int32_t NetworkUtils::setDNS(NetworkParams& aOptions)
+CommandResult NetworkUtils::setDNS(NetworkParams& aOptions)
 {
   uint32_t length = aOptions.mDnses.Length();
 
   if (length > 0) {
     for (uint32_t i = 0; i < length; i++) {
       NS_ConvertUTF16toUTF8 autoDns(aOptions.mDnses[i]);
 
       char dns_prop_key[PROPERTY_VALUE_MAX];
@@ -1229,101 +1274,193 @@ int32_t NetworkUtils::setDNS(NetworkPara
 
   char num[PROPERTY_VALUE_MAX];
   snprintf(num, PROPERTY_VALUE_MAX - 1, "%d", atoi(dnschange) + 1);
   property_set("net.dnschange", num);
 
   // DNS needs to be set through netd since JellyBean (4.3).
   if (SDK_VERSION >= 18) {
     RUN_CHAIN(aOptions, sSetDnsChain, setDnsFail)
+    return CommandResult::Pending();
   }
 
   return SUCCESS;
 }
 
+CommandResult NetworkUtils::configureInterface(NetworkParams& aOptions)
+{
+  NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
+  return mNetUtils->do_ifc_configure(
+    autoIfname.get(),
+    aOptions.mIpaddr,
+    aOptions.mMask,
+    aOptions.mGateway_long,
+    aOptions.mDns1_long,
+    aOptions.mDns2_long
+  );
+}
+
+CommandResult NetworkUtils::dhcpRequest(NetworkParams& aOptions) {
+    mozilla::dom::NetworkResultOptions result;
+
+    NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
+    char ipaddr[PROPERTY_VALUE_MAX];
+    char gateway[PROPERTY_VALUE_MAX];
+    uint32_t prefixLength;
+    char dns1[PROPERTY_VALUE_MAX];
+    char dns2[PROPERTY_VALUE_MAX];
+    char server[PROPERTY_VALUE_MAX];
+    uint32_t lease;
+    char vendorinfo[PROPERTY_VALUE_MAX];
+    int32_t ret = mNetUtils->do_dhcp_do_request(autoIfname.get(),
+                                                ipaddr,
+                                                gateway,
+                                                &prefixLength,
+                                                dns1,
+                                                dns2,
+                                                server,
+                                                &lease,
+                                                vendorinfo);
+
+    RETURN_IF_FAILED(ret);
+
+    result.mIpaddr_str = NS_ConvertUTF8toUTF16(ipaddr);
+    result.mGateway_str = NS_ConvertUTF8toUTF16(gateway);
+    result.mDns1_str = NS_ConvertUTF8toUTF16(dns1);
+    result.mDns2_str = NS_ConvertUTF8toUTF16(dns2);
+    result.mServer_str = NS_ConvertUTF8toUTF16(server);
+    result.mVendor_str = NS_ConvertUTF8toUTF16(vendorinfo);
+    result.mLease = lease;
+    result.mMask = makeMask(prefixLength);
+
+    uint32_t inet4; // only support IPv4 for now.
+
+#define INET_PTON(var, field)                                                 \
+  PR_BEGIN_MACRO                                                              \
+    inet_pton(AF_INET, var, &inet4);                                          \
+    result.field = inet4;                                                    \
+  PR_END_MACRO
+
+    INET_PTON(ipaddr, mIpaddr);
+    INET_PTON(gateway, mGateway);
+
+    if (dns1[0] != '\0') {
+      INET_PTON(dns1, mDns1);
+    }
+
+    if (dns2[0] != '\0') {
+      INET_PTON(dns2, mDns2);
+    }
+
+    INET_PTON(server, mServer);
+
+    char inet_str[64];
+    if (inet_ntop(AF_INET, &result.mMask, inet_str, sizeof(inet_str))) {
+      result.mMask_str = NS_ConvertUTF8toUTF16(inet_str);
+    }
+
+    return result;
+}
+
+CommandResult NetworkUtils::enableInterface(NetworkParams& aOptions) {
+  return mNetUtils->do_ifc_enable(
+    NS_ConvertUTF16toUTF8(aOptions.mIfname).get());
+}
+
+CommandResult NetworkUtils::disableInterface(NetworkParams& aOptions) {
+  return mNetUtils->do_ifc_disable(
+    NS_ConvertUTF16toUTF8(aOptions.mIfname).get());
+}
+
+CommandResult NetworkUtils::resetConnections(NetworkParams& aOptions) {
+  NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
+  return mNetUtils->do_ifc_reset_connections(
+    NS_ConvertUTF16toUTF8(aOptions.mIfname).get(),
+    RESET_ALL_ADDRESSES);
+}
+
 /**
  * Set default route and DNS servers for given network interface.
  */
-int32_t NetworkUtils::setDefaultRouteAndDNS(NetworkParams& aOptions)
+CommandResult NetworkUtils::setDefaultRoute(NetworkParams& aOptions)
 {
   NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
 
   if (!aOptions.mOldIfname.IsEmpty()) {
     // Remove IPv4's default route.
-    mNetUtils->do_ifc_remove_default_route(GET_CHAR(mOldIfname));
+    RETURN_IF_FAILED(mNetUtils->do_ifc_remove_default_route(GET_CHAR(mOldIfname)));
     // Remove IPv6's default route.
-    mNetUtils->do_ifc_remove_route(GET_CHAR(mOldIfname), "::", 0, NULL);
+    RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(GET_CHAR(mOldIfname), "::", 0, NULL));
   }
 
   uint32_t length = aOptions.mGateways.Length();
   if (length > 0) {
     for (uint32_t i = 0; i < length; i++) {
       NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateways[i]);
 
       int type = getIpType(autoGateway.get());
       if (type != AF_INET && type != AF_INET6) {
         continue;
       }
 
       if (type == AF_INET6) {
-        mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, autoGateway.get());
+        RETURN_IF_FAILED(mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, autoGateway.get()));
       } else { /* type == AF_INET */
-        mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(autoGateway.get()));
+        RETURN_IF_FAILED(mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(autoGateway.get())));
       }
     }
   } else {
     // Set default froute from system properties.
     char key[PROPERTY_KEY_MAX];
     char gateway[PROPERTY_KEY_MAX];
 
     snprintf(key, sizeof key - 1, "net.%s.gw", autoIfname.get());
     property_get(key, gateway, "");
 
     int type = getIpType(gateway);
     if (type != AF_INET && type != AF_INET6) {
       return EAFNOSUPPORT;
     }
 
     if (type == AF_INET6) {
-      mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, gateway);
+      RETURN_IF_FAILED(mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, gateway));
     } else { /* type == AF_INET */
-      mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(gateway));
+      RETURN_IF_FAILED(mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(gateway)));
     }
   }
 
-  setDNS(aOptions);
   return SUCCESS;
 }
 
 /**
  * Remove default route for given network interface.
  */
-int32_t NetworkUtils::removeDefaultRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::removeDefaultRoute(NetworkParams& aOptions)
 {
   uint32_t length = aOptions.mGateways.Length();
   for (uint32_t i = 0; i < length; i++) {
     NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateways[i]);
 
     int type = getIpType(autoGateway.get());
     if (type != AF_INET && type != AF_INET6) {
       return EAFNOSUPPORT;
     }
 
-    mNetUtils->do_ifc_remove_route(GET_CHAR(mIfname),
-                                   type == AF_INET ? "0.0.0.0" : "::",
-                                   0, autoGateway.get());
+    RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(GET_CHAR(mIfname),
+                                                    type == AF_INET ? "0.0.0.0" : "::",
+                                                    0, autoGateway.get()));
   }
 
   return SUCCESS;
 }
 
 /**
  * Add host route for given network interface.
  */
-int32_t NetworkUtils::addHostRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::addHostRoute(NetworkParams& aOptions)
 {
   NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
   NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp);
   NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateway);
   int type, prefix;
 
   type = getIpType(autoHostname.get());
   if (type != AF_INET && type != AF_INET6) {
@@ -1337,17 +1474,17 @@ int32_t NetworkUtils::addHostRoute(Netwo
   prefix = type == AF_INET ? 32 : 128;
   return mNetUtils->do_ifc_add_route(autoIfname.get(), autoHostname.get(),
                                      prefix, autoGateway.get());
 }
 
 /**
  * Remove host route for given network interface.
  */
-int32_t NetworkUtils::removeHostRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::removeHostRoute(NetworkParams& aOptions)
 {
   NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
   NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp);
   NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateway);
   int type, prefix;
 
   type = getIpType(autoHostname.get());
   if (type != AF_INET && type != AF_INET6) {
@@ -1361,22 +1498,22 @@ int32_t NetworkUtils::removeHostRoute(Ne
   prefix = type == AF_INET ? 32 : 128;
   return mNetUtils->do_ifc_remove_route(autoIfname.get(), autoHostname.get(),
                                         prefix, autoGateway.get());
 }
 
 /**
  * Remove the routes associated with the named interface.
  */
-int32_t NetworkUtils::removeHostRoutes(NetworkParams& aOptions)
+CommandResult NetworkUtils::removeHostRoutes(NetworkParams& aOptions)
 {
   return mNetUtils->do_ifc_remove_host_routes(GET_CHAR(mIfname));
 }
 
-int32_t NetworkUtils::removeNetworkRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::removeNetworkRoute(NetworkParams& aOptions)
 {
   NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
   NS_ConvertUTF16toUTF8 autoIp(aOptions.mIp);
 
   int type = getIpType(autoIp.get());
   if (type != AF_INET && type != AF_INET6) {
     return EAFNOSUPPORT;
   }
@@ -1401,100 +1538,100 @@ int32_t NetworkUtils::removeNetworkRoute
     }
 
     char subnetStr[INET6_ADDRSTRLEN];
     if (!inet_ntop(AF_INET6, &in6, subnetStr, sizeof subnetStr)) {
       return EINVAL;
     }
 
     // Remove default route.
-    mNetUtils->do_ifc_remove_route(autoIfname.get(), "::", 0, NULL);
+    RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), "::", 0, NULL));
 
     // Remove subnet route.
-    mNetUtils->do_ifc_remove_route(autoIfname.get(), subnetStr, prefixLength, NULL);
+    RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), subnetStr, prefixLength, NULL));
     return SUCCESS;
   }
 
   /* type == AF_INET */
   uint32_t ip = inet_addr(autoIp.get());
   uint32_t netmask = makeMask(prefixLength);
   uint32_t subnet = ip & netmask;
   const char* gateway = "0.0.0.0";
   struct in_addr addr;
   addr.s_addr = subnet;
   const char* dst = inet_ntoa(addr);
 
-  mNetUtils->do_ifc_remove_default_route(autoIfname.get());
-  mNetUtils->do_ifc_remove_route(autoIfname.get(), dst, prefixLength, gateway);
+  RETURN_IF_FAILED(mNetUtils->do_ifc_remove_default_route(autoIfname.get()));
+  RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), dst, prefixLength, gateway));
   return SUCCESS;
 }
 
-int32_t NetworkUtils::addSecondaryRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::addSecondaryRoute(NetworkParams& aOptions)
 {
   char command[MAX_COMMAND_SIZE];
   snprintf(command, MAX_COMMAND_SIZE - 1,
            "interface route add %s secondary %s %s %s",
            GET_CHAR(mIfname),
            GET_CHAR(mIp),
            GET_CHAR(mPrefix),
            GET_CHAR(mGateway));
 
   doCommand(command, nullptr, nullptr);
   return SUCCESS;
 }
 
-int32_t NetworkUtils::removeSecondaryRoute(NetworkParams& aOptions)
+CommandResult NetworkUtils::removeSecondaryRoute(NetworkParams& aOptions)
 {
   char command[MAX_COMMAND_SIZE];
   snprintf(command, MAX_COMMAND_SIZE - 1,
            "interface route remove %s secondary %s %s %s",
            GET_CHAR(mIfname),
            GET_CHAR(mIp),
            GET_CHAR(mPrefix),
            GET_CHAR(mGateway));
 
   doCommand(command, nullptr, nullptr);
   return SUCCESS;
 }
 
-int32_t NetworkUtils::setNetworkInterfaceAlarm(NetworkParams& aOptions)
+CommandResult NetworkUtils::setNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   DEBUG("setNetworkInterfaceAlarms: %s", GET_CHAR(mIfname));
   RUN_CHAIN(aOptions, sNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail);
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
-int32_t NetworkUtils::enableNetworkInterfaceAlarm(NetworkParams& aOptions)
+CommandResult NetworkUtils::enableNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   DEBUG("enableNetworkInterfaceAlarm: %s", GET_CHAR(mIfname));
   RUN_CHAIN(aOptions, sNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail);
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
-int32_t NetworkUtils::disableNetworkInterfaceAlarm(NetworkParams& aOptions)
+CommandResult NetworkUtils::disableNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   DEBUG("disableNetworkInterfaceAlarms: %s", GET_CHAR(mIfname));
   RUN_CHAIN(aOptions, sNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail);
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
 /**
  * handling main thread's reload Wifi firmware request
  */
-int32_t NetworkUtils::setWifiOperationMode(NetworkParams& aOptions)
+CommandResult NetworkUtils::setWifiOperationMode(NetworkParams& aOptions)
 {
   DEBUG("setWifiOperationMode: %s %s", GET_CHAR(mIfname), GET_CHAR(mMode));
   RUN_CHAIN(aOptions, sWifiOperationModeChain, wifiOperationModeFail);
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
 /**
  * handling main thread's enable/disable WiFi Tethering request
  */
-int32_t NetworkUtils::setWifiTethering(NetworkParams& aOptions)
+CommandResult NetworkUtils::setWifiTethering(NetworkParams& aOptions)
 {
   bool enable = aOptions.mEnable;
   IFProperties interfaceProperties;
   getIFProperties(GET_CHAR(mExternalIfname), interfaceProperties);
 
   if (strcmp(interfaceProperties.dns1, "")) {
     int type = getIpType(interfaceProperties.dns1);
     if (type != AF_INET6) {
@@ -1513,20 +1650,20 @@ int32_t NetworkUtils::setWifiTethering(N
     DEBUG("Starting Wifi Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
     RUN_CHAIN(aOptions, sWifiEnableChain, wifiTetheringFail)
   } else {
     DEBUG("Stopping Wifi Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
     RUN_CHAIN(aOptions, sWifiDisableChain, wifiTetheringFail)
   }
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
-int32_t NetworkUtils::setUSBTethering(NetworkParams& aOptions)
+CommandResult NetworkUtils::setUSBTethering(NetworkParams& aOptions)
 {
   bool enable = aOptions.mEnable;
   IFProperties interfaceProperties;
   getIFProperties(GET_CHAR(mExternalIfname), interfaceProperties);
 
   if (strcmp(interfaceProperties.dns1, "")) {
     int type = getIpType(interfaceProperties.dns1);
     if (type != AF_INET6) {
@@ -1545,61 +1682,59 @@ int32_t NetworkUtils::setUSBTethering(Ne
     DEBUG("Starting USB Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
     RUN_CHAIN(aOptions, sUSBEnableChain, usbTetheringFail)
   } else {
     DEBUG("Stopping USB Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
     RUN_CHAIN(aOptions, sUSBDisableChain, usbTetheringFail)
   }
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
 void NetworkUtils::escapeQuote(nsCString& aString)
 {
   aString.ReplaceSubstring("\\", "\\\\");
   aString.ReplaceSubstring("\"", "\\\"");
 }
 
-void NetworkUtils::checkUsbRndisState(NetworkParams& aOptions)
+CommandResult NetworkUtils::checkUsbRndisState(NetworkParams& aOptions)
 {
   static uint32_t retry = 0;
 
   char currentState[PROPERTY_VALUE_MAX];
   property_get(SYS_USB_STATE_PROPERTY, currentState, nullptr);
 
   nsTArray<nsCString> stateFuncs;
   split(currentState, USB_CONFIG_DELIMIT, stateFuncs);
   bool rndisPresent = stateFuncs.Contains(nsCString(USB_FUNCTION_RNDIS));
 
   if (aOptions.mEnable == rndisPresent) {
     NetworkResultOptions result;
     result.mEnable = aOptions.mEnable;
     result.mResult = true;
-    postMessage(aOptions, result);
     retry = 0;
-    return;
+    return result;
   }
   if (retry < USB_FUNCTION_RETRY_TIMES) {
     retry++;
     usleep(USB_FUNCTION_RETRY_INTERVAL * 1000);
-    checkUsbRndisState(aOptions);
-    return;
+    return checkUsbRndisState(aOptions);
   }
 
   NetworkResultOptions result;
   result.mResult = false;
-  postMessage(aOptions, result);
   retry = 0;
+  return result;
 }
 
 /**
  * Modify usb function's property to turn on USB RNDIS function
  */
-int32_t NetworkUtils::enableUsbRndis(NetworkParams& aOptions)
+CommandResult NetworkUtils::enableUsbRndis(NetworkParams& aOptions)
 {
   bool report = aOptions.mReport;
 
   // For some reason, rndis doesn't play well with diag,modem,nmea.
   // So when turning rndis on, we set sys.usb.config to either "rndis"
   // or "rndis,adb". When turning rndis off, we go back to
   // persist.sys.usb.config.
   //
@@ -1645,28 +1780,28 @@ int32_t NetworkUtils::enableUsbRndis(Net
   join(configFuncs, USB_CONFIG_DELIMIT, PROPERTY_VALUE_MAX, newConfig);
   if (strcmp(currentConfig, newConfig)) {
     property_set(SYS_USB_CONFIG_PROPERTY, newConfig);
   }
 
   // Trigger the timer to check usb state and report the result to NetworkManager.
   if (report) {
     usleep(USB_FUNCTION_RETRY_INTERVAL * 1000);
-    checkUsbRndisState(aOptions);
+    return checkUsbRndisState(aOptions);
   }
   return SUCCESS;
 }
 
 /**
  * handling upstream interface change event.
  */
-int32_t NetworkUtils::updateUpStream(NetworkParams& aOptions)
+CommandResult NetworkUtils::updateUpStream(NetworkParams& aOptions)
 {
   RUN_CHAIN(aOptions, sUpdateUpStreamChain, updateUpStreamFail)
-  return SUCCESS;
+  return CommandResult::Pending();
 }
 
 void NetworkUtils::sendBroadcastMessage(uint32_t code, char* reason)
 {
   NetworkResultOptions result;
   switch(code) {
     case NETD_COMMAND_INTERFACE_CHANGE:
       result.mTopic = NS_ConvertUTF8toUTF16("netd-interface-change");
--- a/dom/system/gonk/NetworkUtils.h
+++ b/dom/system/gonk/NetworkUtils.h
@@ -23,58 +23,16 @@ typedef void (*ErrorCallback)(NetworkPar
                               mozilla::dom::NetworkResultOptions& aResult);
 
 class NetworkParams
 {
 public:
   NetworkParams() {
   }
 
-  NetworkParams(const NetworkParams& aOther) {
-    mIp = aOther.mIp;
-    mCmd = aOther.mCmd;
-    mDomain = aOther.mDomain;
-    mGateway = aOther.mGateway;
-    mGateways = aOther.mGateways;
-    mId = aOther.mId;
-    mIfname = aOther.mIfname;
-    mPrefixLength = aOther.mPrefixLength;
-    mOldIfname = aOther.mOldIfname;
-    mMode = aOther.mMode;
-    mReport = aOther.mReport;
-    mIsAsync = aOther.mIsAsync;
-    mEnabled = aOther.mEnabled;
-    mWifictrlinterfacename = aOther.mWifictrlinterfacename;
-    mInternalIfname = aOther.mInternalIfname;
-    mExternalIfname = aOther.mExternalIfname;
-    mEnable = aOther.mEnable;
-    mSsid = aOther.mSsid;
-    mSecurity = aOther.mSecurity;
-    mKey = aOther.mKey;
-    mPrefix = aOther.mPrefix;
-    mLink = aOther.mLink;
-    mInterfaceList = aOther.mInterfaceList;
-    mWifiStartIp = aOther.mWifiStartIp;
-    mWifiEndIp = aOther.mWifiEndIp;
-    mUsbStartIp = aOther.mUsbStartIp;
-    mUsbEndIp = aOther.mUsbEndIp;
-    mDns1 = aOther.mDns1;
-    mDns2 = aOther.mDns2;
-    mDnses = aOther.mDnses;
-    mStartIp = aOther.mStartIp;
-    mEndIp = aOther.mEndIp;
-    mServerIp = aOther.mServerIp;
-    mMaskLength = aOther.mMaskLength;
-    mPreInternalIfname = aOther.mPreInternalIfname;
-    mPreExternalIfname = aOther.mPreExternalIfname;
-    mCurInternalIfname = aOther.mCurInternalIfname;
-    mCurExternalIfname = aOther.mCurExternalIfname;
-    mThreshold = aOther.mThreshold;
-  }
-
   NetworkParams(const mozilla::dom::NetworkCommandOptions& aOther) {
 
 #define COPY_SEQUENCE_FIELD(prop, type)                                                      \
     if (aOther.prop.WasPassed()) {                                                           \
       mozilla::dom::Sequence<type > const & currentValue = aOther.prop.InternalValue();      \
       uint32_t length = currentValue.Length();                                               \
       for (uint32_t idx = 0; idx < length; idx++) {                                          \
         prop.AppendElement(currentValue[idx]);                                               \
@@ -107,17 +65,16 @@ public:
     COPY_OPT_STRING_FIELD(mGateway, EmptyString())
     COPY_SEQUENCE_FIELD(mGateways, nsString)
     COPY_OPT_STRING_FIELD(mIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mIp, EmptyString())
     COPY_OPT_FIELD(mPrefixLength, 0)
     COPY_OPT_STRING_FIELD(mOldIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mMode, EmptyString())
     COPY_OPT_FIELD(mReport, false)
-    COPY_OPT_FIELD(mIsAsync, false)
     COPY_OPT_FIELD(mEnabled, false)
     COPY_OPT_STRING_FIELD(mWifictrlinterfacename, EmptyString())
     COPY_OPT_STRING_FIELD(mInternalIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mExternalIfname, EmptyString())
     COPY_OPT_FIELD(mEnable, false)
     COPY_OPT_STRING_FIELD(mSsid, EmptyString())
     COPY_OPT_STRING_FIELD(mSecurity, EmptyString())
     COPY_OPT_STRING_FIELD(mKey, EmptyString())
@@ -135,16 +92,21 @@ public:
     COPY_OPT_STRING_FIELD(mEndIp, EmptyString())
     COPY_OPT_STRING_FIELD(mServerIp, EmptyString())
     COPY_OPT_STRING_FIELD(mMaskLength, EmptyString())
     COPY_OPT_STRING_FIELD(mPreInternalIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mPreExternalIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mCurInternalIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mCurExternalIfname, EmptyString())
     COPY_OPT_FIELD(mThreshold, -1)
+    COPY_OPT_FIELD(mIpaddr, 0)
+    COPY_OPT_FIELD(mMask, 0)
+    COPY_OPT_FIELD(mGateway_long, 0)
+    COPY_OPT_FIELD(mDns1_long, 0)
+    COPY_OPT_FIELD(mDns2_long, 0)
 
 #undef COPY_SEQUENCE_FIELD
 #undef COPY_OPT_STRING_FIELD
 #undef COPY_OPT_FIELD
 #undef COPY_FIELD
   }
 
   int32_t mId;
@@ -153,17 +115,16 @@ public:
   nsString mGateway;
   nsTArray<nsString> mGateways;
   nsString mIfname;
   nsString mIp;
   uint32_t mPrefixLength;
   nsString mOldIfname;
   nsString mMode;
   bool mReport;
-  bool mIsAsync;
   bool mEnabled;
   nsString mWifictrlinterfacename;
   nsString mInternalIfname;
   nsString mExternalIfname;
   bool mEnable;
   nsString mSsid;
   nsString mSecurity;
   nsString mKey;
@@ -181,16 +142,21 @@ public:
   nsString mEndIp;
   nsString mServerIp;
   nsString mMaskLength;
   nsString mPreInternalIfname;
   nsString mPreExternalIfname;
   nsString mCurInternalIfname;
   nsString mCurExternalIfname;
   long mThreshold;
+  long mIpaddr;
+  long mMask;
+  long mGateway_long;
+  long mDns1_long;
+  long mDns2_long;
 };
 
 // CommandChain store the necessary information to execute command one by one.
 // Including :
 // 1. Command parameters.
 // 2. Command list.
 // 3. Error callback function.
 // 4. Index of current execution command.
@@ -230,49 +196,73 @@ public:
 private:
   uint32_t mIndex;
   NetworkParams mParams;
   CommandFunc* mCommands;
   uint32_t mLength;
   ErrorCallback mError;
 };
 
+// A helper class to easily construct a resolved
+// or a pending result for command execution.
+class CommandResult
+{
+public:
+  struct Pending {};
+
+public:
+  CommandResult(int32_t aResultCode);
+  CommandResult(const mozilla::dom::NetworkResultOptions& aResult);
+  CommandResult(const Pending&);
+  bool isPending() const;
+
+  mozilla::dom::NetworkResultOptions mResult;
+
+private:
+  bool mIsPending;
+};
+
 class NetworkUtils MOZ_FINAL
 {
 public:
   NetworkUtils(MessageCallback aCallback);
   ~NetworkUtils();
 
   void ExecuteCommand(NetworkParams aOptions);
   void onNetdMessage(mozilla::ipc::NetdCommand* aCommand);
 
   MessageCallback getMessageCallback() { return mMessageCallback; }
 
 private:
   /**
    * Commands supported by NetworkUtils.
    */
-  int32_t setDNS(NetworkParams& aOptions);
-  int32_t setDefaultRouteAndDNS(NetworkParams& aOptions);
-  int32_t addHostRoute(NetworkParams& aOptions);
-  int32_t removeDefaultRoute(NetworkParams& aOptions);
-  int32_t removeHostRoute(NetworkParams& aOptions);
-  int32_t removeHostRoutes(NetworkParams& aOptions);
-  int32_t removeNetworkRoute(NetworkParams& aOptions);
-  int32_t addSecondaryRoute(NetworkParams& aOptions);
-  int32_t removeSecondaryRoute(NetworkParams& aOptions);
-  int32_t setNetworkInterfaceAlarm(NetworkParams& aOptions);
-  int32_t enableNetworkInterfaceAlarm(NetworkParams& aOptions);
-  int32_t disableNetworkInterfaceAlarm(NetworkParams& aOptions);
-  int32_t setWifiOperationMode(NetworkParams& aOptions);
-  int32_t setDhcpServer(NetworkParams& aOptions);
-  int32_t setWifiTethering(NetworkParams& aOptions);
-  int32_t setUSBTethering(NetworkParams& aOptions);
-  int32_t enableUsbRndis(NetworkParams& aOptions);
-  int32_t updateUpStream(NetworkParams& aOptions);
+  CommandResult configureInterface(NetworkParams& aOptions);
+  CommandResult dhcpRequest(NetworkParams& aOptions);
+  CommandResult enableInterface(NetworkParams& aOptions);
+  CommandResult disableInterface(NetworkParams& aOptions);
+  CommandResult resetConnections(NetworkParams& aOptions);
+  CommandResult setDefaultRoute(NetworkParams& aOptions);
+  CommandResult addHostRoute(NetworkParams& aOptions);
+  CommandResult removeDefaultRoute(NetworkParams& aOptions);
+  CommandResult removeHostRoute(NetworkParams& aOptions);
+  CommandResult removeHostRoutes(NetworkParams& aOptions);
+  CommandResult removeNetworkRoute(NetworkParams& aOptions);
+  CommandResult setDNS(NetworkParams& aOptions);
+  CommandResult addSecondaryRoute(NetworkParams& aOptions);
+  CommandResult removeSecondaryRoute(NetworkParams& aOptions);
+  CommandResult setNetworkInterfaceAlarm(NetworkParams& aOptions);
+  CommandResult enableNetworkInterfaceAlarm(NetworkParams& aOptions);
+  CommandResult disableNetworkInterfaceAlarm(NetworkParams& aOptions);
+  CommandResult setWifiOperationMode(NetworkParams& aOptions);
+  CommandResult setDhcpServer(NetworkParams& aOptions);
+  CommandResult setWifiTethering(NetworkParams& aOptions);
+  CommandResult setUSBTethering(NetworkParams& aOptions);
+  CommandResult enableUsbRndis(NetworkParams& aOptions);
+  CommandResult updateUpStream(NetworkParams& aOptions);
 
   /**
    * function pointer array holds all netd commands should be executed
    * in sequence to accomplish a given command by other module.
    */
   static CommandFunc sWifiEnableChain[];
   static CommandFunc sWifiDisableChain[];
   static CommandFunc sWifiFailChain[];
@@ -355,17 +345,17 @@ private:
   /**
    * Notify broadcast message to main thread.
    */
   void sendBroadcastMessage(uint32_t code, char* reason);
 
   /**
    * Utility functions.
    */
-  void checkUsbRndisState(NetworkParams& aOptions);
+  CommandResult checkUsbRndisState(NetworkParams& aOptions);
   void dumpParams(NetworkParams& aOptions, const char* aType);
 
   static void escapeQuote(nsCString& aString);
   inline uint32_t netdResponseType(uint32_t code);
   inline bool isBroadcastMessage(uint32_t code);
   inline bool isError(uint32_t code);
   inline bool isComplete(uint32_t code);
   inline bool isProceeding(uint32_t code);
--- a/dom/system/gonk/NetworkWorker.cpp
+++ b/dom/system/gonk/NetworkWorker.cpp
@@ -28,34 +28,19 @@ StaticRefPtr<NetworkWorker> gNetworkWork
 // The singleton networkutils class, that can be used on any thread.
 static nsAutoPtr<NetworkUtils> gNetworkUtils;
 
 // Runnable used dispatch command result on the main thread.
 class NetworkResultDispatcher : public nsRunnable
 {
 public:
   NetworkResultDispatcher(const NetworkResultOptions& aResult)
+    : mResult(aResult)
   {
     MOZ_ASSERT(!NS_IsMainThread());
-
-#define COPY_FIELD(prop) mResult.prop = aResult.prop;
-    COPY_FIELD(mId)
-    COPY_FIELD(mRet)
-    COPY_FIELD(mBroadcast)
-    COPY_FIELD(mTopic)
-    COPY_FIELD(mReason)
-    COPY_FIELD(mResultCode)
-    COPY_FIELD(mResultReason)
-    COPY_FIELD(mError)
-    COPY_FIELD(mEnable)
-    COPY_FIELD(mResult)
-    COPY_FIELD(mSuccess)
-    COPY_FIELD(mCurExternalIfname)
-    COPY_FIELD(mCurInternalIfname)
-#undef COPY_FIELD
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (gNetworkWorker) {
       gNetworkWorker->DispatchNetworkResult(mResult);
--- a/dom/system/gonk/nsINetworkService.idl
+++ b/dom/system/gonk/nsINetworkService.idl
@@ -96,20 +96,75 @@ interface nsIUpdateUpStreamCallback : ns
    * @param success
    *        Boolean to indicate the operation is successful or not.
    * @param externalIfname
    *        The external interface name.
    */
   void updateUpStreamResult(in boolean success, in DOMString externalIfname);
 };
 
+[scriptable, function, uuid(eedca6c0-1310-11e4-9191-0800200c9a66)]
+interface nsISetDnsCallback : nsISupports
+{
+  /**
+   * Callback function used to report the result of setting DNS server.
+   *
+   * @param error
+   *        An error message if the operation wasn't successful,
+   *        or `null` if it was.
+   */
+  void setDnsResult(in jsval error);
+};
+
+[scriptable, function, uuid(5d0e1a60-1187-11e4-9191-0800200c9a66)]
+interface nsINativeCommandCallback : nsISupports
+{
+  /**
+   * Callback function used to report the result of a network native command.
+   *
+   * @param success
+   *        Boolean to indicate the operation is successful or not.
+   */
+  void nativeCommandResult(in boolean success);
+};
+
+[scriptable, function, uuid(694abb80-1187-11e4-9191-0800200c9a66)]
+interface nsIDhcpRequestCallback : nsISupports
+{
+  /**
+   * Callback function used to report the result of DHCP client request.
+   *
+   * @param success
+   *        Boolean to indicate the operation is successful or not.
+   *
+   * @param dhcpInfo
+   *        An object to represent the successful DHCP request:
+   *
+   *          - gateway_str: string
+   *          - dns1_str:    string
+   *          - dns2_str:    string
+   *          - mask_str:    string
+   *          - server_str:  string
+   *          - vendor_str:  string
+   *          - lease:       long
+   *          - mask:        long
+   *          - ipaddr:      long
+   *          - gateway:     long
+   *          - dns1:        long
+   *          - dns2:        long
+   *          - server:      long
+   */
+  void dhcpRequestResult(in boolean success, in jsval dhcpInfo);
+};
+
+
 /**
  * Provide network services.
  */
-[scriptable, uuid(ddb38428-0cf2-4c6a-a3c9-5e2f00fc54db)]
+[scriptable, uuid(9f1d78e0-1314-11e4-9191-0800200c9a66)]
 interface nsINetworkService : nsISupports
 {
   /**
    * Enable or disable Wifi Tethering
    *
    * @param enabled
    *        Boolean that indicates whether tethering should be enabled (true) or disabled (false).
    * @param config
@@ -224,29 +279,36 @@ interface nsINetworkService : nsISupport
    */
   void resetRoutingTable(in nsINetworkInterface networkInterface);
 
   /**
    * Set DNS.
    *
    * @param networkInterface
    *        The network interface which contains the DNS we want to set.
+   *
+   * @param callback
+   *        Callback to notify the result of setting DNS server.
    */
-  void setDNS(in nsINetworkInterface networkInterface);
+  void setDNS(in nsINetworkInterface networkInterface,
+              in nsISetDnsCallback callback);
 
   /**
-   * Set default route and DNS.
+   * Set default route.
    *
    * @param networkInterface
-   *        The network interface we want to set to the default route and dns.
+   *        The network interface we want to set to the default route.
    * @param oldInterface
    *        The previous network interface.
+   * @param callback
+   *        Callback to notify the result of setting default route.
    */
-  void setDefaultRouteAndDNS(in nsINetworkInterface networkInterface,
-                             in nsINetworkInterface oldInterface);
+  void setDefaultRoute(in nsINetworkInterface networkInterface,
+                       in nsINetworkInterface oldInterface,
+                       in nsINativeCommandCallback callback);
 
   /**
    * Remove default route.
    *
    * @param networkInterface
    *        The network interface we want remove from the default route.
    */
   void removeDefaultRoute(in nsINetworkInterface networkInterface);
@@ -336,9 +398,76 @@ interface nsINetworkService : nsISupport
    * @param current
    *        The current internal and external interface.
    * @param callback
    *        Callback function to report the result.
    */
   void updateUpStream(in jsval previous,
                       in jsval current,
                       in nsIUpdateUpStreamCallback callback);
+
+  /**
+   * Configure a network interface.
+   *
+   * @param config
+   *        An object containing the detail that we want to configure the interface:
+   *
+   *          - ifname:  string
+   *          - ipaddr:  long
+   *          - mask:    long
+   *          - gateway: long
+   *          - dns1:    long
+   *          - dns2:    long
+   *
+   * @param callback
+   *        Callback to notify the result of configurating network interface.
+   */
+  void configureInterface(in jsval config,
+                          in nsINativeCommandCallback callback);
+
+  /**
+   * Issue a DHCP client request.
+   *
+   * @param networkInterface
+   *        The network interface which we wnat to do the DHCP request on.
+   *
+   * @param callback
+   *        Callback to notify the result of the DHCP request.
+   */
+  void dhcpRequest(in DOMString interfaceName,
+                   in nsIDhcpRequestCallback callback);
+
+  /**
+   * Enable a network interface.
+   *
+   * @param networkInterface
+   *        The network interface name which we want to enable.
+   *
+   * @param callback
+   *        Callback to notify the result of disabling network interface.
+   */
+  void enableInterface(in DOMString interfaceName,
+                       in nsINativeCommandCallback callback);
+
+  /**
+   * Disable a network interface.
+   *
+   * @param networkInterface
+   *        The network interface name which we want to disable.
+   *
+   * @param callback
+   *        Callback to notify the result of disabling network interface.
+   */
+  void disableInterface(in DOMString interfaceName,
+                        in nsINativeCommandCallback callback);
+
+  /**
+   * Reset all connections
+   *
+   * @param networkInterface
+   *        The network interface name which we want to reset.
+   *
+   * @param callback
+   *        Callback to notify the result of resetting connections.
+   */
+  void resetConnections(in DOMString interfaceName,
+                        in nsINativeCommandCallback callback);
 };
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -73,18 +73,18 @@ interface AudioContext : EventTarget {
     [NewObject, Throws]
     PeriodicWave createPeriodicWave(Float32Array real, Float32Array imag);
 
 };
 
 // Mozilla extensions
 partial interface AudioContext {
   // Read AudioChannel.webidl for more information about this attribute.
-  [Pref="media.useAudioChannelService", SetterThrows]
-  attribute AudioChannel mozAudioChannelType;
+  [Pref="media.useAudioChannelService"]
+  readonly attribute AudioChannel mozAudioChannelType;
 
   // These 2 events are dispatched when the AudioContext object is muted by
   // the AudioChannelService. It's call 'interrupt' because when this event is
   // dispatched on a HTMLMediaElement, the audio stream is paused.
   [Pref="media.useAudioChannelService"]
   attribute EventHandler onmozinterruptbegin;
 
   [Pref="media.useAudioChannelService"]
--- a/dom/webidl/FMRadio.webidl
+++ b/dom/webidl/FMRadio.webidl
@@ -1,16 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 interface FMRadio : EventTarget {
   /* Indicates if the FM radio is enabled. */
   readonly attribute boolean enabled;
 
+  /* Indicates if RDS reception is enabled */
+  readonly attribute boolean rdsEnabled;
+
   /* Indicates if the antenna is plugged and available. */
   readonly attribute boolean antennaAvailable;
 
   /**
    * Current frequency in MHz. The value will be null if the FM radio is
    * disabled.
    */
   readonly attribute double? frequency;
@@ -26,31 +29,92 @@ interface FMRadio : EventTarget {
    * is, any two radio channels' frequencies differ by at least channelWidth
    * MHz. Usually, the value is one of:
    *  - 0.05 MHz
    *  - 0.1  MHz
    *  - 0.2  MHz
    */
   readonly attribute double channelWidth;
 
+  /**
+   * This is a mask consisting of bits corresponding to
+   * (1 << groupcode) that can be specified to receive
+   * raw RDS groups of specific group types. Note that
+   * groupcode corresponds to the upper 5 bits in block B.
+   */
+  attribute unsigned long rdsGroupMask;
+
+  /**
+   * The Program Identification (PI) code.
+   * Available if RDS is enabled on both the station and on this device.
+   * The value is null otherwise.
+   */
+  readonly attribute unsigned short? pi;
+
+  /**
+   * The Program Type (PTY) code.
+   * Available if RDS is enabled on both the station and on this device.
+   * The value is null otherwise.
+   */
+  readonly attribute octet? pty;
+
+  /**
+   * The Program Service (PS) name.
+   * Available if RDS is enabled on the station and on this device
+   */
+  readonly attribute DOMString? ps;
+
+  /**
+   * The radiotext, as provided by group 2A/2B.
+   * Available if RDS is enabled on the station and on this device
+   */
+  readonly attribute DOMString? rt;
+
+  /**
+   * The last RDS group received.
+   * Available if RDS is enabled on the station and on this device
+   */
+  readonly attribute Uint16Array? rdsgroup;
+
   /* Fired when the FM radio is enabled. */
   attribute EventHandler onenabled;
 
   /* Fired when the FM radio is disabled. */
   attribute EventHandler ondisabled;
 
+  /* Fired when the RDS is enabled. */
+  attribute EventHandler onrdsenabled;
+
+  /* Fired when the RDS is disabled. */
+  attribute EventHandler onrdsdisabled;
+
   /**
    * Fired when the antenna becomes available or unavailable, i.e., fired when
    * the antennaAvailable attribute changes.
    */
   attribute EventHandler onantennaavailablechange;
 
   /* Fired when the FM radio's frequency is changed. */
   attribute EventHandler onfrequencychange;
 
+  /* Fired when the PI code changes */
+  attribute EventHandler onpichange;
+
+  /* Fired when the PTY changes */
+  attribute EventHandler onptychange;
+
+  /* Fired when the PS name changes */
+  attribute EventHandler onpschange;
+
+  /* Fired when the radiotext changes */
+  attribute EventHandler onrtchange;
+
+  /* Fired when we get a new RDS group */
+  attribute EventHandler onnewrdsgroup;
+
   /**
    * Power the FM radio off. The disabled event will be fired if this request
    * completes successfully.
    */
   DOMRequest disable();
 
   /**
    * Power the FM radio on, and tune the radio to the given frequency in MHz.
@@ -89,10 +153,24 @@ interface FMRadio : EventTarget {
    */
   DOMRequest seekDown();
 
   /**
    * Cancel the seek action. If the radio is not currently seeking up or down,
    * error will be fired.
    */
   DOMRequest cancelSeek();
+
+  /**
+   * Enable RDS reception.
+   *
+   * If the radio is off, RDS will be enabled when the radio is turned on.
+   */
+  DOMRequest enableRDS();
+
+  /**
+   * Disable RDS reception.
+   *
+   * If the radio is off, RDS will not be enabled when the radio is turned on.
+   */
+  DOMRequest disableRDS();
 };
 
--- a/dom/webidl/NetworkOptions.webidl
+++ b/dom/webidl/NetworkOptions.webidl
@@ -17,17 +17,16 @@ dictionary NetworkCommandOptions
   unsigned long prefixLength;         // for "removeNetworkRoute".
   DOMString domain;                   // for "setDNS"
   sequence<DOMString> dnses;          // for "setDNS", "setDefaultRouteAndDNS".
   DOMString oldIfname;                // for "setDefaultRouteAndDNS".
   DOMString gateway;                  // for "addSecondaryRoute", "removeSecondaryRoute".
   sequence<DOMString> gateways;       // for "setDefaultRouteAndDNS", "removeDefaultRoute".
   DOMString mode;                     // for "setWifiOperationMode".
   boolean report;                     // for "setWifiOperationMode".
-  boolean isAsync;                    // for "setWifiOperationMode".
   boolean enabled;                    // for "setDhcpServer".
   DOMString wifictrlinterfacename;    // for "setWifiTethering".
   DOMString internalIfname;           // for "setWifiTethering".
   DOMString externalIfname;           // for "setWifiTethering".
   boolean enable;                     // for "setWifiTethering".
   DOMString ssid;                     // for "setWifiTethering".
   DOMString security;                 // for "setWifiTethering".
   DOMString key;                      // for "setWifiTethering".
@@ -45,16 +44,22 @@ dictionary NetworkCommandOptions
   DOMString startIp;                  // for "setDhcpServer".
   DOMString endIp;                    // for "setDhcpServer".
   DOMString serverIp;                 // for "setDhcpServer".
   DOMString maskLength;               // for "setDhcpServer".
   DOMString preInternalIfname;        // for "updateUpStream".
   DOMString preExternalIfname;        // for "updateUpStream".
   DOMString curInternalIfname;        // for "updateUpStream".
   DOMString curExternalIfname;        // for "updateUpStream".
+
+  long ipaddr;                        // for "ifc_configure".
+  long mask;                          // for "ifc_configure".
+  long gateway_long;                  // for "ifc_configure".
+  long dns1_long;                     // for "ifc_configure".
+  long dns2_long;                     // for "ifc_configure".
 };
 
 /**
 * This dictionary holds the parameters sent back to NetworkService.js.
 */
 dictionary NetworkResultOptions
 {
   long id = 0;                        // opaque id.
@@ -68,9 +73,27 @@ dictionary NetworkResultOptions
   boolean error = false;              // for all commands.
 
   boolean enable = false;             // for "setWifiTethering", "setUSBTethering"
                                       //     "enableUsbRndis".
   boolean result = false;             // for "enableUsbRndis".
   boolean success = false;            // for "setDhcpServer".
   DOMString curExternalIfname = "";   // for "updateUpStream".
   DOMString curInternalIfname = "";   // for "updateUpStream".
+
+  DOMString reply = "";               // for "command".
+  DOMString route = "";               // for "ifc_get_default_route".
+  DOMString ipaddr_str = "";          // The following are for the result of
+                                      // dhcp_do_request.
+  DOMString gateway_str = "";
+  DOMString dns1_str = "";
+  DOMString dns2_str = "";
+  DOMString mask_str = "";
+  DOMString server_str = "";
+  DOMString vendor_str = "";
+  long      lease = 0;
+  long      mask = 0;
+  long      ipaddr = 0;
+  long      gateway = 0;
+  long      dns1 = 0;
+  long      dns2 = 0;
+  long      server = 0;
 };
--- a/dom/webidl/TestInterfaceJS.webidl
+++ b/dom/webidl/TestInterfaceJS.webidl
@@ -37,9 +37,15 @@ interface TestInterfaceJS {
   (DOMString or TestInterfaceJS?) pingPongUnionContainingNull((TestInterfaceJS? or DOMString) something);
   (TestInterfaceJS or long)? pingPongNullableUnion((TestInterfaceJS or long)? something);
   (Location or TestInterfaceJS) returnBadUnion();
 
   [Cached, Pure]
   readonly attribute short cachedAttr;
   void setCachedAttr(short n);
   void clearCachedAttrCache();
+
+  // Test for sequence overloading and union behavior
+  void testSequenceOverload(sequence<DOMString> arg);
+  void testSequenceOverload(DOMString arg);
+
+  void testSequenceUnion((sequence<DOMString> or DOMString) arg);
 };
--- a/dom/webidl/WifiOptions.webidl
+++ b/dom/webidl/WifiOptions.webidl
@@ -5,61 +5,27 @@
 /**
   * This dictionnary holds the parameters sent to the wifi service.
   */
 dictionary WifiCommandOptions
 {
   long      id = 0;       // opaque id.
   DOMString cmd = "";     // the command name.
   DOMString request;      // for "command"
-  DOMString ifname;       // for "ifc_reset_connections", "ifc_enable",
-                          // "ifc_disable", "ifc_remove_host_routes",
-                          // "ifc_remove_default_route", "dhcp_stop",
-                          // "dhcp_release_lease", "ifc_get_default_route",
-                          // "ifc_add_host_route", "ifc_set_default_route",
-                          // "ifc_configure", "dhcp_do_request",
-                          // "dhcp_do_request_renew".
-  long route;             // for "ifc_add_host_route", "ifc_set_default_route".
-  long ipaddr;            // for "ifc_configure".
-  long mask;              // for "ifc_configure".
-  long gateway;           // for "ifc_configure".
-  long dns1;              // for "ifc_configure".
-  long dns2;              // for "ifc_configure".
-  DOMString key;          // for "property_get", "property_set".
-  DOMString value;        // for "property_set".
-  DOMString defaultValue; // for "property_get".
 };
 
 /**
   * This dictionnary holds the parameters sent back to WifiWorker.js
   */
 dictionary WifiResultOptions
 {
   long      id = 0;             // opaque id.
   long      status = 0;         // the return status of the command.
                                 // Used by most commands.
   DOMString reply = "";         // for "command".
-  DOMString route = "";         // for "ifc_get_default_route".
-  DOMString error = "";         // for "dhcp_get_errmsg".
-  DOMString value = "";         // for "property_get".
-  DOMString ipaddr_str = "";    // The following are for the result of
-                                // dhcp_do_request.
-  DOMString gateway_str = "";
-  DOMString dns1_str = "";
-  DOMString dns2_str = "";
-  DOMString mask_str = "";
-  DOMString server_str = "";
-  DOMString vendor_str = "";
-  long      lease = 0;
-  long      mask = 0;
-  long      ipaddr = 0;
-  long      gateway = 0;
-  long      dns1 = 0;
-  long      dns2 = 0;
-  long      server = 0;
 };
 
 
 /**
   * This dictionary holds the callback parameter sent back from WifiCertService
   * to WifiWorker, and should only be passed around in chrome process.
   */
 dictionary WifiCertServiceResultOptions
--- a/dom/wifi/WifiNetUtil.jsm
+++ b/dom/wifi/WifiNetUtil.jsm
@@ -25,126 +25,45 @@ this.WifiNetUtil = function(controlMessa
   function debug(msg) {
     if (DEBUG) {
       dump('-------------- NetUtil: ' + msg);
     }
   }
 
   var util = {};
 
-  util.configureInterface = function(cfg, callback) {
-    let message = { cmd:     "ifc_configure",
-                    ifname:  cfg.ifname,
-                    ipaddr:  cfg.ipaddr,
-                    mask:    cfg.mask,
-                    gateway: cfg.gateway,
-                    dns1:    cfg.dns1,
-                    dns2:    cfg.dns2 };
-
-    controlMessage(message, function(data) {
-      callback(!data.status);
-    });
-  };
-
   util.runDhcp = function (ifname, callback) {
-    controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
-      var dhcpInfo = data.status ? null : data;
+    gNetworkService.dhcpRequest(ifname, function(success, dhcpInfo) {
       util.runIpConfig(ifname, dhcpInfo, callback);
     });
   };
 
   util.stopDhcp = function (ifname, callback) {
     // This function does exactly what dhcp_stop does. Unforunately, if we call
     // this function twice before the previous callback is returned. We may block
     // our self waiting for the callback. It slows down the wifi startup procedure.
     // Therefore, we have to roll our own version here.
     let dhcpService = DHCP_PROP + "_" + ifname;
     let suffix = (ifname.substr(0, 3) === "p2p") ? "p2p" : ifname;
     let processName = DHCP + "_" + suffix;
     stopProcess(dhcpService, processName, callback);
   };
 
-  util.enableInterface = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_enable", ifname: ifname }, function (data) {
-      callback(!data.status);
-    });
-  };
-
-  util.disableInterface = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_disable", ifname: ifname }, function (data) {
-      callback(!data.status);
-    });
-  };
-
   util.startDhcpServer = function (config, callback) {
     gNetworkService.setDhcpServer(true, config, function (error) {
       callback(!error);
     });
   };
 
   util.stopDhcpServer = function (callback) {
     gNetworkService.setDhcpServer(false, null, function (error) {
       callback(!error);
     });
   };
 
-  util.addHostRoute = function (ifname, route, callback) {
-    controlMessage({ cmd: "ifc_add_host_route", ifname: ifname, route: route }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.removeHostRoutes = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_remove_host_routes", ifname: ifname }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.setDefaultRoute = function (ifname, route, callback) {
-    controlMessage({ cmd: "ifc_set_default_route", ifname: ifname, route: route }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.getDefaultRoute = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_get_default_route", ifname: ifname }, function(data) {
-      callback(!data.route);
-    });
-  };
-
-  util.removeDefaultRoute = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_remove_default_route", ifname: ifname }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.resetConnections = function (ifname, callback) {
-    controlMessage({ cmd: "ifc_reset_connections", ifname: ifname }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.releaseDhcpLease = function (ifname, callback) {
-    controlMessage({ cmd: "dhcp_release_lease", ifname: ifname }, function(data) {
-      callback(!data.status);
-    });
-  };
-
-  util.getDhcpError = function (callback) {
-    controlMessage({ cmd: "dhcp_get_errmsg" }, function(data) {
-      callback(data.error);
-    });
-  };
-
-  util.runDhcpRenew = function (ifname, callback) {
-    controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
-      callback(data.status ? null : data);
-    });
-  };
-
   util.runIpConfig = function (name, data, callback) {
     if (!data) {
       debug("IP config failed to run");
       callback({ info: data });
       return;
     }
 
     setProperty("net." + name + ".dns1", ipToString(data.dns1),
--- a/dom/wifi/WifiP2pManager.jsm
+++ b/dom/wifi/WifiP2pManager.jsm
@@ -16,16 +16,20 @@ Cu.import("resource://gre/modules/system
 XPCOMUtils.defineLazyServiceGetter(this, "gSysMsgr",
                                    "@mozilla.org/system-message-internal;1",
                                    "nsISystemMessagesInternal");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
                                    "@mozilla.org/network/manager;1",
                                    "nsINetworkManager");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
+                                   "@mozilla.org/network/service;1",
+                                   "nsINetworkService");
+
 this.EXPORTED_SYMBOLS = ["WifiP2pManager"];
 
 const EVENT_IGNORED                      = -1;
 const EVENT_UNKNOWN                      = -2;
 
 // Events from supplicant for p2p.
 const EVENT_P2P_DEVICE_FOUND             = 0;
 const EVENT_P2P_DEVICE_LOST              = 1;
@@ -642,17 +646,17 @@ function P2pStateMachine(aP2pCommand, aN
             onFailure();
             return;
           }
 
           debug('P2P is enabled! Enabling net interface...');
 
           // Step 4: Enable p2p0 net interface. wpa_supplicant may have
           //         already done it for us.
-          aNetUtil.enableInterface(P2P_INTERFACE_NAME, function (success) {
+          gNetworkService.enableInterface(P2P_INTERFACE_NAME, function (success) {
             onSuccess();
           });
         });
       });
     },
 
     handleEvent: function(aEvent) {
       // We won't receive any event since all of them will be blocked.
@@ -1313,17 +1317,17 @@ function P2pStateMachine(aP2pCommand, aN
     enter: function() {
       _sm.pause();
       aNetUtil.stopDhcpServer(function (success) { // Stopping DHCP server is harmless.
         debug('Stop DHCP server result: ' + success);
         aP2pCommand.p2pDisable(function(success) {
           debug('P2P function disabled');
           aP2pCommand.closeSupplicantConnection(function (status) {
             debug('Supplicant connection closed');
-            aNetUtil.disableInterface(P2P_INTERFACE_NAME, function (success){
+            gNetworkService.disableInterface(P2P_INTERFACE_NAME, function (success){
               debug('Disabled interface: ' + P2P_INTERFACE_NAME);
               _onDisabled(true);
               _sm.gotoState(stateDisabled);
             });
           });
         });
       });
     },
--- a/dom/wifi/WifiProxyService.cpp
+++ b/dom/wifi/WifiProxyService.cpp
@@ -84,46 +84,20 @@ private:
   nsCString mInterface;
 };
 
 // Runnable used dispatch the Command result on the main thread.
 class WifiResultDispatcher : public nsRunnable
 {
 public:
   WifiResultDispatcher(WifiResultOptions& aResult, const nsACString& aInterface)
-    : mInterface(aInterface)
+    : mResult(aResult)
+    , mInterface(aInterface)
   {
     MOZ_ASSERT(!NS_IsMainThread());
-
-    // XXX: is there a better way to copy webidl dictionnaries?
-    // the copy constructor is private.
-#define COPY_FIELD(prop) mResult.prop = aResult.prop;
-
-    COPY_FIELD(mId)
-    COPY_FIELD(mStatus)
-    COPY_FIELD(mReply)
-    COPY_FIELD(mRoute)
-    COPY_FIELD(mError)
-    COPY_FIELD(mValue)
-    COPY_FIELD(mIpaddr_str)
-    COPY_FIELD(mGateway_str)
-    COPY_FIELD(mDns1_str)
-    COPY_FIELD(mDns2_str)
-    COPY_FIELD(mMask_str)
-    COPY_FIELD(mServer_str)
-    COPY_FIELD(mVendor_str)
-    COPY_FIELD(mLease)
-    COPY_FIELD(mMask)
-    COPY_FIELD(mIpaddr)
-    COPY_FIELD(mGateway)
-    COPY_FIELD(mDns1)
-    COPY_FIELD(mDns2)
-    COPY_FIELD(mServer)
-
-#undef COPY_FIELD
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
     gWifiProxyService->DispatchWifiResult(mResult, mInterface);
     return NS_OK;
   }
--- a/dom/wifi/WifiUtils.cpp
+++ b/dom/wifi/WifiUtils.cpp
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WifiUtils.h"
 #include <dlfcn.h>
 #include <errno.h>
 #include <cutils/properties.h>
 #include "prinit.h"
 #include "js/CharacterEncoding.h"
-#include "mozilla/dom/network/NetUtils.h"
 
 using namespace mozilla::dom;
 
 #define BUFFER_SIZE        4096
 #define COMMAND_SIZE       256
 #define PROPERTY_VALUE_MAX 80
 
 // Intentionally not trying to dlclose() this handle. That's playing
@@ -375,24 +374,27 @@ public:
     USE_DLFUNC(wifi_command)
     return wifi_command(command, buf, len);
   }
 };
 
 // Concrete class to use to access the wpa supplicant.
 WpaSupplicant::WpaSupplicant()
 {
-  if (NetUtils::SdkVersion() < 16) {
+  char propVersion[PROPERTY_VALUE_MAX];
+  property_get("ro.build.version.sdk", propVersion, "0");
+  mSdkVersion = strtol(propVersion, nullptr, 10);
+
+  if (mSdkVersion < 16) {
     mImpl = new ICSWpaSupplicantImpl();
-  } else if (NetUtils::SdkVersion() < 19) {
+  } else if (mSdkVersion < 19) {
     mImpl = new JBWpaSupplicantImpl();
   } else {
     mImpl = new KKWpaSupplicantImpl();
   }
-  mNetUtils = new NetUtils();
   mWifiHotspotUtils = new WifiHotspotUtils();
 };
 
 void WpaSupplicant::WaitForEvent(nsAString& aEvent, const nsCString& aInterface)
 {
   CHECK_HWLIB()
 
   char buffer[BUFFER_SIZE];
@@ -413,19 +415,16 @@ uint32_t WpaSupplicant::MakeMask(uint32_
   return ntohl(mask);
 }
 
 bool WpaSupplicant::ExecuteCommand(CommandOptions aOptions,
                                    WifiResultOptions& aResult,
                                    const nsCString& aInterface)
 {
   CHECK_HWLIB(false)
-  if (!mNetUtils->GetSharedLibrary()) {
-    return false;
-  }
 
   if (!mWifiHotspotUtils->GetSharedLibrary()) {
     return false;
   }
 
   // Always correlate the opaque ids.
   aResult.mId = aOptions.mId;
 
@@ -450,91 +449,16 @@ bool WpaSupplicant::ExecuteCommand(Comma
   } else if (aOptions.mCmd.EqualsLiteral("unload_driver")) {
     aResult.mStatus = mImpl->do_wifi_unload_driver();
   } else if (aOptions.mCmd.EqualsLiteral("start_supplicant")) {
     aResult.mStatus = mImpl->do_wifi_start_supplicant(GetWifiP2pSupported() ? 1 : 0);
   } else if (aOptions.mCmd.EqualsLiteral("stop_supplicant")) {
     aResult.mStatus = mImpl->do_wifi_stop_supplicant(0);
   } else if (aOptions.mCmd.EqualsLiteral("connect_to_supplicant")) {
     aResult.mStatus = mImpl->do_wifi_connect_to_supplicant(aInterface.get());
-  } else if (aOptions.mCmd.EqualsLiteral("ifc_enable")) {
-    aResult.mStatus = mNetUtils->do_ifc_enable(GET_CHAR(mIfname));
-  } else if (aOptions.mCmd.EqualsLiteral("ifc_disable")) {
-    aResult.mStatus = mNetUtils->do_ifc_disable(GET_CHAR(mIfname));
-  } else if (aOptions.mCmd.EqualsLiteral("ifc_configure")) {
-    aResult.mStatus = mNetUtils->do_ifc_configure(
-      GET_CHAR(mIfname), aOptions.mIpaddr, aOptions.mMask,
-      aOptions.mGateway, aOptions.mDns1, aOptions.mDns2
-    );
-  } else if (aOptions.mCmd.EqualsLiteral("ifc_reset_connections")) {
-    aResult.mStatus = mNetUtils->do_ifc_reset_connections(
-      GET_CHAR(mIfname), RESET_ALL_ADDRESSES
-    );
-  } else if (aOptions.mCmd.EqualsLiteral("dhcp_stop")) {
-    aResult.mStatus = mNetUtils->do_dhcp_stop(GET_CHAR(mIfname));
-  } else if (aOptions.mCmd.EqualsLiteral("dhcp_do_request")) {
-    char ipaddr[PROPERTY_VALUE_MAX];
-    char gateway[PROPERTY_VALUE_MAX];
-    uint32_t prefixLength;
-    char dns1[PROPERTY_VALUE_MAX];
-    char dns2[PROPERTY_VALUE_MAX];
-    char server[PROPERTY_VALUE_MAX];
-    uint32_t lease;
-    char vendorinfo[PROPERTY_VALUE_MAX];
-    aResult.mStatus =
-      mNetUtils->do_dhcp_do_request(GET_CHAR(mIfname),
-                                    ipaddr,
-                                    gateway,
-                                    &prefixLength,
-                                    dns1,
-                                    dns2,
-                                    server,
-                                    &lease,
-                                    vendorinfo);
-
-    if (aResult.mStatus == -1) {
-      // Early return since we failed.
-      return true;
-    }
-
-    aResult.mIpaddr_str = NS_ConvertUTF8toUTF16(ipaddr);
-    aResult.mGateway_str = NS_ConvertUTF8toUTF16(gateway);
-    aResult.mDns1_str = NS_ConvertUTF8toUTF16(dns1);
-    aResult.mDns2_str = NS_ConvertUTF8toUTF16(dns2);
-    aResult.mServer_str = NS_ConvertUTF8toUTF16(server);
-    aResult.mVendor_str = NS_ConvertUTF8toUTF16(vendorinfo);
-    aResult.mLease = lease;
-    aResult.mMask = MakeMask(prefixLength);
-
-    uint32_t inet4; // only support IPv4 for now.
-
-#define INET_PTON(var, field)                                                 \
-  PR_BEGIN_MACRO                                                              \
-    inet_pton(AF_INET, var, &inet4);                                          \
-    aResult.field = inet4;                                                    \
-  PR_END_MACRO
-
-    INET_PTON(ipaddr, mIpaddr);
-    INET_PTON(gateway, mGateway);
-
-    if (dns1[0] != '\0') {
-      INET_PTON(dns1, mDns1);
-    }
-
-    if (dns2[0] != '\0') {
-      INET_PTON(dns2, mDns2);
-    }
-
-    INET_PTON(server, mServer);
-
-    //aResult.mask_str = netHelpers.ipToString(obj.mask);
-    char inet_str[64];
-    if (inet_ntop(AF_INET, &aResult.mMask, inet_str, sizeof(inet_str))) {
-      aResult.mMask_str = NS_ConvertUTF8toUTF16(inet_str);
-    }
   } else if (aOptions.mCmd.EqualsLiteral("hostapd_command")) {
     size_t len = BUFFER_SIZE - 1;
     char buffer[BUFFER_SIZE];
     NS_ConvertUTF16toUTF8 request(aOptions.mRequest);
     aResult.mStatus = mWifiHotspotUtils->do_wifi_hostapd_command(request.get(),
                                                                  buffer,
                                                                  &len);
     nsString value;
@@ -590,17 +514,17 @@ void
 WpaSupplicant::CheckBuffer(char* buffer, int32_t length,
                            nsAString& aEvent)
 {
   if (length <= 0 || length >= (BUFFER_SIZE - 1)) {
     NS_WARNING("WpaSupplicant::CheckBuffer: Invalid buffer length");
     return;
   }
 
-  if (NetUtils::SdkVersion() < 18) {
+  if (mSdkVersion < 18) {
     buffer[length] = 0;
     LossyConvertUTF8toUTF16(buffer, length, aEvent);
     return;
   }
 
   // After Android JB4.3, the SSIDs have been converted into printable form.
   // In most of cases, SSIDs do not use unprintable characters, but IEEE 802.11
   // standard does not limit the used character set, so anything could be used
--- a/dom/wifi/WifiUtils.h
+++ b/dom/wifi/WifiUtils.h
@@ -8,81 +8,44 @@
  */
 
 #ifndef WifiUtils_h
 #define WifiUtils_h
 
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "mozilla/dom/WifiOptionsBinding.h"
-#include "mozilla/dom/network/NetUtils.h"
 #include "WifiHotspotUtils.h"
 
 // Needed to add a copy constructor to WifiCommandOptions.
 struct CommandOptions
 {
 public:
-  CommandOptions(const CommandOptions& aOther) {
-    mId = aOther.mId;
-    mCmd = aOther.mCmd;
-    mRequest = aOther.mRequest;
-    mIfname = aOther.mIfname;
-    mRoute = aOther.mRoute;
-    mIpaddr = aOther.mIpaddr;
-    mMask = aOther.mMask;
-    mGateway = aOther.mGateway;
-    mDns1 = aOther.mDns1;
-    mDns2 = aOther.mDns2;
-    mKey = aOther.mKey;
-    mValue = aOther.mValue;
-    mDefaultValue = aOther.mDefaultValue;
-  }
-
   CommandOptions(const mozilla::dom::WifiCommandOptions& aOther) {
 
 #define COPY_OPT_FIELD(prop, defaultValue)            \
     if (aOther.prop.WasPassed()) {                    \
       prop = aOther.prop.Value();                     \
     } else {                                          \
       prop = defaultValue;                            \
     }
 
 #define COPY_FIELD(prop) prop = aOther.prop;
     COPY_FIELD(mId)
     COPY_FIELD(mCmd)
     COPY_OPT_FIELD(mRequest, EmptyString())
-    COPY_OPT_FIELD(mIfname, EmptyString())
-    COPY_OPT_FIELD(mIpaddr, 0)
-    COPY_OPT_FIELD(mRoute, 0)
-    COPY_OPT_FIELD(mMask, 0)
-    COPY_OPT_FIELD(mGateway, 0)
-    COPY_OPT_FIELD(mDns1, 0)
-    COPY_OPT_FIELD(mDns2, 0)
-    COPY_OPT_FIELD(mKey, EmptyString())
-    COPY_OPT_FIELD(mValue, EmptyString())
-    COPY_OPT_FIELD(mDefaultValue, EmptyString())
 
 #undef COPY_OPT_FIELD
 #undef COPY_FIELD
   }
 
   // All the fields, not Optional<> anymore to get copy constructors.
   nsString mCmd;
-  nsString mDefaultValue;
-  int32_t mDns1;
-  int32_t mDns2;
-  int32_t mGateway;
   int32_t mId;
-  nsString mIfname;
-  int32_t mIpaddr;
-  nsString mKey;
-  int32_t mMask;
   nsString mRequest;
-  int32_t mRoute;
-  nsString mValue;
 };
 
 // Abstract class that exposes libhardware_legacy functions we need for
 // wifi management.
 // We use the ICS signatures here since they are likely more future-proof.
 class WpaSupplicantImpl
 {
 public:
@@ -125,17 +88,18 @@ public:
   // conversion
   void WaitForEvent(nsAString& aEvent, const nsCString& aInterface);
   bool ExecuteCommand(CommandOptions aOptions,
                       mozilla::dom::WifiResultOptions& result,
                       const nsCString& aInterface);
 
 private:
   nsAutoPtr<WpaSupplicantImpl> mImpl;
-  nsAutoPtr<NetUtils> mNetUtils;
   nsAutoPtr<WifiHotspotUtils> mWifiHotspotUtils;
 
+  uint32_t mSdkVersion;
+
 protected:
   void CheckBuffer(char* buffer, int32_t length, nsAString& aEvent);
   uint32_t MakeMask(uint32_t len);
 };
 
 #endif // WifiUtils_h
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -410,18 +410,18 @@ var WifiManager = (function() {
 
       // If the ssid of current connection is the same as configured ssid
       // It means we need update current connection to use static IP address.
       if (setNetworkKey == curNetworkKey) {
         // Use configureInterface directly doesn't work, the network iterface
         // and routing table is changed but still cannot connect to network
         // so the workaround here is disable interface the enable again to
         // trigger network reconnect with static ip.
-        netUtil.disableInterface(manager.ifname, function (ok) {
-          netUtil.enableInterface(manager.ifname, function (ok) {
+        gNetworkService.disableInterface(manager.ifname, function (ok) {
+          gNetworkService.enableInterface(manager.ifname, function (ok) {
           });
         });
       }
     });
   }
 
   var dhcpInfo = null;
 
@@ -437,22 +437,22 @@ var WifiManager = (function() {
     staticIpInfo = staticIpConfig[key];
 
     // Stop dhcpd when use static IP
     if (dhcpInfo != null) {
       netUtil.stopDhcp(manager.ifname, function() {});
     }
 
     // Set ip, mask length, gateway, dns to network interface
-    netUtil.configureInterface( { ifname: ifname,
-                                  ipaddr: staticIpInfo.ipaddr,
-                                  mask: staticIpInfo.maskLength,
-                                  gateway: staticIpInfo.gateway,
-                                  dns1: staticIpInfo.dns1,
-                                  dns2: staticIpInfo.dns2 }, function (data) {
+    gNetworkService.configureInterface( { ifname: ifname,
+                                          ipaddr: staticIpInfo.ipaddr,
+                                          mask: staticIpInfo.maskLength,
+                                          gateway: staticIpInfo.gateway,
+                                          dns1: staticIpInfo.dns1,
+                                          dns2: staticIpInfo.dns2 }, function (data) {
       netUtil.runIpConfig(ifname, staticIpInfo, function(data) {
         dhcpInfo = data.info;
         notify("networkconnected", data);
       });
     });
   }
 
   var suppressEvents = false;
@@ -582,27 +582,27 @@ var WifiManager = (function() {
 
     retryTimer = null;
     connectTries = 0;
     notify("supplicantlost", { success: false });
   }
 
   manager.connectionDropped = function(callback) {
     // Reset network interface when connection drop
-    netUtil.configureInterface( { ifname: manager.ifname,
-                                  ipaddr: 0,
-                                  mask: 0,
-                                  gateway: 0,
-                                  dns1: 0,
-                                  dns2: 0 }, function (data) {
+    gNetworkService.configureInterface( { ifname: manager.ifname,
+                                          ipaddr: 0,
+                                          mask: 0,
+                                          gateway: 0,
+                                          dns1: 0,
+                                          dns2: 0 }, function (data) {
     });
 
     // If we got disconnected, kill the DHCP client in preparation for
     // reconnection.
-    netUtil.resetConnections(manager.ifname, function() {
+    gNetworkService.resetConnections(manager.ifname, function() {
       netUtil.stopDhcp(manager.ifname, function() {
         callback();
       });
     });
   }
 
   manager.start = function() {
     debug("detected SDK version " + sdkVersion);
@@ -884,17 +884,17 @@ var WifiManager = (function() {
     function tryStopSupplicant () {
       let status = libcutils.property_get(SUPP_PROP);
       if (status !== "running") {
         callback();
         return;
       }
       suppressEvents = true;
       wifiCommand.killSupplicant(function() {
-        netUtil.disableInterface(manager.ifname, function (ok) {
+        gNetworkService.disableInterface(manager.ifname, function (ok) {
           suppressEvents = false;
           callback();
         });
       });
     }
   }
 
   // Initial state.
@@ -991,17 +991,17 @@ var WifiManager = (function() {
                   unloadDriver(WIFI_FIRMWARE_STATION, function() {
                     callback(status);
                   });
                   manager.state = "UNINITIALIZED";
                   return;
                 }
 
                 manager.supplicantStarted = true;
-                netUtil.enableInterface(manager.ifname, function (ok) {
+                gNetworkService.enableInterface(manager.ifname, function (ok) {
                   callback(ok ? 0 : -1);
                 });
               });
             }
 
             function doStartSupplicant() {
               cancelWaitForDriverReadyTimer();
 
@@ -1035,17 +1035,17 @@ var WifiManager = (function() {
       // supplicant gracefully, then we need to continue telling it to die
       // until it does.
       let doDisableWifi = function() {
         manager.stopSupplicantCallback = (function () {
           wifiCommand.stopSupplicant(function (status) {
             wifiCommand.closeSupplicantConnection(function() {
               manager.connectToSupplicant = false;
               manager.state = "UNINITIALIZED";
-              netUtil.disableInterface(manager.ifname, function (ok) {
+              gNetworkService.disableInterface(manager.ifname, function (ok) {
                 unloadDriver(WIFI_FIRMWARE_STATION, callback);
               });
             });
           });
         }).bind(this);
 
         let terminateEventCallback = (function() {
           handleEvent("CTRL-EVENT-TERMINATING");
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2200,17 +2200,17 @@ RuntimeService::CancelWorkersForWindow(n
     if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(aWindow))) {
       return;
     }
     JSContext* cx = jsapi.cx();
 
     for (uint32_t index = 0; index < workers.Length(); index++) {
       WorkerPrivate*& worker = workers[index];
 
-      if (worker->IsSharedWorker()) {
+      if (worker->IsSharedWorker() || worker->IsServiceWorker()) {
         worker->CloseSharedWorkersForWindow(aWindow);
       } else if (!worker->Cancel(cx)) {
         JS_ReportPendingException(cx);
       }
     }
   }
 }
 
--- a/dom/xslt/xslt/txStylesheet.cpp
+++ b/dom/xslt/xslt/txStylesheet.cpp
@@ -123,17 +123,17 @@ txStylesheet::findTemplate(const txXPath
     if (aImportedBy) {
         ImportFrame* curr = static_cast<ImportFrame*>(frameIter.next());
         while (curr != aImportedBy) {
                curr = static_cast<ImportFrame*>(frameIter.next());
         }
         endFrame = aImportedBy->mFirstNotImported;
     }
 
-#ifdef PR_LOGGING
+#if defined(PR_LOGGING) && defined(TX_TO_STRING)
     txPattern* match = 0;
 #endif
 
     ImportFrame* frame;
     while (!matchTemplate &&
            (frame = static_cast<ImportFrame*>(frameIter.next())) &&
            frame != endFrame) {
 
@@ -144,17 +144,17 @@ txStylesheet::findTemplate(const txXPath
         if (templates) {
             // Find template with highest priority
             uint32_t i, len = templates->Length();
             for (i = 0; i < len && !matchTemplate; ++i) {
                 MatchableTemplate& templ = (*templates)[i];
                 if (templ.mMatch->matches(aNode, aContext)) {
                     matchTemplate = templ.mFirstInstruction;
                     *aImportFrame = frame;
-#ifdef PR_LOGGING
+#if defined(PR_LOGGING) && defined(TX_TO_STRING)
                     match = templ.mMatch;
 #endif
                 }
             }
         }
     }
 
 #ifdef PR_LOGGING
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -59,18 +59,17 @@ MOZ_END_ENUM_CLASS(LayersBackend)
 
 MOZ_BEGIN_ENUM_CLASS(BufferMode, int8_t)
   BUFFER_NONE,
   BUFFERED
 MOZ_END_ENUM_CLASS(BufferMode)
 
 MOZ_BEGIN_ENUM_CLASS(DrawRegionClip, int8_t)
   DRAW,
-  DRAW_SNAPPED,
-  CLIP_NONE
+  NONE
 MOZ_END_ENUM_CLASS(DrawRegionClip)
 
 MOZ_BEGIN_ENUM_CLASS(SurfaceMode, int8_t)
   SURFACE_NONE = 0,
   SURFACE_OPAQUE,
   SURFACE_SINGLE_CHANNEL_ALPHA,
   SURFACE_COMPONENT_ALPHA
 MOZ_END_ENUM_CLASS(SurfaceMode)
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -690,17 +690,17 @@ RotatedContentBuffer::BeginPaint(Painted
     mBufferRotation = nsIntPoint(0,0);
   }
   NS_ASSERTION(canHaveRotation || mBufferRotation == nsIntPoint(0,0),
                "Rotation disabled, but we have nonzero rotation?");
 
   nsIntRegion invalidate;
   invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
   result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
-  result.mClip = DrawRegionClip::DRAW_SNAPPED;
+  result.mClip = DrawRegionClip::DRAW;
   result.mMode = mode;
 
   return result;
 }
 
 DrawTarget*
 RotatedContentBuffer::BorrowDrawTargetForPainting(PaintState& aPaintState,
                                                   DrawIterator* aIter /* = nullptr */)
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -224,17 +224,17 @@ public:
    * depend on the buffer type.  mDidSelfCopy is true if we kept our buffer
    * but used MovePixels() to shift its content.
    */
   struct PaintState {
     PaintState()
       : mRegionToDraw()
       , mRegionToInvalidate()
       , mMode(SurfaceMode::SURFACE_NONE)
-      , mClip(DrawRegionClip::CLIP_NONE)
+      , mClip(DrawRegionClip::NONE)
       , mContentType(gfxContentType::SENTINEL)
       , mDidSelfCopy(false)
     {}
 
     nsIntRegion mRegionToDraw;
     nsIntRegion mRegionToInvalidate;
     SurfaceMode mMode;
     DrawRegionClip mClip;
--- a/gfx/layers/basic/BasicPaintedLayer.cpp
+++ b/gfx/layers/basic/BasicPaintedLayer.cpp
@@ -86,17 +86,17 @@ BasicPaintedLayer::PaintThebes(gfxContex
                                             &needsClipToVisibleRegion);
         if (effectiveOperator != CompositionOp::OP_OVER) {
           needsClipToVisibleRegion = true;
         }
       } else {
         groupContext = aContext;
       }
       SetAntialiasingFlags(this, groupContext->GetDrawTarget());
-      aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData);
+      aCallback(this, groupContext, toDraw, DrawRegionClip::NONE, nsIntRegion(), aCallbackData);
       if (needsGroup) {
         aContext->PopGroupToSource();
         if (needsClipToVisibleRegion) {
           gfxUtils::ClipToRegion(aContext, toDraw);
         }
         AutoSetOperator setOptimizedOperator(aContext, ThebesOp(effectiveOperator));
         PaintWithMask(aContext, opacity, aMaskLayer);
       }
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -438,30 +438,47 @@ ClientLayerManager::RunOverfillCallback(
 void
 ClientLayerManager::MakeSnapshotIfRequired()
 {
   if (!mShadowTarget) {
     return;
   }
   if (mWidget) {
     if (CompositorChild* remoteRenderer = GetRemoteRenderer()) {
+      // The compositor doesn't draw to a different sized surface
+      // when there's a rotation. Instead we rotate the result
+      // when drawing into dt
+      nsIntRect outerBounds;
+      mWidget->GetBounds(outerBounds);
+
       nsIntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
+      if (mTargetRotation) {
+        bounds = RotateRect(bounds, outerBounds, mTargetRotation);
+      }
+
       SurfaceDescriptor inSnapshot;
       if (!bounds.IsEmpty() &&
           mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(),
                                              gfxContentType::COLOR_ALPHA,
                                              &inSnapshot) &&
           remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
         RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(inSnapshot);
         DrawTarget* dt = mShadowTarget->GetDrawTarget();
+
         Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height);
         Rect srcRect(0, 0, bounds.width, bounds.height);
+
+        gfx::Matrix rotate = ComputeTransformForUnRotation(outerBounds, mTargetRotation);
+
+        gfx::Matrix oldMatrix = dt->GetTransform();
+        dt->SetTransform(oldMatrix * rotate);
         dt->DrawSurface(surf, dstRect, srcRect,
                         DrawSurfaceOptions(),
                         DrawOptions(1.0f, CompositionOp::OP_OVER));
+        dt->SetTransform(oldMatrix);
       }
       mForwarder->DestroySharedSurface(&inSnapshot);
     }
   }
   mShadowTarget = nullptr;
 }
 
 void
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -929,17 +929,17 @@ ClientTiledLayerBuffer::PaintThebes(cons
     if (PR_IntervalNow() - start > 3) {
       printf_stderr("Slow alloc %i\n", PR_IntervalNow() - start);
     }
     start = PR_IntervalNow();
 #endif
     PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw",
       js::ProfileEntry::Category::GRAPHICS);
 
-    mCallback(mPaintedLayer, ctxt, aPaintRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), mCallbackData);
+    mCallback(mPaintedLayer, ctxt, aPaintRegion, DrawRegionClip::NONE, nsIntRegion(), mCallbackData);
   }
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (PR_IntervalNow() - start > 30) {
     const nsIntRect bounds = aPaintRegion.GetBounds();
     printf_stderr("Time to draw %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
     if (aPaintRegion.IsComplex()) {
       printf_stderr("Complex region\n");
@@ -1299,17 +1299,17 @@ ClientTiledLayerBuffer::ValidateTile(Til
     ctxt->NewPath();
     ctxt->Clip(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
     ctxt->SetMatrix(
       ctxt->CurrentMatrix().Translate(-unscaledTileOrigin.x,
                                       -unscaledTileOrigin.y).
                             Scale(mResolution, mResolution));
     mCallback(mPaintedLayer, ctxt,
               tileRegion.GetBounds(),
-              DrawRegionClip::CLIP_NONE,
+              DrawRegionClip::NONE,
               nsIntRegion(), mCallbackData);
 
   }
 
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   DrawDebugOverlay(drawTarget, aTileOrigin.x * mResolution,
                    aTileOrigin.y * mResolution, GetTileLength(), GetTileLength());
 #endif
--- a/gfx/layers/d3d9/PaintedLayerD3D9.cpp
+++ b/gfx/layers/d3d9/PaintedLayerD3D9.cpp
@@ -532,17 +532,17 @@ PaintedLayerD3D9::DrawRegion(nsIntRegion
     gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface,
                                                            IntSize(destinationSurface->GetSize().width,
                                                                    destinationSurface->GetSize().height));
 
   nsRefPtr<gfxContext> context = new gfxContext(dt);
 
   context->SetMatrix(context->CurrentMatrix().Translate(-bounds.x, -bounds.y));
   LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
-  cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData);
+  cbInfo.Callback(this, context, aRegion, DrawRegionClip::NONE, nsIntRegion(), cbInfo.CallbackData);
 
   for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) {
     NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE,
                  "Transparent surfaces should not be used for readback");
     const ReadbackProcessor::Update& update = aReadbackUpdates[i];
     nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset();
     nsRefPtr<gfxContext> ctx =
         update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset,
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -999,22 +999,25 @@ ProcessPriorityToString(ProcessPriority 
     break;
   }
 
   MOZ_ASSERT(false);
   return "???";
 }
 
 static StaticAutoPtr<ObserverList<FMRadioOperationInformation> > sFMRadioObservers;
+static StaticAutoPtr<ObserverList<FMRadioRDSGroup> > sFMRadioRDSObservers;
 
 static void
 InitializeFMRadioObserver()
 {
   if (!sFMRadioObservers) {
     sFMRadioObservers = new ObserverList<FMRadioOperationInformation>;
+    sFMRadioRDSObservers = new ObserverList<FMRadioRDSGroup>;
+    ClearOnShutdown(&sFMRadioRDSObservers);
     ClearOnShutdown(&sFMRadioObservers);
   }
 }
 
 void
 RegisterFMRadioObserver(FMRadioObserver* aFMRadioObserver) {
   AssertMainThread();
   InitializeFMRadioObserver();
@@ -1030,16 +1033,37 @@ UnregisterFMRadioObserver(FMRadioObserve
 
 void
 NotifyFMRadioStatus(const FMRadioOperationInformation& aFMRadioState) {
   InitializeFMRadioObserver();
   sFMRadioObservers->Broadcast(aFMRadioState);
 }
 
 void
+RegisterFMRadioRDSObserver(FMRadioRDSObserver* aFMRadioRDSObserver) {
+  AssertMainThread();
+  InitializeFMRadioObserver();
+  sFMRadioRDSObservers->AddObserver(aFMRadioRDSObserver);
+}
+
+void
+UnregisterFMRadioRDSObserver(FMRadioRDSObserver* aFMRadioRDSObserver) {
+  AssertMainThread();
+  InitializeFMRadioObserver();
+  sFMRadioRDSObservers->RemoveObserver(aFMRadioRDSObserver);
+}
+
+
+void
+NotifyFMRadioRDSGroup(const FMRadioRDSGroup& aRDSGroup) {
+  InitializeFMRadioObserver();
+  sFMRadioRDSObservers->Broadcast(aRDSGroup);
+}
+
+void
 EnableFMRadio(const FMRadioSettings& aInfo) {
   AssertMainThread();
   PROXY_IF_SANDBOXED(EnableFMRadio(aInfo));
 }
 
 void
 DisableFMRadio() {
   AssertMainThread();
@@ -1083,16 +1107,28 @@ GetFMRadioSignalStrength() {
 }
 
 void
 CancelFMRadioSeek() {
   AssertMainThread();
   PROXY_IF_SANDBOXED(CancelFMRadioSeek());
 }
 
+void
+EnableRDS(uint32_t aMask) {
+  AssertMainThread();
+  PROXY_IF_SANDBOXED(EnableRDS(aMask));
+}
+
+void
+DisableRDS() {
+  AssertMainThread();
+  PROXY_IF_SANDBOXED(DisableRDS());
+}
+
 FMRadioSettings
 GetFMBandSettings(FMRadioCountry aCountry) {
   FMRadioSettings settings;
 
   switch (aCountry) {
     case FM_RADIO_COUNTRY_US:
     case FM_RADIO_COUNTRY_EU:
       settings.upperLimit() = 108000;
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -499,22 +499,38 @@ void SetCurrentThreadPriority(hal::Threa
 void RegisterFMRadioObserver(hal::FMRadioObserver* aRadioObserver);
 
 /**
  * Unregister the observer for the FM radio.
  */
 void UnregisterFMRadioObserver(hal::FMRadioObserver* aRadioObserver);
 
 /**
+ * Register an observer for the FM radio.
+ */
+void RegisterFMRadioRDSObserver(hal::FMRadioRDSObserver* aRDSObserver);
+
+/**
+ * Unregister the observer for the FM radio.
+ */
+void UnregisterFMRadioRDSObserver(hal::FMRadioRDSObserver* aRDSObserver);
+
+/**
  * Notify observers that a call to EnableFMRadio, DisableFMRadio, or FMRadioSeek
  * has completed, and indicate what the call returned.
  */
 void NotifyFMRadioStatus(const hal::FMRadioOperationInformation& aRadioState);
 
 /**
+ * Notify observers of new RDS data
+ * This can be called on any thread.
+ */
+void NotifyFMRadioRDSGroup(const hal::FMRadioRDSGroup& aRDSGroup);
+
+/**
  * Enable the FM radio and configure it according to the settings in aInfo.
  */
 void EnableFMRadio(const hal::FMRadioSettings& aInfo);
 
 /**
  * Disable the FM radio.
  */
 void DisableFMRadio();
@@ -561,16 +577,26 @@ uint32_t GetFMRadioSignalStrength();
 void CancelFMRadioSeek();
 
 /**
  * Get FM radio band settings by country.
  */
 hal::FMRadioSettings GetFMBandSettings(hal::FMRadioCountry aCountry);
 
 /**
+ * Enable RDS data reception
+ */
+void EnableRDS(uint32_t aMask);
+
+/**
+ * Disable RDS data reception
+ */
+void DisableRDS();
+
+/**
  * Start a watchdog to compulsively shutdown the system if it hangs.
  * @param aMode Specify how to shutdown the system.
  * @param aTimeoutSecs Specify the delayed seconds to shutdown the system.
  *
  * This API is currently only allowed to be used from the main process.
  */
 void StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs);
 
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -220,17 +220,19 @@ enum FMRadioCountry {
   FM_RADIO_COUNTRY_CH,  //Switzerland
   FM_RADIO_COUNTRY_TW,  //Taiwan
   FM_RADIO_COUNTRY_TR,  //Turkey
   FM_RADIO_COUNTRY_UA,  //Ukraine
   FM_RADIO_COUNTRY_USER_DEFINED,
   NUM_FM_RADIO_COUNTRY
 };
 
+class FMRadioRDSGroup;
 typedef Observer<FMRadioOperationInformation> FMRadioObserver;
+typedef Observer<FMRadioRDSGroup> FMRadioRDSObserver;
 } // namespace hal
 } // namespace mozilla
 
 namespace IPC {
 
 /**
  * Light type serializer.
  */
--- a/hal/fallback/FallbackFMRadio.cpp
+++ b/hal/fallback/FallbackFMRadio.cpp
@@ -52,10 +52,18 @@ GetFMRadioSignalStrength()
 {
   return 0;
 }
 
 void
 CancelFMRadioSeek()
 {}
 
+void
+EnableRDS(uint32_t aMask)
+{}
+
+void
+DisableRDS()
+{}
+
 } // hal_impl
 } // namespace mozilla
--- a/hal/gonk/GonkFMRadio.cpp
+++ b/hal/gonk/GonkFMRadio.cpp
@@ -20,16 +20,17 @@
 #include "mozilla/FileUtils.h"
 
 #include <cutils/properties.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/videodev2.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/epoll.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
 
 /* Bionic might not have the newer version of the v4l2 headers that
  * define these controls, so we define them here if they're not found.
  */
 #ifndef V4L2_CTRL_CLASS_FM_RX
@@ -37,27 +38,47 @@
 #define V4L2_CID_FM_RX_CLASS_BASE (V4L2_CTRL_CLASS_FM_RX | 0x900)
 #define V4L2_CID_TUNE_DEEMPHASIS  (V4L2_CID_FM_RX_CLASS_BASE + 1)
 #define V4L2_DEEMPHASIS_DISABLED  0
 #define V4L2_DEEMPHASIS_50_uS     1
 #define V4L2_DEEMPHASIS_75_uS     2
 #define V4L2_CID_RDS_RECEPTION    (V4L2_CID_FM_RX_CLASS_BASE + 2)
 #endif
 
+#ifndef V4L2_RDS_BLOCK_MSK
+struct v4l2_rds_data {
+  uint8_t lsb;
+  uint8_t msb;
+  uint8_t block;
+} __attribute__ ((packed));
+#define V4L2_RDS_BLOCK_MSK 0x7
+#define V4L2_RDS_BLOCK_A 0
+#define V4L2_RDS_BLOCK_B 1
+#define V4L2_RDS_BLOCK_C 2
+#define V4L2_RDS_BLOCK_D 3
+#define V4L2_RDS_BLOCK_C_ALT 4
+#define V4L2_RDS_BLOCK_INVALID 7
+#define V4L2_RDS_BLOCK_CORRECTED 0x40
+#define V4L2_RDS_BLOCK_ERROR 0x80
+#endif
+
 namespace mozilla {
 namespace hal_impl {
 
 uint32_t GetFMRadioFrequency();
 
 static int sRadioFD;
 static bool sRadioEnabled;
+static bool sRDSEnabled;
 static pthread_t sRadioThread;
+static pthread_t sRDSThread;
 static hal::FMRadioSettings sRadioSettings;
 static int sMsmFMVersion;
 static bool sMsmFMMode;
+static bool sRDSSupported;
 
 static int
 setControl(uint32_t id, int32_t value)
 {
   struct v4l2_control control;
   control.id = id;
   control.value = value;
   return ioctl(sRadioFD, VIDIOC_S_CTRL, &control);
@@ -306,16 +327,18 @@ EnableFMRadio(const hal::FMRadioSettings
     return;
   }
 
   if (!(cap.capabilities & V4L2_CAP_TUNER)) {
     HAL_LOG("/dev/radio0 doesn't support the tuner interface");
     hal::NotifyFMRadioStatus(info);
     return;
   }
+
+  sRDSSupported = cap.capabilities & V4L2_CAP_RDS_CAPTURE;
   sRadioSettings = aInfo;
 
   if (sMsmFMMode) {
     sRadioFD = fd.forget();
     sMsmFMVersion = cap.version;
     if (pthread_create(&sRadioThread, nullptr, runMsmFMRadio, nullptr)) {
       HAL_LOG("Couldn't create radio thread");
       hal::NotifyFMRadioStatus(info);
@@ -361,16 +384,19 @@ EnableFMRadio(const hal::FMRadioSettings
 }
 
 void
 DisableFMRadio()
 {
   if (!sRadioEnabled)
     return;
 
+  if (sRDSEnabled)
+    hal::DisableRDS();
+
   sRadioEnabled = false;
 
   if (sMsmFMMode) {
     int rc = setControl(V4L2_CID_PRIVATE_TAVARUA_STATE, FM_OFF);
     if (rc < 0) {
       HAL_LOG("Unable to turn off radio");
     }
 
@@ -489,10 +515,191 @@ GetFMRadioSignalStrength()
 
   return tuner.signal;
 }
 
 void
 CancelFMRadioSeek()
 {}
 
+/* Runs on the rds thread */
+static void*
+readRDSDataThread(void* data)
+{
+  v4l2_rds_data rdsblocks[16];
+  uint16_t blocks[4];
+
+  ScopedClose pipefd((int)data);
+
+  ScopedClose epollfd(epoll_create(2));
+  if (epollfd < 0) {
+    HAL_LOG("Could not create epoll FD for RDS thread (%d)", errno);
+    return nullptr;
+  }
+
+  epoll_event event = {
+    EPOLLIN,
+    { 0 }
+  };
+
+  event.data.fd = pipefd;
+  if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd, &event) < 0) {
+    HAL_LOG("Could not set up epoll FD for RDS thread (%d)", errno);
+    return nullptr;
+  }
+
+  event.data.fd = sRadioFD;
+  if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sRadioFD, &event) < 0) {
+    HAL_LOG("Could not set up epoll FD for RDS thread (%d)", errno);
+    return nullptr;
+  }
+
+  epoll_event events[2] = {{ 0 }};
+  int event_count;
+  uint32_t block_bitmap = 0;
+  while ((event_count = epoll_wait(epollfd, events, 2, -1)) > 0 ||
+         errno == EINTR) {
+    bool RDSDataAvailable = false;
+    for (int i = 0; i < event_count; i++) {
+      if (events[i].data.fd == pipefd) {
+        if (!sRDSEnabled)
+          return nullptr;
+        char tmp[32];
+        TEMP_FAILURE_RETRY(read(pipefd, tmp, sizeof(tmp)));
+      } else if (events[i].data.fd == sRadioFD) {
+        RDSDataAvailable = true;
+      }
+    }
+
+    if (!RDSDataAvailable)
+      continue;
+
+    ssize_t len =
+      TEMP_FAILURE_RETRY(read(sRadioFD, rdsblocks, sizeof(rdsblocks)));
+    if (len < 0) {
+      HAL_LOG("Unexpected error while reading RDS data %d", errno);
+      return nullptr;
+    }
+
+    int blockcount = len / sizeof(rdsblocks[0]);
+    int lastblock = -1;
+    for (int i = 0; i < blockcount; i++) {
+      if ((rdsblocks[i].block & V4L2_RDS_BLOCK_MSK) == V4L2_RDS_BLOCK_INVALID ||
+           rdsblocks[i].block & V4L2_RDS_BLOCK_ERROR) {
+        block_bitmap |= 1 << V4L2_RDS_BLOCK_INVALID;
+        continue;
+      }
+
+      int blocknum = rdsblocks[i].block & V4L2_RDS_BLOCK_MSK;
+      // In some cases, the full set of bits in an RDS group isn't
+      // needed, in which case version B RDS groups can be sent.
+      // Version B groups replace block C with block C' (V4L2_RDS_BLOCK_C_ALT).
+      // Block C' always stores the PI code, so receivers can find the PI
+      // code more quickly/reliably.
+      // However, we only process whole RDS groups, so it doesn't matter here.
+      if (blocknum == V4L2_RDS_BLOCK_C_ALT)
+        blocknum = V4L2_RDS_BLOCK_C;
+      if (blocknum > V4L2_RDS_BLOCK_D) {
+        HAL_LOG("Unexpected RDS block number %d. This is a driver bug.",
+                blocknum);
+        continue;
+      }
+
+      if (blocknum == V4L2_RDS_BLOCK_A)
+        block_bitmap = 0;
+
+      // Skip the group if we skipped a block.
+      // This stops us from processing blocks sent out of order.
+      if (block_bitmap != ((1 << blocknum) - 1)) {
+        block_bitmap |= 1 << V4L2_RDS_BLOCK_INVALID;
+        continue;
+      }
+
+      block_bitmap |= 1 << blocknum;
+
+      lastblock = blocknum;
+      blocks[blocknum] = (rdsblocks[i].msb << 8) | rdsblocks[i].lsb;
+
+      // Make sure we have all 4 blocks and that they're valid
+      if (block_bitmap != 0x0F)
+        continue;
+
+      hal::FMRadioRDSGroup group;
+      group.blockA() = blocks[V4L2_RDS_BLOCK_A];
+      group.blockB() = blocks[V4L2_RDS_BLOCK_B];
+      group.blockC() = blocks[V4L2_RDS_BLOCK_C];
+      group.blockD() = blocks[V4L2_RDS_BLOCK_D];
+      NotifyFMRadioRDSGroup(group);
+    }
+  }
+
+  return nullptr;
+}
+
+static int sRDSPipeFD;
+
+void
+EnableRDS(uint32_t aMask)
+{
+  if (!sRadioEnabled || !sRDSSupported)
+    return;
+
+  if (sMsmFMMode)
+    setControl(V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK, aMask);
+
+  if (sRDSEnabled)
+    return;
+
+  int pipefd[2];
+  int rc = pipe2(pipefd, O_NONBLOCK);
+  if (rc < 0) {
+    HAL_LOG("Could not create RDS thread signaling pipes (%d)", rc);
+    return;
+  }
+
+  ScopedClose writefd(pipefd[1]);
+  ScopedClose readfd(pipefd[0]);
+
+  rc = setControl(V4L2_CID_RDS_RECEPTION, true);
+  if (rc < 0) {
+    HAL_LOG("Could not enable RDS reception (%d)", rc);
+    return;
+  }
+
+  sRDSPipeFD = writefd;
+
+  sRDSEnabled = true;
+
+  rc = pthread_create(&sRDSThread, nullptr,
+                      readRDSDataThread, (void*)pipefd[0]);
+  if (rc) {
+    HAL_LOG("Could not start RDS reception thread (%d)", rc);
+    setControl(V4L2_CID_RDS_RECEPTION, false);
+    sRDSEnabled = false;
+    return;
+  }
+
+  readfd.forget();
+  writefd.forget();
+}
+
+void
+DisableRDS()
+{
+  if (!sRadioEnabled || !sRDSEnabled)
+    return;
+
+  int rc = setControl(V4L2_CID_RDS_RECEPTION, false);
+  if (rc < 0) {
+    HAL_LOG("Could not disable RDS reception (%d)", rc);
+  }
+
+  sRDSEnabled = false;
+
+  write(sRDSPipeFD, "x", 1);
+
+  pthread_join(sRDSThread, nullptr);
+
+  close(sRDSPipeFD);
+}
+
 } // hal_impl
 } // namespace mozilla
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -64,16 +64,23 @@ struct ScreenConfiguration {
 };
 
 struct FMRadioOperationInformation {
   FMRadioOperation operation;
   FMRadioOperationStatus status;
   uint32_t frequency;
 };
 
+struct FMRadioRDSGroup {
+  uint16_t blockA;
+  uint16_t blockB;
+  uint16_t blockC;
+  uint16_t blockD;
+};
+
 struct FMRadioSettings {
   FMRadioCountry country;
   uint32_t upperLimit;
   uint32_t lowerLimit;
   uint32_t spaceType;
   uint32_t preEmphasis;
 };
 
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -422,16 +422,28 @@ GetFMRadioSignalStrength()
 
 void
 CancelFMRadioSeek()
 {
   NS_RUNTIMEABORT("FM radio cannot be called from sandboxed contexts.");
 }
 
 void
+EnableRDS(uint32_t aMask)
+{
+  NS_RUNTIMEABORT("FM radio cannot be called from sandboxed contexts.");
+}
+
+void
+DisableRDS()
+{
+  NS_RUNTIMEABORT("FM radio cannot be called from sandboxed contexts.");
+}
+
+void
 FactoryReset(FactoryResetReason& aReason)
 {
   if (aReason == FactoryResetReason::Normal) {
     Hal()->SendFactoryReset(NS_LITERAL_STRING("normal"));
   } else if (aReason == FactoryResetReason::Wipe) {
     Hal()->SendFactoryReset(NS_LITERAL_STRING("wipe"));
   }
 }
--- a/ipc/glue/MessageLink.cpp
+++ b/ipc/glue/MessageLink.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/ipc/MessageLink.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/ContentParent.h"
 #endif
 
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "nsDebug.h"
 #include "nsISupportsImpl.h"
 #include "nsXULAppAPI.h"
 
@@ -65,16 +66,19 @@ MessageLink::~MessageLink()
 #endif
 }
 
 ProcessLink::ProcessLink(MessageChannel *aChan)
   : MessageLink(aChan)
   , mTransport(nullptr)
   , mIOLoop(nullptr)
   , mExistingListener(nullptr)
+#ifdef MOZ_NUWA_PROCESS
+  , mIsToNuwaProcess(false)
+#endif
 {
 }
 
 ProcessLink::~ProcessLink()
 {
 #ifdef DEBUG
     mTransport = nullptr;
     mIOLoop = nullptr;
@@ -163,16 +167,36 @@ ProcessLink::EchoMessage(Message *msg)
 }
 
 void
 ProcessLink::SendMessage(Message *msg)
 {
     mChan->AssertWorkerThread();
     mChan->mMonitor->AssertCurrentThreadOwns();
 
+#ifdef MOZ_NUWA_PROCESS
+    if (mIsToNuwaProcess && mozilla::dom::ContentParent::IsNuwaReady()) {
+        switch (msg->type()) {
+        case mozilla::dom::PContent::Msg_NuwaFork__ID:
+        case mozilla::dom::PContent::Reply_AddNewProcess__ID:
+        case mozilla::dom::PContent::Msg_NotifyPhoneStateChange__ID:
+        case GOODBYE_MESSAGE_TYPE:
+            break;
+        default:
+#ifdef DEBUG
+            MOZ_CRASH();
+#else
+            // In optimized build, message will be dropped.
+            printf_stderr("Sending message to frozen Nuwa");
+            return;
+#endif
+        }
+    }
+#endif
+
     mIOLoop->PostTask(
         FROM_HERE,
         NewRunnableMethod(mTransport, &Transport::Send, msg));
 }
 
 void
 ProcessLink::SendClose()
 {
@@ -355,16 +379,20 @@ ProcessLink::OnChannelConnected(int32_t 
           mChan->mMonitor->Notify();
           notifyChannel = true;
         }
     }
 
     if (mExistingListener)
         mExistingListener->OnChannelConnected(peer_pid);
 
+#ifdef MOZ_NUWA_PROCESS
+    mIsToNuwaProcess = (peer_pid == mozilla::dom::ContentParent::NuwaPid());
+#endif
+
     if (notifyChannel) {
       mChan->OnChannelConnected(peer_pid);
     }
 }
 
 void
 ProcessLink::OnChannelError()
 {
--- a/ipc/glue/MessageLink.h
+++ b/ipc/glue/MessageLink.h
@@ -165,16 +165,19 @@ class ProcessLink
 
     virtual bool Unsound_IsClosed() const MOZ_OVERRIDE;
     virtual uint32_t Unsound_NumQueuedMessages() const MOZ_OVERRIDE;
 
   protected:
     Transport* mTransport;
     MessageLoop* mIOLoop;       // thread where IO happens
     Transport::Listener* mExistingListener; // channel's previous listener
+#ifdef MOZ_NUWA_PROCESS
+    bool mIsToNuwaProcess;
+#endif
 };
 
 class ThreadLink : public MessageLink
 {
   public:
     ThreadLink(MessageChannel *aChan, MessageChannel *aTargetChan);
     virtual ~ThreadLink();
 
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2011,16 +2011,22 @@ CheckSideEffects(ExclusiveContext *cx, B
                 /*
                  * Not a use of an unshadowed named function expression's given
                  * name, so this expression could invoke a getter that has side
                  * effects.
                  */
                 *answer = true;
             }
         }
+
+        if (pn->isHoistedLetUse()) {
+            // Hoisted uses of lexical bindings throw on access.
+            *answer = true;
+        }
+
         if (pn->isKind(PNK_DOT)) {
             /* Dotted property references in general can call getters. */
             *answer = true;
         }
         return CheckSideEffects(cx, bce, pn->maybeExpr(), answer);
 
       case PN_NULLARY:
         if (pn->isKind(PNK_DEBUGGER))
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/letTDZDelete.js
@@ -0,0 +1,23 @@
+function assertThrowsReferenceError(f) {
+  var e = null;
+  try {
+    f();
+  } catch (ex) {
+    e = ex;
+  }
+  assertEq(e instanceof ReferenceError, true);
+}
+
+assertThrowsReferenceError(function () { delete x; let x; });
+
+// FIXME do this unconditionally once bug 611388 lands.
+function constIsLexical() {
+  try {
+    (function () { z++; const z; })();
+    return false;
+  } catch (e) {
+    return true;
+  }
+}
+if (constIsLexical())
+  assertThrowsReferenceError(function () { delete x; const x; });
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/letTDZEffectful.js
@@ -0,0 +1,24 @@
+function assertThrowsReferenceError(f) {
+  var e = null;
+  try {
+    f();
+  } catch (ex) {
+    e = ex;
+  }
+  assertEq(e instanceof ReferenceError, true);
+}
+
+// TDZ is effectful, don't optimize out x.
+assertThrowsReferenceError(function () { x; let x; });
+
+// FIXME do this unconditionally once bug 611388 lands.
+function constIsLexical() {
+  try {
+    (function () { z++; const z; })();
+    return false;
+  } catch (e) {
+    return true;
+  }
+}
+if (constIsLexical())
+  assertThrowsReferenceError(function () { x; const x; });
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1070465.js
@@ -0,0 +1,5 @@
+// |jit-test| error: ReferenceError
+{
+  while (x && 0) {}
+  let x
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1073702.js
@@ -0,0 +1,10 @@
+try {
+  let x = ((function f(y) {
+    if (y > 0) {
+      f(-1)
+    }
+    x
+  })(1))
+} catch (e) {
+  assertEq(e instanceof ReferenceError, true);
+}
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -7906,23 +7906,38 @@ ICSetPropNativeAddCompiler::generateStub
     scratch = regs.takeAny();
 
     // Changing object shape.  Write the object's new shape.
     Address shapeAddr(objReg, JSObject::offsetOfShape());
     EmitPreBarrier(masm, shapeAddr, MIRType_Shape);
     masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
     masm.storePtr(scratch, shapeAddr);
 
-    // Change the object's type if required.
+    // Try to change the object's type.
     Label noTypeChange;
+
+    // Check if the cache has a new type to change to.
     masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch);
     masm.branchTestPtr(Assembler::Zero, scratch, scratch, &noTypeChange);
+
+    // Check if the old type still has a newScript.
+    masm.loadPtr(Address(objReg, JSObject::offsetOfType()), scratch);
+    masm.branchPtr(Assembler::Equal,
+                   Address(scratch, types::TypeObject::offsetOfNewScript()),
+                   ImmWord(0),
+                   &noTypeChange);
+
+    // Reload the new type from the cache.
+    masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch);
+
+    // Change the object's type.
     Address typeAddr(objReg, JSObject::offsetOfType());
     EmitPreBarrier(masm, typeAddr, MIRType_TypeObject);
     masm.storePtr(scratch, typeAddr);
+
     masm.bind(&noTypeChange);
 
     Register holderReg;
     regs.add(R0);
     regs.takeUnchecked(objReg);
     if (isFixedSlot_) {
         holderReg = objReg;
     } else {
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -2578,21 +2578,37 @@ GenerateAddSlot(JSContext *cx, MacroAsse
     Shape *newShape = obj->lastProperty();
     Address shapeAddr(object, JSObject::offsetOfShape());
     if (cx->zone()->needsIncrementalBarrier())
         masm.callPreBarrier(shapeAddr, MIRType_Shape);
     masm.storePtr(ImmGCPtr(newShape), shapeAddr);
 
     if (oldType != obj->type()) {
         // Changing object's type from a partially to fully initialized type,
-        // per the acquired properties analysis.
+        // per the acquired properties analysis. Only change the type if the
+        // old type still has a newScript.
+        Label noTypeChange, skipPop;
+
+        masm.push(object);
+        masm.loadPtr(Address(object, JSObject::offsetOfType()), object);
+        masm.branchPtr(Assembler::Equal,
+                       Address(object, types::TypeObject::offsetOfNewScript()),
+                       ImmWord(0),
+                       &noTypeChange);
+        masm.pop(object);
+
         Address typeAddr(object, JSObject::offsetOfType());
         if (cx->zone()->needsIncrementalBarrier())
             masm.callPreBarrier(typeAddr, MIRType_TypeObject);
         masm.storePtr(ImmGCPtr(obj->type()), typeAddr);
+
+        masm.jump(&skipPop);
+        masm.bind(&noTypeChange);
+        masm.pop(object);
+        masm.bind(&skipPop);
     }
 
     // Set the value on the object. Since this is an add, obj->lastProperty()
     // must be the shape of the property we are adding.
     if (obj->isFixedSlot(newShape->slot())) {
         Address addr(object, JSObject::getFixedSlotOffset(newShape->slot()));
         masm.storeConstantOrRegister(value, addr);
     } else {
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -568,25 +568,42 @@ jit::MakeSingletonTypeSet(types::Compile
     JS_ASSERT(constraints);
     types::TypeObjectKey *objType = types::TypeObjectKey::get(obj);
     objType->hasFlags(constraints, types::OBJECT_FLAG_UNKNOWN_PROPERTIES);
 
     LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
     return alloc->new_<types::TemporaryTypeSet>(alloc, types::Type::ObjectType(obj));
 }
 
+static types::TemporaryTypeSet *
+MakeUnknownTypeSet()
+{
+    LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
+    return alloc->new_<types::TemporaryTypeSet>(alloc, types::Type::UnknownType());
+}
+
 MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constraints)
   : value_(vp)
 {
     setResultType(MIRTypeFromValue(vp));
     if (vp.isObject()) {
         // Create a singleton type set for the object. This isn't necessary for
         // other types as the result type encodes all needed information.
         setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject()));
     }
+    if (vp.isMagic() && vp.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
+        // JS_UNINITIALIZED_LEXICAL does not escape to script and is not
+        // observed in type sets. However, it may flow around freely during
+        // Ion compilation. Give it an unknown typeset to poison any type sets
+        // it merges with.
+        //
+        // TODO We could track uninitialized lexicals more precisely by tracking
+        // them in type sets.
+        setResultTypeSet(MakeUnknownTypeSet());
+    }
 
     setMovable();
 }
 
 MConstant::MConstant(JSObject *obj)
   : value_(ObjectValue(*obj))
 {
     setResultType(MIRType_Object);
--- a/js/src/jsapi-tests/README
+++ b/js/src/jsapi-tests/README
@@ -2,27 +2,29 @@
 
 The tests in this directory exercise the JSAPI.
 
 
 --- Building and running the tests
 
 If you built JS, you already built the tests.
 
-If you did `make check` in your JS objdir, you already ran them.
-
 The tests are built by default when you build JS. All the tests are compiled
 into a single binary named jsapi-tests. They all run in a single process.
 
+To run the tests:
+
+    cd $OBJDIR/dist/bin
+    ./jsapi-tests
+
 To run the tests in a debugger:
 
-    cd $OBJDIR/jsapi-tests
+    cd $OBJDIR/dist/bin
     gdb ./jsapi-tests
 
-
 --- Creating new tests
 
  1. You can either add to an existing test*.cpp file or make a new one.
     Copy an existing test and replace the body with your test code.
     The test harness provides `cx`, `rt`, and `global` for your use.
 
  2. If you made a new .cpp file, add it to the CPPSRCS list in Makefile.in.
 
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -24,16 +24,17 @@ UNIFIED_SOURCES += [
     'testDefineGetterSetterNonEnumerable.cpp',
     'testDefineProperty.cpp',
     'testDefinePropertyIgnoredAttributes.cpp',
     'testEnclosingFunction.cpp',
     'testErrorCopying.cpp',
     'testException.cpp',
     'testExternalStrings.cpp',
     'testFindSCCs.cpp',
+    'testForOfIterator.cpp',
     'testFreshGlobalEvalRedefinition.cpp',
     'testFuncCallback.cpp',
     'testFunctionProperties.cpp',
     'testGCAllocator.cpp',
     'testGCExactRooting.cpp',
     'testGCFinalizeCallback.cpp',
     'testGCHeapPostBarriers.cpp',
     'testGCOutOfMemory.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testForOfIterator.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jsapi-tests/tests.h"
+
+BEGIN_TEST(testForOfIterator_basicNonIterable)
+{
+    JS::RootedValue v(cx);
+    // Hack to make it simple to produce an object that has a property
+    // named Symbol.iterator.
+    EVAL("var obj = { '@@iterator': 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; obj;", &v);
+    JS::ForOfIterator iter(cx);
+    bool ok = iter.init(v);
+    CHECK(!ok);
+    JS_ClearPendingException(cx);
+    return true;
+}
+END_TEST(testForOfIterator_basicNonIterable)
+
+BEGIN_TEST(testForOfIterator_bug515273_part1)
+{
+    JS::RootedValue v(cx);
+
+    // Hack to make it simple to produce an object that has a property
+    // named Symbol.iterator.
+    EVAL("var obj = { '@@iterator': 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; obj;", &v);
+
+    JS::ForOfIterator iter(cx);
+    bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable);
+    CHECK(!ok);
+    JS_ClearPendingException(cx);
+    return true;
+}
+END_TEST(testForOfIterator_bug515273_part1)
+
+BEGIN_TEST(testForOfIterator_bug515273_part2)
+{
+    JS::RootedObject obj(cx,
+			 JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
+    CHECK(obj);
+    JS::RootedValue v(cx, JS::ObjectValue(*obj));
+
+    JS::ForOfIterator iter(cx);
+    bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable);
+    CHECK(ok);
+    CHECK(!iter.valueIsIterable());
+    return true;
+}
+END_TEST(testForOfIterator_bug515273_part2)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5186,20 +5186,20 @@ class MOZ_STACK_CLASS JS_PUBLIC_API(ForO
     explicit ForOfIterator(JSContext *cx) : cx_(cx), iterator(cx_), index(NOT_ARRAY) { }
 
     enum NonIterableBehavior {
         ThrowOnNonIterable,
         AllowNonIterable
     };
 
     /*
-     * Initialize the iterator.  If AllowNonIterable is passed then if iterable
-     * does not have a callable @@iterator init() will just return true instead
-     * of throwing.  Callers should then check valueIsIterable() before
-     * continuing with the iteration.
+     * Initialize the iterator.  If AllowNonIterable is passed then if getting
+     * the @@iterator property from iterable returns undefined init() will just
+     * return true instead of throwing.  Callers must then check
+     * valueIsIterable() before continuing with the iteration.
      */
     bool init(JS::HandleValue iterable,
               NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable);
 
     /*
      * This method assumes that |iterator| is already an iterator.  It will not
      * check for, and call @@iterator.  Callers should make sure that the passed
      * in value is in fact an iterator.
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1231,16 +1231,20 @@ struct TypeObject : public gc::TenuredCe
     static inline uint32_t offsetOfClasp() {
         return offsetof(TypeObject, clasp_);
     }
 
     static inline uint32_t offsetOfProto() {
         return offsetof(TypeObject, proto_);
     }
 
+    static inline uint32_t offsetOfNewScript() {
+        return offsetof(TypeObject, newScript_);
+    }
+
   private:
     inline uint32_t basePropertyCount() const;
     inline void setBasePropertyCount(uint32_t count);
 
     static void staticAsserts() {
         JS_STATIC_ASSERT(offsetof(TypeObject, proto_) == offsetof(js::shadow::TypeObject, proto));
     }
 };
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1361,23 +1361,27 @@ ForOfIterator::init(HandleValue iterable
     if (!args.init(0))
         return false;
     args.setThis(ObjectValue(*iterableObj));
 
     RootedValue callee(cx);
     if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee))
         return false;
 
-    // Throw if obj[@@iterator] isn't callable if we were asked to do so.
+    // If obj[@@iterator] is undefined and we were asked to allow non-iterables,
+    // bail out now without setting iterator.  This will make valueIsIterable(),
+    // which our caller should check, return false.
+    if (nonIterableBehavior == AllowNonIterable && callee.isUndefined())
+        return true;
+
+    // Throw if obj[@@iterator] isn't callable.
     // js::Invoke is about to check for this kind of error anyway, but it would
     // throw an inscrutable error message about |method| rather than this nice
     // one about |obj|.
     if (!callee.isObject() || !callee.toObject().isCallable()) {
-        if (nonIterableBehavior == AllowNonIterable)
-            return true;
         char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, NullPtr());
         if (!bytes)
             return false;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, bytes);
         js_free(bytes);
         return false;
     }
 
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -249,27 +249,30 @@ FetchName(JSContext *cx, HandleObject ob
         if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
             /* Fast path for Object instance properties. */
             JS_ASSERT(shape->hasSlot());
             vp.set(obj2->nativeGetSlot(shape->slot()));
         } else if (!NativeGet(cx, normalized, obj2, shape, vp)) {
             return false;
         }
     }
-    return true;
+
+    // NAME operations are the slow paths already, so unconditionally check
+    // for uninitialized lets.
+    return CheckUninitializedLexical(cx, name, vp);
 }
 
 inline bool
 FetchNameNoGC(JSObject *pobj, Shape *shape, MutableHandleValue vp)
 {
     if (!shape || !pobj->isNative() || !shape->isDataDescriptor() || !shape->hasDefaultGetter())
         return false;
 
     vp.set(pobj->nativeGetSlot(shape->slot()));
-    return true;
+    return !IsUninitializedLexical(vp);
 }
 
 inline bool
 GetIntrinsicOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue vp)
 {
     RootedPropertyName name(cx, cx->currentScript()->getName(pc));
     return GlobalObject::getIntrinsicValue(cx, cx->global(), name, vp);
 }
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -293,27 +293,19 @@ NameOperation(JSContext *cx, Interpreter
     RootedPropertyName nameRoot(cx, name);
     RootedShape shapeRoot(cx);
 
     if (!LookupName(cx, nameRoot, objRoot, &scopeRoot, &pobjRoot, &shapeRoot))
         return false;
 
     /* Kludge to allow (typeof foo == "undefined") tests. */
     JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
-    if (op2 == JSOP_TYPEOF) {
-        if (!FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp))
-            return false;
-    } else {
-        if (!FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp))
-            return false;
-    }
-
-    // NAME operations are the slow paths already, so unconditionally check
-    // for uninitialized lets.
-    return CheckUninitializedLexical(cx, nameRoot, vp);
+    if (op2 == JSOP_TYPEOF)
+        return FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
+    return FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
 }
 
 static inline bool
 SetPropertyOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lval,
                      HandleValue rval)
 {
     JS_ASSERT(*pc == JSOP_SETPROP);
 
@@ -3559,17 +3551,17 @@ js::GetScopeName(JSContext *cx, HandleOb
         if (AtomToPrintableString(cx, name, &printable))
             js_ReportIsNotDefined(cx, printable.ptr());
         return false;
     }
 
     if (!JSObject::getProperty(cx, obj, obj, name, vp))
         return false;
 
-    // See note in NameOperation.
+    // See note in FetchName.
     return CheckUninitializedLexical(cx, name, vp);
 }
 
 /*
  * Alternate form for NAME opcodes followed immediately by a TYPEOF,
  * which do not report an exception on (typeof foo == "undefined") tests.
  */
 bool
@@ -3584,17 +3576,17 @@ js::GetScopeNameForTypeOf(JSContext *cx,
     if (!shape) {
         vp.set(UndefinedValue());
         return true;
     }
 
     if (!JSObject::getProperty(cx, obj, obj, name, vp))
         return false;
 
-    // See note in NameOperation.
+    // See note in FetchName.
     return CheckUninitializedLexical(cx, name, vp);
 }
 
 JSObject *
 js::Lambda(JSContext *cx, HandleFunction fun, HandleObject parent)
 {
     MOZ_ASSERT(!fun->isArrow());
 
@@ -3869,16 +3861,23 @@ js::DeleteNameOperation(JSContext *cx, H
         return false;
 
     if (!scope) {
         // Return true for non-existent names.
         res.setBoolean(true);
         return true;
     }
 
+    // NAME operations are the slow paths already, so unconditionally check
+    // for uninitialized lets.
+    if (pobj == scope && IsUninitializedLexicalSlot(scope, shape)) {
+        ReportUninitializedLexical(cx, name);
+        return false;
+    }
+
     bool succeeded;
     RootedId id(cx, NameToId(name));
     if (!JSObject::deleteGeneric(cx, scope, id, &succeeded))
         return false;
     res.setBoolean(succeeded);
     return true;
 }
 
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -4366,17 +4366,17 @@ FrameLayerBuilder::PaintItems(nsTArray<C
 /**
  * Returns true if it is preferred to draw the list of display
  * items separately for each rect in the visible region rather
  * than clipping to a complex region.
  */
 static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip)
 {
   if (!gfxPrefs::LayoutPaintRectsSeparately() ||
-      aClip == DrawRegionClip::CLIP_NONE) {
+      aClip == DrawRegionClip::NONE) {
     return false;
   }
 
   DrawTarget *dt = aContext->GetDrawTarget();
   return dt->GetBackendType() == BackendType::DIRECT2D;
 }
 
 static void DrawForcedBackgroundColor(gfxContext* aContext, Layer* aLayer, nscolor aBackgroundColor)
@@ -4448,19 +4448,17 @@ FrameLayerBuilder::DrawPaintedLayer(Pain
   PaintedDisplayItemLayerUserData* userData =
     static_cast<PaintedDisplayItemLayerUserData*>
       (aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
   NS_ASSERTION(userData, "where did our user data go?");
 
   bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip);
 
   if (!shouldDrawRectsSeparately) {
-    if (aClip == DrawRegionClip::DRAW_SNAPPED) {
-      gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw);
-    } else if (aClip == DrawRegionClip::DRAW) {
+    if (aClip == DrawRegionClip::DRAW) {
       gfxUtils::ClipToRegion(aContext, aRegionToDraw);
     }
 
     DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor);
   }
 
   // make the origin of the context coincide with the origin of the
   // PaintedLayer
@@ -4481,17 +4479,17 @@ FrameLayerBuilder::DrawPaintedLayer(Pain
   nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
   rc->Init(presContext->DeviceContext(), aContext);
 
   if (shouldDrawRectsSeparately) {
     nsIntRegionRectIterator it(aRegionToDraw);
     while (const nsIntRect* iterRect = it.Next()) {
       gfxContextAutoSaveRestore save(aContext);
       aContext->NewPath();
-      aContext->Rectangle(*iterRect, aClip == DrawRegionClip::DRAW_SNAPPED);
+      aContext->Rectangle(*iterRect);
       aContext->Clip();
 
       DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor);
 
       // Apply the residual transform if it has been enabled, to ensure that
       // snapping when we draw into aContext exactly matches the ideal transform.
       // See above for why this is OK.
       aContext->SetMatrix(
@@ -4517,19 +4515,17 @@ FrameLayerBuilder::DrawPaintedLayer(Pain
                              entry->mCommonClipCount);
   }
 
   bool isActiveLayerManager = !aLayer->Manager()->IsInactiveLayerManager();
 
   if (presContext->GetPaintFlashing() && isActiveLayerManager) {
     gfxContextAutoSaveRestore save(aContext);
     if (shouldDrawRectsSeparately) {
-      if (aClip == DrawRegionClip::DRAW_SNAPPED) {
-        gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw);
-      } else if (aClip == DrawRegionClip::DRAW) {
+      if (aClip == DrawRegionClip::DRAW) {
         gfxUtils::ClipToRegion(aContext, aRegionToDraw);
       }
     }
     FlashPaint(aContext);
   }
 
   if (presContext && presContext->GetDocShell() && isActiveLayerManager) {
     nsDocShell* docShell = static_cast<nsDocShell*>(presContext->GetDocShell());
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -3064,16 +3064,26 @@ ElementRestyler::RestyleSelf(nsIFrame* a
         } else if (newContext->IsShared()) {
           LOG_RESTYLE("not swapping style structs, since the new context is "
                       "shared");
         } else {
           LOG_RESTYLE("swapping style structs between %p and %p",
                       oldContext.get(), newContext.get());
           oldContext->SwapStyleData(newContext, equalStructs);
           *aSwappedStructs |= equalStructs;
+#ifdef RESTYLE_LOGGING
+          uint32_t structs = RestyleManager::StructsToLog() & equalStructs;
+          if (structs) {
+            LOG_RESTYLE_INDENT();
+            LOG_RESTYLE("old style context now has: %s",
+                        oldContext->GetCachedStyleDataAsString(structs).get());
+            LOG_RESTYLE("new style context now has: %s",
+                        newContext->GetCachedStyleDataAsString(structs).get());
+          }
+#endif
         }
         LOG_RESTYLE("setting new style context");
         aSelf->SetStyleContext(newContext);
       }
     } else {
       LOG_RESTYLE("not setting new style context, since we'll reframe");
     }
   }
@@ -3631,16 +3641,49 @@ RestyleManager::ComputeStyleChangeFor(ns
         NS_ASSERTION(!cont->GetPrevContinuation(),
                      "continuing frame had more severe impact than first-in-flow");
         return;
       }
     }
   }
 }
 
+#ifdef RESTYLE_LOGGING
+uint32_t
+RestyleManager::StructsToLog()
+{
+  static bool initialized = false;
+  static uint32_t structs;
+  if (!initialized) {
+    structs = 0;
+    const char* value = getenv("MOZ_DEBUG_RESTYLE_STRUCTS");
+    if (value) {
+      nsCString s(value);
+      while (!s.IsEmpty()) {
+        int32_t index = s.FindChar(',');
+        nsStyleStructID sid;
+        bool found;
+        if (index == -1) {
+          found = nsStyleContext::LookupStruct(s, sid);
+          s.Truncate();
+        } else {
+          found = nsStyleContext::LookupStruct(Substring(s, 0, index), sid);
+          s = Substring(s, index + 1);
+        }
+        if (found) {
+          structs |= nsCachedStyleData::GetBitForSID(sid);
+        }
+      }
+    }
+    initialized = true;
+  }
+  return structs;
+}
+#endif
+
 #ifdef DEBUG
 /* static */ nsCString
 RestyleManager::RestyleHintToString(nsRestyleHint aHint)
 {
   nsCString result;
   bool any = false;
   const char* names[] = { "Self", "Subtree", "LaterSiblings", "CSSTransitions",
                           "CSSAnimations", "SVGAttrAnimations", "StyleAttribute",
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -381,16 +381,23 @@ public:
     return enabled;
   }
 
   static bool AnimationRestyleLoggingEnabled() {
     static bool animations = getenv("MOZ_DEBUG_RESTYLE_ANIMATIONS") != 0;
     return animations;
   }
 
+  // Set MOZ_DEBUG_RESTYLE_STRUCTS to a comma-separated string of
+  // style struct names -- such as "Font,SVGReset" -- to log the style context
+  // tree and those cached struct pointers before each restyle.  This
+  // function returns a bitfield of the structs named in the
+  // environment variable.
+  static uint32_t StructsToLog();
+
   static nsCString StructNamesToString(uint32_t aSIDs);
   int32_t& LoggingDepth() { return mLoggingDepth; }
 #endif
 
 private:
   /* aMinHint is the minimal change that should be made to the element */
   // XXXbz do we really need the aPrimaryFrame argument here?
   void RestyleElement(Element*        aElement,
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -157,17 +157,27 @@ RestyleTracker::ProcessOneRestyle(Elemen
   NS_PRECONDITION(aElement->GetCrossShadowCurrentDoc() == Document(),
                   "Element has unexpected document");
 
   LOG_RESTYLE("aRestyleHint = %s, aChangeHint = %s",
               RestyleManager::RestyleHintToString(aRestyleHint).get(),
               RestyleManager::ChangeHintToString(aChangeHint).get());
 
   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
+
   if (aRestyleHint & ~eRestyle_LaterSiblings) {
+#ifdef RESTYLE_LOGGING
+    if (ShouldLogRestyle() && primaryFrame &&
+        RestyleManager::StructsToLog() != 0) {
+      LOG_RESTYLE("style context tree before restyle:");
+      LOG_RESTYLE_INDENT();
+      primaryFrame->StyleContext()->LogStyleContextTree(
+          LoggingDepth(), RestyleManager::StructsToLog());
+    }
+#endif
     mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
                                     *this, aRestyleHint);
   } else if (aChangeHint &&
              (primaryFrame ||
               (aChangeHint & nsChangeHint_ReconstructFrame))) {
     // Don't need to recompute style; just apply the hint
     nsStyleChangeList changeList;
     changeList.AppendChange(primaryFrame, aElement, aChangeHint);
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -1219,30 +1219,31 @@ nsBidiPresUtils::ResolveParagraphWithinB
   ResolveParagraph(aBlockFrame, aBpd);
   aBpd->ResetData();
 }
 
 void
 nsBidiPresUtils::ReorderFrames(nsIFrame*   aFirstFrameOnLine,
                                int32_t     aNumFramesOnLine,
                                WritingMode aLineWM,
-                               nscoord&    aLineWidth)
+                               nscoord&    aLineWidth,
+                               nscoord     aStart)
 {
   // If this line consists of a line frame, reorder the line frame's children.
   if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) {
     aFirstFrameOnLine = aFirstFrameOnLine->GetFirstPrincipalChild();
     if (!aFirstFrameOnLine)
       return;
     // All children of the line frame are on the first line. Setting aNumFramesOnLine
     // to -1 makes InitLogicalArrayFromLine look at all of them.
     aNumFramesOnLine = -1;
   }
 
   BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
-  RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth);
+  RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth, aStart);
 }
 
 nsIFrame*
 nsBidiPresUtils::GetFirstLeaf(nsIFrame* aFrame)
 {
   nsIFrame* firstLeaf = aFrame;
   while (!IsBidiLeaf(firstLeaf)) {
     nsIFrame* firstChild = firstLeaf->GetFirstPrincipalChild();
@@ -1274,30 +1275,32 @@ nsBidiPresUtils::GetFrameBaseLevel(nsIFr
     firstLeaf = firstLeaf->GetFirstPrincipalChild();
   }
   return NS_GET_BASE_LEVEL(firstLeaf);
 }
 
 void
 nsBidiPresUtils::IsFirstOrLast(nsIFrame*             aFrame,
                                nsContinuationStates* aContinuationStates,
+                               bool                  aSpanDirMatchesLineDir,
                                bool&                 aIsFirst /* out */,
                                bool&                 aIsLast /* out */)
 {
   /*
    * Since we lay out frames in the line's direction, visiting a frame with
    * 'mFirstVisualFrame == nullptr', means it's the first appearance of one
    * of its continuation chain frames on the line.
    * To determine if it's the last visual frame of its continuation chain on
    * the line or not, we count the number of frames of the chain on the line,
    * and then reduce it when we lay out a frame of the chain. If this value
    * becomes 1 it means that it's the last visual frame of its continuation
    * chain on this line.
    */
 
+  bool firstInLineOrder, lastInLineOrder;
   nsFrameContinuationState* frameState = aContinuationStates->GetEntry(aFrame);
   nsFrameContinuationState* firstFrameState;
 
   if (!frameState->mFirstVisualFrame) {
     // aFrame is the first visual frame of its continuation chain
     nsFrameContinuationState* contState;
     nsIFrame* frame;
 
@@ -1322,26 +1325,40 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame*
     for (frame = aFrame->GetNextContinuation();
          frame && (contState = aContinuationStates->GetEntry(frame));
          frame = frame->GetNextContinuation()) {
       frameState->mFrameCount++;
       contState->mFirstVisualFrame = aFrame;
     }
     frameState->mHasContOnNextLines = (frame != nullptr);
 
-    aIsFirst = !frameState->mHasContOnPrevLines;
+    firstInLineOrder = true;
     firstFrameState = frameState;
   } else {
     // aFrame is not the first visual frame of its continuation chain
-    aIsFirst = false;
+    firstInLineOrder = false;
     firstFrameState = aContinuationStates->GetEntry(frameState->mFirstVisualFrame);
   }
 
-  aIsLast = (firstFrameState->mFrameCount == 1 &&
-             !firstFrameState->mHasContOnNextLines);
+  lastInLineOrder = (firstFrameState->mFrameCount == 1);
+
+  if (aSpanDirMatchesLineDir) {
+    aIsFirst = firstInLineOrder;
+    aIsLast = lastInLineOrder;
+  } else {
+    aIsFirst = lastInLineOrder;
+    aIsLast = firstInLineOrder;
+  }
+
+  if (frameState->mHasContOnPrevLines) {
+    aIsFirst = false;
+  }
+  if (firstFrameState->mHasContOnNextLines) {
+    aIsLast = false;
+  }
 
   if ((aIsFirst || aIsLast) &&
       (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
     // For ib splits, don't treat anything except the last part as
     // endmost or anything except the first part as startmost.
     // As an optimization, only get the first continuation once.
     nsIFrame* firstContinuation = aFrame->FirstContinuation();
     if (firstContinuation->FrameIsNonLastInIBSplit()) {
@@ -1351,72 +1368,81 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame*
     if (firstContinuation->FrameIsNonFirstInIBSplit()) {
       // We are not startmost
       aIsFirst = false;
     }
   }
 
   // Reduce number of remaining frames of the continuation chain on the line.
   firstFrameState->mFrameCount--;
+
+  nsInlineFrame* testFrame = do_QueryFrame(aFrame);
+
+  if (testFrame) {
+    aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET);
+
+    if (aIsFirst) {
+      aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
+    } else {
+      aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
+    }
+
+    if (aIsLast) {
+      aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
+    } else {
+      aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
+    }
+  }
 }
 
 void
 nsBidiPresUtils::RepositionFrame(nsIFrame*             aFrame,
                                  bool                  aIsEvenLevel,
                                  nscoord&              aStart,
                                  nsContinuationStates* aContinuationStates,
-                                 WritingMode           aLineWM,
-                                 nscoord&              aLineWidth)
+                                 WritingMode           aContainerWM,
+                                 nscoord&              aContainerWidth)
 {
   if (!aFrame)
     return;
 
   bool isFirst, isLast;
+  WritingMode frameWM = aFrame->GetWritingMode();
   IsFirstOrLast(aFrame,
                 aContinuationStates,
+                aContainerWM.IsBidiLTR() == frameWM.IsBidiLTR(),
                 isFirst /* out */,
                 isLast /* out */);
 
-  WritingMode frameWM = aFrame->GetWritingMode();
-  nsInlineFrame* testFrame = do_QueryFrame(aFrame);
-
-  if (testFrame) {
-    aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET);
+  // We only need the margin if the frame is first or last in its own
+  // writing mode, but we're traversing the frames in the order of the
+  // container's writing mode. To get the right values, we set start and
+  // end margins on a logical margin in the frame's writing mode, and
+  // then convert the margin to the container's writing mode to set the
+  // coordinates.
 
-    if (isFirst) {
-      aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
-    } else {
-      aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
-    }
-
-    if (isLast) {
-      aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
-    } else {
-      aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
-    }
-  }
   // This method is called from nsBlockFrame::PlaceLine via the call to
   // bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
   // have been reflowed, which is required for GetUsedMargin/Border/Padding
-  LogicalMargin margin(aLineWM, aFrame->GetUsedMargin());
-  if (isFirst) {
-    aStart += margin.IStart(aLineWM);
+  LogicalMargin frameMargin = aFrame->GetLogicalUsedMargin(frameWM);
+  LogicalMargin borderPadding = aFrame->GetLogicalUsedBorderAndPadding(frameWM);
+  if (!isFirst) {
+    frameMargin.IStart(frameWM) = 0;
+    borderPadding.IStart(frameWM) = 0;
   }
+  if (!isLast) {
+    frameMargin.IEnd(frameWM) = 0;
+    borderPadding.IEnd(frameWM) = 0;
+  }
+  LogicalMargin margin = frameMargin.ConvertTo(aContainerWM, frameWM);
+  aStart += margin.IStart(aContainerWM);
 
   nscoord start = aStart;
-  nscoord frameISize = aFrame->ISize(aLineWM);
 
-  if (!IsBidiLeaf(aFrame))
-  {
-    nscoord iCoord = 0;
-    LogicalMargin borderPadding(frameWM, aFrame->GetUsedBorderAndPadding());
-    if (isFirst) {
-      iCoord += borderPadding.IStart(frameWM);
-    }
-
+  if (!IsBidiLeaf(aFrame)) {
     // If the resolved direction of the container is different from the
     // direction of the frame, we need to traverse the child list in reverse
     // order, to make it O(n) we store the list locally and iterate the list
     // in reverse
     bool reverseOrder = aIsEvenLevel != frameWM.IsBidiLTR();
     nsTArray<nsIFrame*> childList;
     nsIFrame *frame = aFrame->GetFirstPrincipalChild();
     if (frame && reverseOrder) {
@@ -1425,45 +1451,43 @@ nsBidiPresUtils::RepositionFrame(nsIFram
         childList.AppendElement(frame);
         frame = frame->GetNextSibling();
       }
       frame = childList[childList.Length() - 1];
     }
 
     // Reposition the child frames
     int32_t index = 0;
+    nscoord iCoord = borderPadding.IStart(frameWM);
+
     while (frame) {
       RepositionFrame(frame,
                       aIsEvenLevel,
                       iCoord,
                       aContinuationStates,
                       frameWM,
-                      frameISize);
+                      aFrame->GetLogicalSize(aContainerWM).Width(aContainerWM));
       index++;
       frame = reverseOrder ?
                 childList[childList.Length() - index - 1] :
                 frame->GetNextSibling();
     }
 
-    if (isLast) {
-      iCoord += borderPadding.IEnd(frameWM);
-    }
-    aStart += iCoord;
+    aStart += iCoord + borderPadding.IEnd(frameWM);
   } else {
-    aStart += frameISize;
+    aStart += aFrame->ISize(aContainerWM);
   }
 
-  LogicalRect logicalRect(aLineWM, aFrame->GetRect(), aLineWidth);
-  logicalRect.IStart(aLineWM) = start;
-  logicalRect.ISize(aLineWM) = aStart - start;
-  aFrame->SetRect(aLineWM, logicalRect, aLineWidth);
+  LogicalRect logicalRect = aFrame->GetLogicalRect(aContainerWM,
+                                                   aContainerWidth);
+  logicalRect.IStart(aContainerWM) = start;
+  logicalRect.ISize(aContainerWM) = aStart - start;
+  aFrame->SetRect(aContainerWM, logicalRect, aContainerWidth);
 
-  if (isLast) {
-    aStart += margin.IEnd(aLineWM);
-  }
+  aStart += margin.IEnd(aContainerWM);
 }
 
 void
 nsBidiPresUtils::InitContinuationStates(nsIFrame*              aFrame,
                                         nsContinuationStates*  aContinuationStates)
 {
   nsFrameContinuationState* state = aContinuationStates->PutEntry(aFrame);
   state->mFirstVisualFrame = nullptr;
@@ -1480,30 +1504,20 @@ nsBidiPresUtils::InitContinuationStates(
     }
   }
 }
 
 void
 nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
                                         nsIFrame* aFirstChild,
                                         WritingMode aLineWM,
-                                        nscoord& aLineWidth)
+                                        nscoord& aLineWidth,
+                                        nscoord& aStart)
 {
-  nscoord startSpace = 0;
-
-  // This method is called from nsBlockFrame::PlaceLine via the call to
-  // bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
-  // have been reflowed, which is required for GetUsedMargin/Border/Padding
-  LogicalMargin margin(aLineWM, aFirstChild->GetUsedMargin());
-  if (!aFirstChild->GetPrevContinuation() &&
-      !aFirstChild->FrameIsNonFirstInIBSplit())
-    startSpace = margin.IStart(aLineWM);
-
-  nscoord start = LogicalRect(aLineWM, aFirstChild->GetRect(),
-                              aLineWidth).IStart(aLineWM) - startSpace;
+  nscoord start = aStart;
   nsIFrame* frame;
   int32_t count = aBld->mVisualFrames.Length();
   int32_t index;
   nsContinuationStates continuationStates;
 
   // Initialize continuation states to (nullptr, 0) for
   // each frame on the line.
   for (index = 0; index < count; index++) {
--- a/layout/base/nsBidiPresUtils.h
+++ b/layout/base/nsBidiPresUtils.h
@@ -155,17 +155,18 @@ public:
    * Reorder this line using Bidi engine.
    * Update frame array, following the new visual sequence.
    * 
    * @lina 05/02/2000
    */
   static void ReorderFrames(nsIFrame*            aFirstFrameOnLine,
                             int32_t              aNumFramesOnLine,
                             mozilla::WritingMode aLineWM,
-                            nscoord&             aLineWidth);
+                            nscoord&             aLineWidth,
+                            nscoord              aStart);
 
   /**
    * Format Unicode text, taking into account bidi capabilities
    * of the platform. The formatting includes: reordering, Arabic shaping,
    * symmetric and numeric swapping, removing control characters.
    *
    * @lina 06/18/2000 
    */
@@ -392,61 +393,72 @@ private:
    *                             OUT value will be the ending position of aFrame
    *                             (after adding its inline-end margin)
    * @param aContinuationStates  A map from nsIFrame* to nsFrameContinuationState
    */
   static void RepositionFrame(nsIFrame*              aFrame,
                               bool                   aIsEvenLevel,
                               nscoord&               aStart,
                               nsContinuationStates*  aContinuationStates,
-                              mozilla::WritingMode   aLineWM,
-                              nscoord&               aLineWidth);
+                              mozilla::WritingMode   aContainerWM,
+                              nscoord&               aContainerWidth);
 
   /*
    * Initialize the continuation state(nsFrameContinuationState) to
    * (nullptr, 0) for aFrame and its descendants.
    *
    * @param aFrame               The frame which itself and its descendants will
    *                             be initialized
    * @param aContinuationStates  A map from nsIFrame* to nsFrameContinuationState
    */
   static void InitContinuationStates(nsIFrame*              aFrame,
                                      nsContinuationStates*  aContinuationStates);
 
   /*
-   * Determine if aFrame is leftmost or rightmost, and set aIsLeftMost and
-   * aIsRightMost values. Also set continuation states of aContinuationStates.
+   * Determine if aFrame is first or last, and set aIsFirst and
+   * aIsLast values. Also set continuation states of
+   * aContinuationStates.
+   *
+   * A frame is first if it's the first appearance of its continuation
+   * chain on the line and the chain is on its first line.
+   * A frame is last if it's the last appearance of its continuation
+   * chain on the line and the chain is on its last line.
    *
-   * A frame is leftmost if it's the first appearance of its continuation chain
-   * on the line and the chain is on its first line if it's LTR or the chain is
-   * on its last line if it's RTL.
-   * A frame is rightmost if it's the last appearance of its continuation chain
-   * on the line and the chain is on its first line if it's RTL or the chain is
-   * on its last line if it's LTR.
+   * N.B: "First appearance" and "Last appearance" in the previous
+   * paragraph refer to the frame's inline direction, not necessarily
+   * the line's.
    *
-   * @param aContinuationStates  A map from nsIFrame* to nsFrameContinuationState
-   * @param[out] aIsLeftMost     TRUE means aFrame is leftmost frame or continuation
-   * @param[out] aIsRightMost    TRUE means aFrame is rightmost frame or continuation
+   * @param aContinuationStates        A map from nsIFrame* to
+   *                                    nsFrameContinuationState
+   * @param[in] aSpanDirMatchesLineDir TRUE means that the inline
+   *                                    direction of aFrame is the same
+   *                                    as its container
+   * @param[out] aIsFirst              TRUE means aFrame is first frame
+   *                                    or continuation
+   * @param[out] aIsLast               TRUE means aFrame is last frame
+   *                                    or continuation
    */
    static void IsFirstOrLast(nsIFrame*              aFrame,
                              nsContinuationStates*  aContinuationStates,
+                             bool                   aSpanInLineOrder /* in */,
                              bool&                  aIsFirst /* out */,
                              bool&                  aIsLast /* out */);
 
   /**
    *  Adjust frame positions following their visual order
    *
    *  @param aFirstChild the first kid
    *
    *  @lina 04/11/2000
    */
   static void RepositionInlineFrames(BidiLineData* aBld,
                                      nsIFrame* aFirstChild,
                                      mozilla::WritingMode aLineWM,
-                                     nscoord& aLineWidth);
+                                     nscoord& aLineWidth,
+                                     nscoord& aStart);
   
   /**
    * Helper method for Resolve()
    * Truncate a text frame to the end of a single-directional run and possibly
    * create a continuation frame for the remainder of its content.
    *
    * @param aFrame       the original frame
    * @param aNewFrame    [OUT] the new frame that was created
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -2593,30 +2593,32 @@ nsLineLayout::TextAlignLine(nsLineBox* a
 
       case NS_STYLE_TEXT_ALIGN_CENTER:
       case NS_STYLE_TEXT_ALIGN_MOZ_CENTER:
         dx = remainingISize / 2;
         break;
     }
   }
 
-  if (dx) {
+  if (mPresContext->BidiEnabled() &&
+      (!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
+    nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
+                                   aLine->GetChildCount(),
+                                   lineWM, mContainerWidth,
+                                   psd->mIStart + mTextIndent + dx);
+    if (dx) {
+      aLine->IndentBy(dx, mContainerWidth);
+    }
+  } else if (dx) {
     for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
       pfd->mBounds.IStart(lineWM) += dx;
       pfd->mFrame->SetRect(lineWM, pfd->mBounds, mContainerWidth);
     }
     aLine->IndentBy(dx, mContainerWidth);
   }
-
-  if (mPresContext->BidiEnabled() &&
-      (!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
-    nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
-                                   aLine->GetChildCount(),
-                                   lineWM, mContainerWidth);
-  }
 }
 
 void
 nsLineLayout::RelativePositionFrames(nsOverflowAreas& aOverflowAreas)
 {
   RelativePositionFrames(mRootSpan, aOverflowAreas);
 }
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/1069941-inline-bidi-border-1-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Test for bug 1069941 -- borders</title>
+</head>
+<body>
+<div dir="ltr">
+  <span dir="ltr" style="color:transparent;background:gray;border-left:10px solid teal;">+٥</span>
+</div>
+<div dir="ltr">
+  <span dir="ltr" style="color:transparent;background:gray;border-right:10px solid teal;">+٥</span>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/1069941-inline-bidi-border-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Test for bug 1069941 -- borders</title>
+</head>
+<body>
+<div dir="ltr">
+  <span dir="rtl" style="color:transparent;background:gray;border-left:10px solid teal;">+٥</span>
+</div>
+<div dir="ltr">
+  <span dir="rtl" style="color:transparent;background:gray;border-right:10px solid teal;">+٥</span>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/1069941-inline-bidi-margin-1-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Test for bug 1069941 -- margins</title>
+<style type="text/css">
+ .outer {
+   display: inline-block;
+   border: 1px solid lime;
+ }
+ .inner {
+   color:transparent;
+   margin-left: 50px;
+   border: 2px solid teal;
+ }
+</style>
+</head>
+<body>
+<span class="outer"><span class="inner">(12]</span></span>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/1069941-inline-bidi-margin-1.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Test for bug 1069941 -- margins</title>
+<style type="text/css">
+ .outer {
+   display: inline-block;
+   border: 1px solid lime;
+ }
+ .inner {
+   color:transparent;
+   margin-left: 50px;
+   border: 2px solid teal;
+ }
+</style>
+</head>
+<body>
+<span class="outer"><span class="inner" dir="rtl">[12)</span></span>
+</body>
+</html>
--- a/layout/reftests/bidi/reftest.list
+++ b/layout/reftests/bidi/reftest.list
@@ -137,8 +137,11 @@ skip-if(B2G) == 726420-1.html 726420-1-r
 == 746987-3.html 746987-3-ref.html
 == 746987-4.html 746987-4-ref.html
 == 779003-1.html 779003-1-ref.html
 == 779003-1-dynamic.html 779003-1-ref.html
 == 847242-1.html 847242-1-ref.html
 skip-if(B2G&&browserIsRemote) == 869833-1.xul 869833-1-ref.xul
 == 922530-1.html 922530-1-ref.html
 == 922550-1.html 922550-1-ref.html
+== 1069941-inline-bidi-border-1.html 1069941-inline-bidi-border-1-ref.html
+== 1069941-inline-bidi-margin-1.html 1069941-inline-bidi-margin-1-ref.html
+
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -1043,16 +1043,31 @@ nsStyleContext::StructName(nsStyleStruct
     case eStyleStruct_##name_:                                                \
       return #name_;
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
     default:
       return "Unknown";
   }
 }
+
+/* static */ bool
+nsStyleContext::LookupStruct(const nsACString& aName, nsStyleStructID& aResult)
+{
+  if (false)
+    ;
+#define STYLE_STRUCT(name_, checkdata_cb_)                                    \
+  else if (aName.EqualsLiteral(#name_))                                       \
+    aResult = eStyleStruct_##name_;
+#include "nsStyleStructList.h"
+#undef STYLE_STRUCT
+  else
+    return false;
+  return true;
+}
 #endif
 
 bool
 nsStyleContext::HasSameCachedStyleData(nsStyleContext* aOther,
                                        nsStyleStructID aSID)
 {
   return GetCachedStyleData(aSID) == aOther->GetCachedStyleData(aSID);
 }
@@ -1157,8 +1172,101 @@ nsStyleContext::DoClearCachedInheritedSt
   }
 
   if (aStructs == 0) {
     return;
   }
 
   ClearCachedInheritedStyleDataOnDescendants(aStructs);
 }
+
+#ifdef RESTYLE_LOGGING
+nsCString
+nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
+{
+  nsCString structs;
+  for (nsStyleStructID i = nsStyleStructID(0);
+       i < nsStyleStructID_Length;
+       i = nsStyleStructID(i + 1)) {
+    if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
+      const void* data = GetCachedStyleData(i);
+      if (!structs.IsEmpty()) {
+        structs.Append(' ');
+      }
+      structs.AppendPrintf("%s=%p", StructName(i), data);
+      if (HasCachedInheritedStyleData(i)) {
+        structs.AppendLiteral("(dependent)");
+      } else {
+        structs.AppendLiteral("(owned)");
+      }
+    }
+  }
+  return structs;
+}
+
+int32_t&
+nsStyleContext::LoggingDepth()
+{
+  static int32_t depth = 0;
+  return depth;
+}
+
+void
+nsStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
+{
+  LoggingDepth() = aLoggingDepth;
+  LogStyleContextTree(true, aStructs);
+}
+
+void
+nsStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
+{
+  nsCString structs = GetCachedStyleDataAsString(aStructs);
+  if (!structs.IsEmpty()) {
+    structs.Append(' ');
+  }
+
+  nsCString pseudo;
+  if (mPseudoTag) {
+    nsAutoString pseudoTag;
+    mPseudoTag->ToString(pseudoTag);
+    AppendUTF16toUTF8(pseudoTag, pseudo);
+    pseudo.Append(' ');
+  }
+
+  nsCString flags;
+  if (IsStyleIfVisited()) {
+    flags.AppendLiteral("IS_STYLE_IF_VISITED ");
+  }
+  if (UsesGrandancestorStyle()) {
+    flags.AppendLiteral("USES_GRANDANCESTOR_STYLE ");
+  }
+  if (IsShared()) {
+    flags.AppendLiteral("IS_SHARED ");
+  }
+
+  nsCString parent;
+  if (aFirst) {
+    parent.AppendPrintf("parent=%p ", mParent);
+  }
+
+  LOG_RESTYLE("%p(%d) %s%s%s%s",
+              this, mRefCnt,
+              structs.get(), pseudo.get(), flags.get(), parent.get());
+
+  LOG_RESTYLE_INDENT();
+
+  if (nullptr != mChild) {
+    nsStyleContext* child = mChild;
+    do {
+      child->LogStyleContextTree(false, aStructs);
+      child = child->mNextSibling;
+    } while (mChild != child);
+  }
+  if (nullptr != mEmptyChild) {
+    nsStyleContext* child = mEmptyChild;
+    do {
+      child->LogStyleContextTree(false, aStructs);
+      child = child->mNextSibling;
+    } while (mEmptyChild != child);
+  }
+}
+#endif
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* the interface (to internal code) for retrieving computed style data */
 
 #ifndef _nsStyleContext_h_
 #define _nsStyleContext_h_
 
+#include "mozilla/RestyleLogging.h"
 #include "nsRuleNode.h"
 #include "nsCSSPseudoElements.h"
 
 class nsIAtom;
 class nsPresContext;
 
 /**
  * An nsStyleContext represents the computed style data for an element.
@@ -392,16 +393,23 @@ public:
    * structs indicated in aStructs.
    */
   void ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
 
 #ifdef DEBUG
   void List(FILE* out, int32_t aIndent);
   static void AssertStyleStructMaxDifferenceValid();
   static const char* StructName(nsStyleStructID aSID);
+  static bool LookupStruct(const nsACString& aName, nsStyleStructID& aResult);
+#endif
+
+#ifdef RESTYLE_LOGGING
+  nsCString GetCachedStyleDataAsString(uint32_t aStructs);
+  void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs);
+  int32_t& LoggingDepth();
 #endif
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~nsStyleContext();
 
   void AddChild(nsStyleContext* aChild);
   void RemoveChild(nsStyleContext* aChild);
@@ -445,16 +453,25 @@ private:
   // Helper for ClearCachedInheritedStyleDataOnDescendants.
   void DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
 
 #ifdef DEBUG
   void AssertStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext,
                                      int32_t aLevels) const;
 #endif
 
+#ifdef RESTYLE_LOGGING
+  void LogStyleContextTree(bool aFirst, uint32_t aStructs);
+
+  // This only gets called under call trees where we've already checked
+  // that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
+  // It exists here just to satisfy LOG_RESTYLE's expectations.
+  bool ShouldLogRestyle() { return true; }
+#endif
+
   nsStyleContext* mParent; // STRONG
 
   // Children are kept in two circularly-linked lists.  The list anchor
   // is not part of the list (null for empty), and we point to the first
   // child.
   // mEmptyChild for children whose rule node is the root rule node, and
   // mChild for other children.  The order of children is not
   // meaningful.
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -159,16 +159,17 @@ class RemoteOptions(ReftestOptions):
         # httpd-path is specified by standard makefile targets and may be specified
         # on the command line to select a particular version of httpd.js. If not
         # specified, try to select the one from hostutils.zip, as required in bug 882932.
         if not options.httpdPath:
             options.httpdPath = os.path.join(options.utilityPath, "components")
 
         # Android does not run leak tests, but set some reasonable defaults to avoid errors.
         options.leakThresholds = {}
+        options.ignoreMissingLeaks = []
 
         # TODO: Copied from main, but I think these are no longer used in a post xulrunner world
         #options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner'
         #options.utilityPath = options.testRoot + self.automation._product + '/bin'
         return options
 
 class ReftestServer:
     """ Web server used to serve Reftests, for closer fidelity to the real web.
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -339,17 +339,17 @@ class RefTest(object):
                                  cmdlineArgs,
                                  utilityPath = options.utilityPath,
                                  xrePath=options.xrePath,
                                  debuggerInfo=debuggerInfo,
                                  symbolsPath=options.symbolsPath,
                                  # give the JS harness 30 seconds to deal
                                  # with its own timeouts
                                  timeout=options.timeout + 30.0)
-      processLeakLog(self.leakLogFile, options.leakThresholds)
+      processLeakLog(self.leakLogFile, options.leakThresholds, options.ignoreMissingLeaks)
       self.automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
     finally:
       self.cleanup(profileDir)
     return status
 
   def copyExtraFilesToProfile(self, options, profile):
     "Copy extra files or dirs specified on the command line to the testing profile."
     profileDir = profile.profile
@@ -508,16 +508,18 @@ class ReftestOptions(OptionParser):
         self.error("cannot specify thisChunk or totalChunks with parallel tests")
       if options.focusFilterMode != "all":
         self.error("cannot specify focusFilterMode with parallel tests")
       if options.debugger is not None:
         self.error("cannot specify a debugger with parallel tests")
 
       options.leakThresholds = {"default": options.defaultLeakThreshold}
 
+      options.ignoreMissingLeaks = []
+
     return options
 
 def main():
   automation = Automation()
   parser = ReftestOptions(automation)
   reftest = RefTest(automation)
 
   options, args = parser.parse_args()
old mode 100644
new mode 100755
rename from media/libnestegg/README
rename to media/libnestegg/README.md
--- a/media/libnestegg/README
+++ b/media/libnestegg/README.md
@@ -1,6 +1,8 @@
+[![Build Status](https://travis-ci.org/kinetiknz/nestegg.svg?branch=master)](https://travis-ci.org/kinetiknz/nestegg)
+
 See INSTALL for build instructions.
 
 Licensed under an ISC-style license.  See LICENSE for details.
 
 The source under the halloc/ directory is licensed under a BSD license.  See
 halloc/halloc.h for details.
--- a/media/libnestegg/README_MOZILLA
+++ b/media/libnestegg/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the nestegg
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The nestegg git repository is: git://github.com/kinetiknz/nestegg.git
 
-The git commit ID used was 46ab96bcc8b099704cc8a15993f80fe0269a5284.
+The git commit ID used was 59220ae3e801cbad0f8160129c4df315469af671.
--- a/media/libnestegg/include/nestegg.h
+++ b/media/libnestegg/include/nestegg.h
@@ -376,16 +376,19 @@ int nestegg_has_cues(nestegg * context);
  * @retval 0 The file is not a WebM file.
  * @retval 1 The file is a WebM file. */
 int nestegg_sniff(unsigned char const * buffer, size_t length);
 
 /**
  * Set the underlying allocation function for library allocations.
  *
  * @param realloc_func The desired function.
+ * @retval 0 realloc_func(p, 0) does not act as free()
+ * @retval 1 realloc_func(p, 0) acts as free()
+ * @retval -1 malloc failed during realloc_func test
  */
-void nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t));
+int nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t));
 
 #if defined(__cplusplus)
 }
 #endif
 
 #endif /* NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 */
--- a/media/libnestegg/src/halloc.c
+++ b/media/libnestegg/src/halloc.c
@@ -41,33 +41,36 @@ typedef struct hblock
  */
 realloc_t halloc_allocator = NULL;
 
 #define allocator halloc_allocator
 
 /*
  *	static methods
  */
-static void _set_allocator(void);
+int halloc_set_allocator(realloc_t realloc_func);
 static void * _realloc(void * ptr, size_t n);
 
 static int  _relate(hblock_t * b, hblock_t * p);
 static void _free_children(hblock_t * p);
 
 /*
  *	Core API
  */
 void * halloc(void * ptr, size_t len)
 {
 	hblock_t * p;
 
 	/* set up default allocator */
 	if (! allocator)
 	{
-		_set_allocator();
+		if (halloc_set_allocator(realloc) == 0)
+		{
+			halloc_set_allocator(_realloc);
+		}
 		assert(allocator);
 	}
 
 	/* calloc */
 	if (! ptr)
 	{
 		if (! len)
 			return NULL;
@@ -167,42 +170,42 @@ char * h_strdup(const char * str)
 	size_t len = strlen(str);
 	char * ptr = halloc(0, len + 1);
 	return ptr ? (ptr[len] = 0, memcpy(ptr, str, len)) : NULL;
 }
 
 /*
  *	static stuff
  */
-static void _set_allocator(void)
+int halloc_set_allocator(realloc_t realloc_func)
 {
 	void * p;
 	assert(! allocator);
 	
 	/*
 	 *	the purpose of the test below is to check the behaviour
 	 *	of realloc(ptr, 0), which is defined in the standard
 	 *	as an implementation-specific. if it returns zero,
 	 *	then it's equivalent to free(). it can however return
 	 *	non-zero, in which case it cannot be used for freeing
 	 *	memory blocks and we'll need to supply our own version
 	 *
 	 *	Thanks to Stan Tobias for pointing this tricky part out.
 	 */
-	allocator = realloc;
-	if (! (p = malloc(1)))
+	if (! (p = realloc_func(NULL, 1)))
 		/* hmm */
-		return;
+		return -1;
 		
-	if ((p = realloc(p, 0)))
+	if ((p = realloc_func(p, 0)))
 	{
-		/* realloc cannot be used as free() */
-		allocator = _realloc;
-		free(p);
+		/* realloc_func cannot be used as free() */
+		return 0;
 	}
+	allocator = realloc_func;
+	return 1;
 }
 
 static void * _realloc(void * ptr, size_t n)
 {
 	/*
 	 *	free'ing realloc()
 	 */
 	if (n)
--- a/media/libnestegg/src/nestegg.c
+++ b/media/libnestegg/src/nestegg.c
@@ -316,19 +316,28 @@ struct frame {
 
 struct block_additional {
   unsigned int id;
   unsigned char * data;
   size_t length;
   struct block_additional * next;
 };
 
+#define NE_IO_BUFSZ 16384
+
+struct nestegg_io_buf {
+  nestegg_io io;
+  unsigned char buffer[NE_IO_BUFSZ];
+  size_t bufsz;
+  int offset;
+};
+
 /* Public (opaque) Structures */
 struct nestegg {
-  nestegg_io * io;
+  struct nestegg_io_buf * io;
   nestegg_log log;
   struct pool_ctx * alloc_pool;
   uint64_t last_id;
   uint64_t last_size;
   int last_valid;
   struct list_node * ancestor;
   struct ebml ebml;
   struct segment segment;
@@ -541,53 +550,127 @@ ne_pool_alloc(size_t size, struct pool_c
 
 static void *
 ne_alloc(size_t size)
 {
   return calloc(1, size);
 }
 
 static int
-ne_io_read(nestegg_io * io, void * buffer, size_t length)
+ne_io_read(struct nestegg_io_buf * io, void * buffer, size_t length)
 {
-  return io->read(buffer, length, io->userdata);
+  int64_t off;
+  int r;
+  size_t avail;
+
+  assert(io->offset == -1 || (io->offset >= 0 && (unsigned int) io->offset < io->bufsz));
+
+  /* Too big to buffer, invalidate buffer and read through */
+  if (length > io->bufsz) {
+    if (io->offset != -1) {
+      r = io->io.seek(-(io->bufsz - io->offset), NESTEGG_SEEK_CUR, io->io.userdata);
+      if (r != 0) {
+        return -1;
+      }
+    }
+    io->offset = -1;
+    return io->io.read(buffer, length, io->io.userdata);
+  }
+
+  /* Buffer invalid */
+  if (io->offset == -1) {
+    off = io->io.tell(io->io.userdata);
+    if (off == -1) {
+      return -1;
+    }
+    /* Refill buffer */
+    r = io->io.read(io->buffer, io->bufsz, io->io.userdata);
+    if (r != 1) {
+      /* Read truncated due to being within io->bufsz of EOS, reset read
+         position and switch to read through mode */
+      io->offset = -1;
+      io->bufsz = 0;
+      if (r == 0) {
+        r = io->io.seek(off, NESTEGG_SEEK_SET, io->io.userdata);
+      }
+      if (r == 0) {
+        return io->io.read(buffer, length, io->io.userdata);
+      }
+      return -1;
+    }
+    if (r == 1) {
+      io->offset = 0;
+    }
+  }
+
+  /* Service request with what we have */
+  avail = length;
+  if (io->bufsz - io->offset < length) {
+    avail = io->bufsz - io->offset;
+  }
+  memcpy(buffer, io->buffer + io->offset, avail);
+  io->offset += avail;
+
+  if ((unsigned int) io->offset == io->bufsz) {
+    io->offset = -1;
+  }
+
+  /* Still more to read, invalidate buffer and read more */
+  if (length - avail > 0) {
+    return ne_io_read(io, (char *) buffer + avail, length - avail);
+  }
+
+  return 1;
 }
 
 static int
-ne_io_seek(nestegg_io * io, int64_t offset, int whence)
+ne_io_seek(struct nestegg_io_buf * io, int64_t offset, int whence)
+{
+  /* Invalidate buffer */
+  io->offset = -1;
+
+  return io->io.seek(offset, whence, io->io.userdata);
+}
+
+static int64_t
+ne_io_tell(struct nestegg_io_buf * io)
 {
-  return io->seek(offset, whence, io->userdata);
+  int64_t off;
+
+  off = io->io.tell(io->io.userdata);
+  if (off == -1) {
+    return -1;
+  }
+  if (io->offset == -1) {
+    return off;
+  }
+  assert(off >= (int64_t) io->bufsz - io->offset);
+  return off - io->bufsz + (unsigned int) io->offset;
 }
 
 static int
-ne_io_read_skip(nestegg_io * io, size_t length)
+ne_io_read_skip(struct nestegg_io_buf * io, size_t length)
 {
   size_t get;
   unsigned char buf[8192];
   int r = 1;
 
   while (length > 0) {
     get = length < sizeof(buf) ? length : sizeof(buf);
     r = ne_io_read(io, buf, get);
     if (r != 1)
       break;
     length -= get;
   }
 
   return r;
 }
 
-static int64_t
-ne_io_tell(nestegg_io * io)
-{
-  return io->tell(io->userdata);
-}
-
 static int
-ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag)
+ne_bare_read_vint(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag)
 {
   int r;
   unsigned char b;
   size_t maxlen = 8;
   unsigned int count = 1, mask = 1 << 7;
 
   r = ne_io_read(io, &b, 1);
   if (r != 1)
@@ -614,29 +697,29 @@ ne_bare_read_vint(nestegg_io * io, uint6
     *value <<= 8;
     *value |= b;
   }
 
   return 1;
 }
 
 static int
-ne_read_id(nestegg_io * io, uint64_t * value, uint64_t * length)
+ne_read_id(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length)
 {
   return ne_bare_read_vint(io, value, length, MASK_NONE);
 }
 
 static int
-ne_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length)
+ne_read_vint(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length)
 {
   return ne_bare_read_vint(io, value, length, MASK_FIRST_BIT);
 }
 
 static int
-ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length)
+ne_read_svint(struct nestegg_io_buf * io, int64_t * value, uint64_t * length)
 {
   int r;
   uint64_t uvalue;
   uint64_t ulength;
   int64_t svint_subtr[] = {
     0x3f, 0x1fff,
     0xfffff, 0x7ffffff,
     0x3ffffffffLL, 0x1ffffffffffLL,
@@ -648,17 +731,17 @@ ne_read_svint(nestegg_io * io, int64_t *
     return r;
   *value = uvalue - svint_subtr[ulength - 1];
   if (length)
     *length = ulength;
   return r;
 }
 
 static int
-ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length)
+ne_read_uint(struct nestegg_io_buf * io, uint64_t * val, uint64_t length)
 {
   unsigned char b;
   int r;
 
   if (length == 0 || length > 8)
     return -1;
   r = ne_io_read(io, &b, 1);
   if (r != 1)
@@ -670,44 +753,44 @@ ne_read_uint(nestegg_io * io, uint64_t *
       return r;
     *val <<= 8;
     *val |= b;
   }
   return 1;
 }
 
 static int
-ne_read_int(nestegg_io * io, int64_t * val, uint64_t length)
+ne_read_int(struct nestegg_io_buf * io, int64_t * val, uint64_t length)
 {
   int r;
   uint64_t uval, base;
 
   r = ne_read_uint(io, &uval, length);
   if (r != 1)
     return r;
 
   if (length < sizeof(int64_t)) {
     base = 1;
     base <<= length * 8 - 1;
     if (uval >= base) {
-        base = 1;
-        base <<= length * 8;
+      base = 1;
+      base <<= length * 8;
     } else {
       base = 0;
     }
     *val = uval - base;
   } else {
     *val = (int64_t) uval;
   }
 
   return 1;
 }
 
 static int
-ne_read_float(nestegg_io * io, double * val, uint64_t length)
+ne_read_float(struct nestegg_io_buf * io, double * val, uint64_t length)
 {
   union {
     uint64_t u;
     float f;
     double d;
   } value;
   int r;
 
@@ -731,19 +814,19 @@ ne_read_string(nestegg * ctx, char ** va
   int r;
 
   if (length > LIMIT_STRING)
     return -1;
   str = ne_pool_alloc(length + 1, ctx->alloc_pool);
   if (!str)
     return -1;
   if (length) {
-      r = ne_io_read(ctx->io, (unsigned char *) str, length);
-      if (r != 1)
-        return r;
+    r = ne_io_read(ctx->io, (unsigned char *) str, length);
+    if (r != 1)
+      return r;
   }
   str[length] = '\0';
   *val = str;
   return 1;
 }
 
 static int
 ne_read_binary(nestegg * ctx, struct ebml_binary * val, uint64_t length)
@@ -1013,18 +1096,19 @@ ne_read_simple(nestegg * ctx, struct ebm
   case TYPE_STRING:
     r = ne_read_string(ctx, &storage->v.s, length);
     break;
   case TYPE_BINARY:
     r = ne_read_binary(ctx, &storage->v.b, length);
     break;
   case TYPE_MASTER:
   case TYPE_UNKNOWN:
+  default:
+    r = 0;
     assert(0);
-    r = 0;
     break;
   }
 
   if (r == 1)
     storage->read = 1;
 
   return r;
 }
@@ -1131,17 +1215,17 @@ ne_xiph_lace_value(unsigned char ** np)
   }
 
   *np = p;
 
   return value;
 }
 
 static int
-ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed)
+ne_read_xiph_lace_value(struct nestegg_io_buf * io, uint64_t * value, size_t * consumed)
 {
   int r;
   uint64_t lace;
 
   r = ne_read_uint(io, &lace, 1);
   if (r != 1)
     return r;
   *consumed += 1;
@@ -1154,17 +1238,17 @@ ne_read_xiph_lace_value(nestegg_io * io,
     *consumed += 1;
     *value += lace;
   }
 
   return 1;
 }
 
 static int
-ne_read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes)
+ne_read_xiph_lacing(struct nestegg_io_buf * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes)
 {
   int r;
   size_t i = 0;
   uint64_t sum = 0;
 
   while (--n) {
     r = ne_read_xiph_lace_value(io, &sizes[i], read);
     if (r != 1)
@@ -1177,17 +1261,17 @@ ne_read_xiph_lacing(nestegg_io * io, siz
     return -1;
 
   /* Last frame is the remainder of the block. */
   sizes[i] = block - *read - sum;
   return 1;
 }
 
 static int
-ne_read_ebml_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes)
+ne_read_ebml_lacing(struct nestegg_io_buf * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes)
 {
   int r;
   uint64_t lace, sum, length;
   int64_t slace;
   size_t i = 0;
 
   r = ne_read_vint(io, &lace, &length);
   if (r != 1)
@@ -1787,61 +1871,61 @@ ne_init_cue_points(nestegg * ctx, int64_
  * sniff_buffer. */
 struct sniff_buffer {
   unsigned char const * buffer;
   size_t length;
   int64_t offset;
 };
 
 static int
-ne_buffer_read(void * buffer, size_t length, void * user_data)
+ne_buffer_read(void * buffer, size_t length, void * userdata)
 {
-  struct sniff_buffer * sb = user_data;
+  struct sniff_buffer * sb = userdata;
 
   int rv = 1;
   size_t available = sb->length - sb->offset;
 
   if (available < length)
     return 0;
 
   memcpy(buffer, sb->buffer + sb->offset, length);
   sb->offset += length;
 
   return rv;
 }
 
 static int
-ne_buffer_seek(int64_t offset, int whence, void * user_data)
+ne_buffer_seek(int64_t offset, int whence, void * userdata)
 {
-  struct sniff_buffer * sb = user_data;
+  struct sniff_buffer * sb = userdata;
   int64_t o = sb->offset;
 
   switch(whence) {
-    case NESTEGG_SEEK_SET: