merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 30 Sep 2014 15:02:58 +0200
changeset 207859 4475aa556e69f7bd69f16263eb108a89252d5035
parent 207775 7c24470b6b3aace8d17bb3c218cd8c6598017245 (current diff)
parent 207858 e0776c837c2b5a2389aef15d97471dbedb1be955 (diff)
child 207921 2ae57957e4bb916f6596f3d1c1c19a1b6399900b
push id27568
push usercbook@mozilla.com
push dateTue, 30 Sep 2014 13:03:13 +0000
treeherdermozilla-central@4475aa556e69 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
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 mozilla-inbound to mozilla-central a=merge
media/libnestegg/README
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -7,24 +7,26 @@
 #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"
@@ -128,19 +130,23 @@ static const GInterfaceInfo atk_if_infos
  */
 struct MaiAtkObject
 {
   AtkObject parent;
   /*
    * The AccessibleWrap whose properties and features are exported
    * via this object instance.
    */
-  AccessibleWrap* accWrap;
+  uintptr_t 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);
@@ -243,17 +249,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 = nullptr;
+            MAI_ATK_OBJECT(mAtkObject)->accWrap = 0;
         }
         SetMaiHyperlink(nullptr);
         g_object_unref(mAtkObject);
         mAtkObject = nullptr;
     }
 }
 
 void
@@ -577,26 +583,25 @@ 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 =
-    static_cast<AccessibleWrap*>(aData);
+  MAI_ATK_OBJECT(aAtkObj)->accWrap = reinterpret_cast<uintptr_t>(aData);
 }
 
 void
 finalizeCB(GObject *aObj)
 {
     if (!IS_MAI_OBJECT(aObj))
         return;
-    NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == nullptr, "AccWrap NOT null");
+    NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == 0, "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*
@@ -658,35 +663,43 @@ getDescriptionCB(AtkObject *aAtkObj)
                                    NS_ConvertUTF16toUTF8(uniDesc).get());
 
     return aAtkObj->description;
 }
 
 AtkRole
 getRoleCB(AtkObject *aAtkObj)
 {
-  AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
-  if (!accWrap)
-    return ATK_ROLE_INVALID;
+  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");
+    NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
+                 "Does not support nsIAccessibleText when it should");
 #endif
 
-  if (aAtkObj->role != ATK_ROLE_INVALID)
-    return aAtkObj->role;
+    role = accWrap->Role();
+  }
 
 #define ROLE(geckoRole, stringRole, atkRole, macRole, \
              msaaRole, ia2Role, nameRule) \
   case roles::geckoRole: \
     aAtkObj->role = atkRole; \
     break;
 
-  switch (accWrap->Role()) {
+  switch (role) {
 #include "RoleMap.h"
     default:
       MOZ_CRASH("Unknown role.");
   };
 
 #undef ROLE
 
   if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1))
@@ -941,31 +954,80 @@ 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);
-  AccessibleWrap* accWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap;
+
+  // 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);
 
   // 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(void);
+  uint16_t CreateMaiInterfaces();
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif /* __NS_ACCESSIBLE_WRAP_H__ */
--- a/accessible/atk/moz.build
+++ b/accessible/atk/moz.build
@@ -30,16 +30,17 @@ 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,32 +8,39 @@
 #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,16 +227,18 @@ 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,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/. */
 
 #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"
@@ -22,16 +23,18 @@
 #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
 ////////////////////////////////////////////////////////////////////////////////
@@ -413,16 +416,22 @@ 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,16 +12,17 @@
 #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
 {
@@ -60,16 +61,35 @@ 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() { }
 
@@ -139,16 +159,21 @@ 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,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/. */
 
 #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;
@@ -550,10 +551,20 @@ 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,19 +1,21 @@
 /* -*- 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
@@ -212,18 +214,29 @@ 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 (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);
+          }
+
           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,16 +2,18 @@
 /* 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.
@@ -42,11 +44,22 @@ 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,17 +778,19 @@ 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
+  KEY = 129,
+
+  LAST_ROLE = KEY
 };
 
 } // namespace role
 
 typedef enum mozilla::a11y::roles::Role role;
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/base/moz.build
+++ b/accessible/base/moz.build
@@ -55,16 +55,17 @@ 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',
@@ -88,8 +89,10 @@ 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/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -235,17 +235,17 @@ Accessible::Description(nsString& aDescr
         }
       }
     }
   }
 
   if (!aDescription.IsEmpty()) {
     aDescription.CompressWhitespace();
     nsAutoString name;
-    ENameValueFlag nameFlag = Name(name);
+    Name(name);
     // Don't expose a description if it is the same as the name.
     if (aDescription.Equals(name))
       aDescription.Truncate();
   }
 }
 
 KeyBinding
 Accessible::AccessKey() const
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.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 "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"
@@ -78,17 +79,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)
+  mPresShell(aPresShell), mIPCDoc(nullptr)
 {
   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
@@ -468,16 +469,22 @@ 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
 
@@ -1431,16 +1438,23 @@ 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,16 +28,17 @@ 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,
@@ -515,16 +516,30 @@ 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:
@@ -637,16 +652,19 @@ 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,16 +23,17 @@ 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']:
@@ -49,8 +50,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co
         '/accessible/mac',
     ]
 else:
     LOCAL_INCLUDES += [
         '/accessible/other',
     ]
 
 FINAL_LIBRARY = 'xul'
+
+include('/ipc/chromium/chromium-config.mozbuild')
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/DocAccessibleChild.cpp
@@ -0,0 +1,40 @@
+/* -*- 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);
+}
+}
+}
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/DocAccessibleChild.h
@@ -0,0 +1,43 @@
+/* -*- 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
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -0,0 +1,112 @@
+/* -*- 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;
+}
+}
+}
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -0,0 +1,141 @@
+/* -*- 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
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/PDocAccessible.ipdl
@@ -0,0 +1,44 @@
+/* -*- 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);
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/ProxyAccessible.cpp
@@ -0,0 +1,42 @@
+/* -*- 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;
+  }
+}
+}
+}
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/ProxyAccessible.h
@@ -0,0 +1,77 @@
+/* -*- 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
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/moz.build
@@ -0,0 +1,28 @@
+# -*- 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/jsat/content-script.js
+++ b/accessible/jsat/content-script.js
@@ -15,16 +15,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'EventManager',
   'resource://gre/modules/accessibility/EventManager.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'ContentControl',
   'resource://gre/modules/accessibility/ContentControl.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Roles',
   'resource://gre/modules/accessibility/Constants.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'States',
+  'resource://gre/modules/accessibility/Constants.jsm');
 
 Logger.debug('content-script.js');
 
 let eventManager = null;
 let contentControl = null;
 
 function forwardToParent(aMessage) {
   // XXX: This is a silly way to make a deep copy
@@ -137,17 +139,30 @@ addMessageListener(
     contentControl.start();
 
     if (!eventManager) {
       eventManager = new EventManager(this, contentControl);
     }
     eventManager.inTest = m.json.inTest;
     eventManager.start();
 
-    sendAsyncMessage('AccessFu:ContentStarted');
+    function contentStarted() {
+      let accDoc = Utils.AccRetrieval.getAccessibleFor(content.document);
+      if (accDoc && !Utils.getState(accDoc).contains(States.BUSY)) {
+        sendAsyncMessage('AccessFu:ContentStarted');
+      } else {
+        content.setTimeout(contentStarted, 0);
+      }
+    }
+
+    if (m.json.inTest) {
+      // During a test we want to wait for the document to finish loading for
+      // consistency.
+      contentStarted();
+    }
   });
 
 addMessageListener(
   'AccessFu:Stop',
   function(m) {
     Logger.debug('AccessFu:Stop');
 
     removeMessageListener('AccessFu:ContextMenu', activateContextMenu);
--- a/accessible/mac/Platform.mm
+++ b/accessible/mac/Platform.mm
@@ -28,16 +28,25 @@ 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', 'jsat', 'xpcom']
+DIRS += ['base', 'generic', 'html', 'interfaces', 'ipc', 'jsat', 'xpcom']
 
 if CONFIG['MOZ_XUL']:
     DIRS += ['xul']
 
 TEST_DIRS += ['tests/mochitest']
--- a/accessible/other/Platform.cpp
+++ b/accessible/other/Platform.cpp
@@ -13,8 +13,18 @@ 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,8 +29,17 @@ a11y::PlatformInit()
 void
 a11y::PlatformShutdown()
 {
   ::DestroyCaret();
 
   nsWinUtils::ShutdownWindowEmulation();
 }
 
+void
+a11y::ProxyCreated(ProxyAccessible*)
+{
+}
+
+void
+a11y::ProxyDestroyed(ProxyAccessible*)
+{
+}
--- a/b2g/app/B2GLoader.cpp
+++ b/b2g/app/B2GLoader.cpp
@@ -21,33 +21,36 @@
 #include <sys/socket.h>
 
 #include <dlfcn.h>
 
 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
 
 #define ASSERT(x) if (!(x)) { MOZ_CRASH(); }
 
-
 // Functions being loaded by XPCOMGlue
 XRE_ProcLoaderServiceRunType XRE_ProcLoaderServiceRun;
 XRE_ProcLoaderClientInitType XRE_ProcLoaderClientInit;
 XRE_ProcLoaderPreloadType XRE_ProcLoaderPreload;
 extern XRE_CreateAppDataType XRE_CreateAppData;
 extern XRE_GetFileFromPathType XRE_GetFileFromPath;
 
 static const nsDynamicFunctionLoad kXULFuncs[] = {
   { "XRE_ProcLoaderServiceRun", (NSFuncPtr*) &XRE_ProcLoaderServiceRun },
   { "XRE_ProcLoaderClientInit", (NSFuncPtr*) &XRE_ProcLoaderClientInit },
   { "XRE_ProcLoaderPreload", (NSFuncPtr*) &XRE_ProcLoaderPreload },
   { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
   { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
   { nullptr, nullptr }
 };
 
+typedef mozilla::Vector<int> FdArray;
+static const int kReservedFileDescriptors = 5;
+static const int kBeginReserveFileDescriptor = STDERR_FILENO + 1;
+
 static int
 GetDirnameSlash(const char *aPath, char *aOutDir, int aMaxLen)
 {
   char *lastSlash = strrchr(aPath, XPCOM_FILE_PATH_SEPARATOR[0]);
   if (lastSlash == nullptr) {
     return 0;
   }
   int cpsz = lastSlash - aPath + 1; // include slash
@@ -64,17 +67,17 @@ GetXPCOMPath(const char *aProgram, char 
 {
   nsAutoArrayPtr<char> progBuf(new char[aMaxLen]);
   nsresult rv = mozilla::BinaryPath::Get(aProgram, progBuf);
   NS_ENSURE_SUCCESS(rv, false);
 
   int len = GetDirnameSlash(progBuf, aOutPath, aMaxLen);
   NS_ENSURE_TRUE(!!len, false);
 
-  NS_ENSURE_TRUE((len + sizeof(XPCOM_DLL)) < aMaxLen, false);
+  NS_ENSURE_TRUE((len + sizeof(XPCOM_DLL)) < (unsigned)aMaxLen, false);
   char *afterSlash = aOutPath + len;
   strcpy(afterSlash, XPCOM_DLL);
   return true;
 }
 
 static bool
 LoadLibxul(const char *aXPCOMPath)
 {
@@ -176,17 +179,17 @@ LoadStaticData(int argc, const char *arg
 }
 
 /**
  * Fork and run parent and child process.
  *
  * The parent is the b2g process and child for Nuwa.
  */
 static int
-RunProcesses(int argc, const char *argv[])
+RunProcesses(int argc, const char *argv[], FdArray& aReservedFds)
 {
   /*
    * The original main() of the b2g process.  It is renamed to
    * b2g_main() for the b2g loader.
    */
   int b2g_main(int argc, const char *argv[]);
 
   int ipcSockets[2] = {-1, -1};
@@ -207,42 +210,82 @@ RunProcesses(int argc, const char *argv[
   close(isChildProcess ? parentSock : childSock);
 
   if (isChildProcess) {
     /* The Nuwa process */
     /* This provides the IPC service of loading Nuwa at the process.
      * The b2g process would send a IPC message of loading Nuwa
      * as the replacement of forking and executing plugin-container.
      */
-    return XRE_ProcLoaderServiceRun(getppid(), childSock, argc, argv);
+    return XRE_ProcLoaderServiceRun(getppid(), childSock, argc, argv,
+                                    aReservedFds);
   }
 
   // The b2g process
   int childPid = pid;
-  XRE_ProcLoaderClientInit(childPid, parentSock);
+  XRE_ProcLoaderClientInit(childPid, parentSock, aReservedFds);
   return b2g_main(argc, argv);
 }
 
 /**
+ * Reserve the file descriptors that shouldn't be taken for other use for the
+ * child process.
+ */
+static void
+ReserveFileDescriptors(FdArray& aReservedFds)
+{
+  for (int i = 0; i < kReservedFileDescriptors; i++) {
+    struct stat fileState;
+    int target = kBeginReserveFileDescriptor + i;
+    if (fstat(target, &fileState) == 0) {
+      MOZ_CRASH("ProcLoader error: a magic file descriptor is occupied.");
+    }
+
+    int fd = open("/dev/null", O_RDWR);
+    if (fd == -1) {
+      MOZ_CRASH("ProcLoader error: failed to reserve a magic file descriptor.");
+    }
+
+    aReservedFds.append(target);
+
+    if (fd == target) {
+      // No need to call dup2(). We already occupy the desired file descriptor.
+      continue;
+    }
+
+    if (dup2(fd, target)) {
+      MOZ_CRASH("ProcLoader error: failed to reserve a magic file descriptor.");
+    }
+
+    close(fd);
+  }
+}
+
+/**
  * B2G Loader is responsible for loading the b2g process and the
  * Nuwa process.  It forks into the parent process, for the b2g
  * process, and the child process, for the Nuwa process.
  *
  * The loader loads libxul and performs initialization of static data
  * before forking, so relocation of libxul and static data can be
  * shared between the b2g process, the Nuwa process, and the content
  * processes.
  */
 int
 main(int argc, const char* argv[])
 {
-  const char *program = argv[0];
+  /**
+   * Reserve file descriptors before loading static data.
+   */
+  FdArray reservedFds;
+  ReserveFileDescriptors(reservedFds);
+
   /*
    * Before fork(), libxul and static data of Gecko are loaded for
    * sharing.
    */
   bool ok = LoadStaticData(argc, argv);
   if (!ok) {
     return 255;
   }
 
-  return RunProcesses(argc, argv);
+  return RunProcesses(argc, argv, reservedFds);
 }
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -672,16 +672,18 @@ pref("javascript.options.mem.gc_min_empt
 #else
 pref("javascript.options.mem.gc_min_empty_chunk_count", 0);
 #endif
 pref("javascript.options.mem.gc_max_empty_chunk_count", 2);
 
 // Show/Hide scrollbars when active/inactive
 pref("ui.showHideScrollbars", 1);
 pref("ui.useOverlayScrollbars", 1);
+pref("ui.scrollbarFadeBeginDelay", 450);
+pref("ui.scrollbarFadeDuration", 200);
 
 // Enable the ProcessPriorityManager, and give processes with no visible
 // documents a 1s grace period before they're eligible to be marked as
 // background. Background processes that are perceivable due to playing
 // media are given a longer grace period to accomodate changing tracks, etc.
 pref("dom.ipc.processPriorityManager.enabled", true);
 pref("dom.ipc.processPriorityManager.backgroundGracePeriodMS", 1000);
 pref("dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS", 5000);
--- a/b2g/chrome/content/devtools/hud.js
+++ b/b2g/chrome/content/devtools/hud.js
@@ -264,16 +264,17 @@ let consoleWatcher = {
     errors: false,
     security: false
   },
   _security: [
     'Mixed Content Blocker',
     'Mixed Content Message',
     'CSP',
     'Invalid HSTS Headers',
+    'Invalid HPKP Headers',
     'Insecure Password Field',
     'SSL',
     'CORS'
   ],
 
   init: function cw_init(client) {
     this._client = client;
     this.consoleListener = this.consoleListener.bind(this);
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1172,26 +1172,19 @@ pref("toolbar.customization.usesheet", f
 #ifdef XP_MACOSX
 // On mac, the default pref is per-architecture
 pref("dom.ipc.plugins.enabled.i386", true);
 pref("dom.ipc.plugins.enabled.x86_64", true);
 #else
 pref("dom.ipc.plugins.enabled", true);
 #endif
 
-#if defined(NIGHTLY_BUILD)
-// browser.tabs.remote is enabled on nightly. However, users won't
-// actually get remote tabs unless they enable
-// browser.tabs.remote.autostart or they use the "New OOP Window" menu
-// option.
-pref("browser.tabs.remote", true);
-#else
-pref("browser.tabs.remote", false);
-#endif
+// Start the browser in e10s mode
 pref("browser.tabs.remote.autostart", false);
+pref("browser.tabs.remote.desktopbehavior", true);
 
 #if defined(MOZ_CONTENT_SANDBOX) && defined(XP_WIN)
 // This controls whether the content process on Windows is sandboxed.
 // You also need to be using remote tabs, see above.
 // on = full sandbox enabled
 // warn = warn only sandbox enabled
 // anything else = sandbox disabled
 // This will probably require a restart.
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6787,21 +6787,21 @@ var gIdentityHandler = {
     this._identityPopup.addEventListener("blur", this, true);
     this._identityPopup.addEventListener("popuphidden", this);
   },
 
   onDragStart: function (event) {
     if (gURLBar.getAttribute("pageproxystate") != "valid")
       return;
 
-    var value = content.location.href;
-    var urlString = value + "\n" + content.document.title;
-    var htmlString = "<a href=\"" + value + "\">" + value + "</a>";
-
-    var dt = event.dataTransfer;
+    let value = gBrowser.currentURI.spec;
+    let urlString = value + "\n" + gBrowser.contentTitle;
+    let htmlString = "<a href=\"" + value + "\">" + value + "</a>";
+
+    let dt = event.dataTransfer;
     dt.setData("text/x-moz-url", urlString);
     dt.setData("text/uri-list", value);
     dt.setData("text/plain", value);
     dt.setData("text/html", htmlString);
     dt.setDragImage(gProxyFavIcon, 16, 16);
   },
  
   handleEvent: function (event) {
@@ -6947,30 +6947,26 @@ let gPrivateBrowsingUI = {
 };
 
 let gRemoteTabsUI = {
   init: function() {
     if (window.location.href != getBrowserURL()) {
       return;
     }
 
-    let remoteTabs = Services.appinfo.browserTabsRemote;
-    let autostart = Services.appinfo.browserTabsRemoteAutostart;
-
     let newRemoteWindow = document.getElementById("menu_newRemoteWindow");
     let newNonRemoteWindow = document.getElementById("menu_newNonRemoteWindow");
-
-    if (!remoteTabs) {
-      newRemoteWindow.hidden = true;
-      newNonRemoteWindow.hidden = true;
-      return;
-    }
-
+#ifdef E10S_TESTING_ONLY
+    let autostart = Services.appinfo.browserTabsRemoteAutostart;
     newRemoteWindow.hidden = autostart;
     newNonRemoteWindow.hidden = !autostart;
+#else
+    newRemoteWindow.hidden = true;
+    newNonRemoteWindow.hidden = true;
+#endif
   }
 };
 
 /**
  * Switch to a tab that has a given URI, and focusses its browser window.
  * If a matching tab is in this window, it will be switched to. Otherwise, other
  * windows will be searched.
  *
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -497,17 +497,24 @@ nsContextMenu.prototype = {
   },
 
   inspectNode: function CM_inspectNode() {
     let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
     let gBrowser = this.browser.ownerDocument.defaultView.gBrowser;
     let tt = devtools.TargetFactory.forTab(gBrowser.selectedTab);
     return gDevTools.showToolbox(tt, "inspector").then(function(toolbox) {
       let inspector = toolbox.getCurrentPanel();
-      inspector.selection.setNode(this.target, "browser-context-menu");
+      if (this.isRemote) {
+        this.browser.messageManager.sendAsyncMessage("debug:inspect", {}, {node: this.target});
+        inspector.walker.findInspectingNode().then(nodeFront => {
+          inspector.selection.setNodeFront(nodeFront, "browser-context-menu");
+        });
+      } else {
+        inspector.selection.setNode(this.target, "browser-context-menu");
+      }
     }.bind(this));
   },
 
   // Set various context menu attributes based on the state of the world.
   setTarget: function (aNode, aRangeParent, aRangeOffset) {
     // If gContextMenuContentData is not null, this event was forwarded from a
     // child process, so use that information instead.
     if (gContextMenuContentData) {
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2558,17 +2558,16 @@
         <parameter name="aTab"/>
         <body>
           <![CDATA[
             let url = aTab.linkedBrowser.currentURI.spec;
             return window.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no,non-remote", url);
           ]]>
         </body>
       </method>
-#endif
 
       <method name="moveTabTo">
         <parameter name="aTab"/>
         <parameter name="aIndex"/>
         <body>
         <![CDATA[
           var oldPosition = aTab._tPos;
           if (oldPosition == aIndex)
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -60,16 +60,17 @@ support-files =
   get_user_media.html
   head.js
   healthreport_testRemoteCommands.html
   moz.png
   offlineQuotaNotification.cacheManifest
   offlineQuotaNotification.html
   page_style_sample.html
   parsingTestHelpers.jsm
+  pinning_headers.sjs
   popup_blocker.html
   print_postdata.sjs
   redirect_bug623155.sjs
   searchSuggestionEngine.sjs
   searchSuggestionEngine.xml
   test-mixedcontent-securityerrors.html
   test_bug435035.html
   test_bug462673.html
@@ -488,9 +489,10 @@ skip-if = e10s
 [browser_bug1024133-switchtab-override-keynav.js]
 skip-if = e10s
 [browser_bug1025195_switchToTabHavingURI_ignoreFragment.js]
 [browser_addCertException.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (content.document.getElementById)
 [browser_bug1045809.js]
 skip-if = e10s # Bug 1068360 - [e10s] Mixed content blocker doorhanger doesn't work
 [browser_e10s_switchbrowser.js]
-
+[browser_blockHPKP.js]
+skip-if = e10s # bug ?????? - test directly manipulates content (content.document.getElementById)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_blockHPKP.js
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Test that visiting a site pinned with HPKP headers does not succeed when it
+// uses a certificate with a key not in the pinset. This should result in an
+// about:neterror page
+// Also verify that removal of the HPKP headers succeeds (via HPKP headers)
+// and that after removal the visit to the site with the previously
+// unauthorized pins succeeds.
+//
+// This test required three certs to be created in build/pgo/certs:
+// 1. A new trusted root:
+//   a. certutil -S -s "Alternate trusted authority" -s "CN=Alternate Trusted Authority" -t "C,," -x -m 1 -v 120 -n "alternateTrustedAuthority" -Z SHA256 -g 2048 -2 -d .
+//   b. (export) certutil -L -d . -n "alternateTrustedAuthority" -a -o alternateroot.ca
+//     (files ended in .ca are added as trusted roots by the mochitest harness)
+// 2. A good pinning server cert (signed by the pgo root):
+//   certutil -S -n "dynamicPinningGood" -s "CN=dynamic-pinning.example.com" -c "pgo temporary ca" -t "P,," -k rsa -g 2048 -Z SHA256 -m 8939454 -v 120 -8 "*.include-subdomains.pinning-dynamic.example.com,*.pinning-dynamic.example.com" -d .
+// 3. A certificate with a different issuer, so as to cause a key pinning violation."
+//   certutil -S -n "dynamicPinningBad" -s "CN=bad.include-subdomains.pinning-dynamic.example.com" -c "alternateTrustedAuthority" -t "P,," -k rsa -g 2048 -Z SHA256 -m 893945439 -v 120 -8 "bad.include-subdomains.pinning-dynamic.example.com" -d .
+
+const gSSService = Cc["@mozilla.org/ssservice;1"]
+                     .getService(Ci.nsISiteSecurityService);
+const gIOService = Cc["@mozilla.org/network/io-service;1"]
+                    .getService(Ci.nsIIOService);
+
+const kPinningDomain = "include-subdomains.pinning-dynamic.example.com";
+const khpkpPinninEnablePref = "security.cert_pinning.process_headers_from_non_builtin_roots";
+const kpkpEnforcementPref = "security.cert_pinning.enforcement_level";
+const kBadPinningDomain = "bad.include-subdomains.pinning-dynamic.example.com";
+const kURLPath = "/browser/browser/base/content/test/general/pinning_headers.sjs?";
+
+function test() {
+  waitForExplicitFinish();
+  // Enable enforcing strict pinning and processing headers from
+  // non-builtin roots.
+  Services.prefs.setIntPref(kpkpEnforcementPref, 2);
+  Services.prefs.setBoolPref(khpkpPinninEnablePref, true);
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref(kpkpEnforcementPref);
+    Services.prefs.clearUserPref(khpkpPinninEnablePref);
+    let uri = gIOService.newURI("https://" + kPinningDomain, null, null);
+    gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
+  });
+  whenNewTabLoaded(window, loadPinningPage);
+}
+
+// Start by making a successful connection to a domain that will pin a site
+function loadPinningPage() {
+  gBrowser.selectedBrowser.addEventListener("load",
+                                             successfulPinningPageListener,
+                                             true);
+
+  gBrowser.selectedBrowser.loadURI("https://" + kPinningDomain + kURLPath + "valid");
+}
+
+// After the site is pinned try to load with a subdomain site that should
+// fail to validate
+let successfulPinningPageListener = {
+  handleEvent: function() {
+    gBrowser.selectedBrowser.removeEventListener("load", this, true);
+    gBrowser.addProgressListener(certErrorProgressListener);
+    gBrowser.selectedBrowser.loadURI("https://" + kBadPinningDomain);
+  }
+};
+
+// The browser should load about:neterror, when this happens, proceed
+// to load the pinning domain again, this time removing the pinning information
+let certErrorProgressListener = {
+  buttonClicked: false,
+  onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
+    if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
+      let self = this;
+      // Can't directly call button.click() in onStateChange
+      executeSoon(function() {
+        let button =   content.document.getElementById("errorTryAgain");
+        // If about:neterror hasn't fully loaded, the button won't be present.
+        // It will eventually be there, however.
+        if (button && !self.buttonClicked) {
+          gBrowser.removeProgressListener(self);
+          gBrowser.selectedBrowser.addEventListener("load",
+                                                    successfulPinningRemovalPageListener,
+                                                    true);
+          gBrowser.selectedBrowser.loadURI("https://" + kPinningDomain + kURLPath + "zeromaxagevalid");
+        }
+      });
+    }
+  }
+};
+
+// After the pinning information has been removed (successful load) proceed
+// to load again with the invalid pin domain.
+let successfulPinningRemovalPageListener = {
+  handleEvent: function() {
+    gBrowser.selectedBrowser.removeEventListener("load", this, true);
+    gBrowser.selectedBrowser.addEventListener("load",
+                                              successfulLoadListener,
+                                              true);
+
+    gBrowser.selectedBrowser.loadURI("https://" + kBadPinningDomain);
+  }
+};
+
+// Finally, we should successfully load
+// https://bad.include-subdomains.pinning-dynamic.example.com.
+let successfulLoadListener = {
+  handleEvent: function() {
+    gBrowser.selectedBrowser.removeEventListener("load", this, true);
+    gBrowser.removeTab(gBrowser.selectedTab);
+    ok(true, "load complete");
+    finish();
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/pinning_headers.sjs
@@ -0,0 +1,23 @@
+const INVALIDPIN1 = "pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\";";
+const INVALIDPIN2 = "pin-sha256=\"AAAAAAAAAAAAAAAAAAAAAAAAAj0e1Md7GkYYkVoZWmM=\";";
+const VALIDPIN = "pin-sha256=\"hXweb81C3HnmM2Ai1dnUzFba40UJMhuu8qZmvN/6WWc=\";";
+
+function handleRequest(request, response)
+{
+  // avoid confusing cache behaviors
+  response.setHeader("Cache-Control", "no-cache", false);
+
+  response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
+  switch (request.queryString) {
+    case "zeromaxagevalid":
+      response.setHeader("Public-Key-Pins", "max-age=0;" + VALIDPIN +
+                                            INVALIDPIN2 + "includeSubdomains");
+      break;
+    case "valid":
+    default:
+      response.setHeader("Public-Key-Pins", "max-age=50000;" + VALIDPIN +
+                                            INVALIDPIN2 + "includeSubdomains");
+  }
+
+  response.write("Hello world!" + request.host);
+}
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -1038,38 +1038,36 @@ if (Services.prefs.getBoolPref("privacy.
       forgetButton.removeEventListener("command", this);
       this._updateHeights(view, false);
     },
   });
 }
 
 #ifdef E10S_TESTING_ONLY
 /**
- * The e10s button's purpose is to lower the barrier of entry
- * for our Nightly testers to use e10s windows. We'll be removing it
- * once remote tabs are enabled. This button should never ever make it
- * to production. If it does, that'd be bad, and we should all feel bad.
- */
-if (Services.prefs.getBoolPref("browser.tabs.remote")) {
-  let getCommandFunction = function(aOpenRemote) {
-    return function(aEvent) {
-      let win = aEvent.view;
-      if (win && typeof win.OpenBrowserWindow == "function") {
-        win.OpenBrowserWindow({remote: aOpenRemote});
-      }
-    };
-  }
+  * The e10s button's purpose is to lower the barrier of entry
+  * for our Nightly testers to use e10s windows. We'll be removing it
+  * once remote tabs are enabled. This button should never ever make it
+  * to production. If it does, that'd be bad, and we should all feel bad.
+  */
+let getCommandFunction = function(aOpenRemote) {
+  return function(aEvent) {
+    let win = aEvent.view;
+    if (win && typeof win.OpenBrowserWindow == "function") {
+      win.OpenBrowserWindow({remote: aOpenRemote});
+    }
+  };
+}
 
-  let openRemote = !Services.appinfo.browserTabsRemoteAutostart;
-  // Like the XUL menuitem counterparts, we hard-code these strings in because
-  // this button should never roll into production.
-  let buttonLabel = openRemote ? "New e10s Window"
-                               : "New Non-e10s Window";
+let openRemote = !Services.appinfo.browserTabsRemoteAutostart;
+// Like the XUL menuitem counterparts, we hard-code these strings in because
+// this button should never roll into production.
+let buttonLabel = openRemote ? "New e10s Window"
+                              : "New Non-e10s Window";
 
-  CustomizableWidgets.push({
-    id: "e10s-button",
-    label: buttonLabel,
-    tooltiptext: buttonLabel,
-    defaultArea: CustomizableUI.AREA_PANEL,
-    onCommand: getCommandFunction(openRemote),
-  });
-}
+CustomizableWidgets.push({
+  id: "e10s-button",
+  label: buttonLabel,
+  tooltiptext: buttonLabel,
+  defaultArea: CustomizableUI.AREA_PANEL,
+  onCommand: getCommandFunction(openRemote),
+});
 #endif
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -11,16 +11,21 @@ Cu.import("resource:///modules/Customiza
 let {Promise, CustomizableUI} = tmp;
 
 let ChromeUtils = {};
 Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", ChromeUtils);
 
 Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
 registerCleanupFunction(() => Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck"));
 
+// Remove temporary e10s related new window options in customize ui,
+// they break a lot of tests.
+CustomizableUI.destroyWidget("e10s-button");
+CustomizableUI.removeWidgetFromArea("e10s-button");
+
 let {synthesizeDragStart, synthesizeDrop} = ChromeUtils;
 
 const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const kTabEventFailureTimeoutInMs = 20000;
 
 function createDummyXULButton(id, label) {
   let btn = document.createElementNS(kNSXUL, "toolbarbutton");
   btn.id = id;
--- a/browser/devtools/styleinspector/test/head.js
+++ b/browser/devtools/styleinspector/test/head.js
@@ -104,26 +104,17 @@ function addTab(url) {
   let def = promise.defer();
 
   window.focus();
 
   let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
   let browser = tab.linkedBrowser;
 
   info("Loading the helper frame script " + FRAME_SCRIPT_URL);
-  // Bug 687194 - Mochitest registers its chrome URLs after browser
-  // initialization, so the content processes don't pick them up. That
-  // means we can't load our frame script from its chrome URI, because
-  // the content process won't be able to find it.
-  // Instead, we resolve the chrome URI for the script to a file URI, which
-  // we can then pass to the content process, which it is able to find.
-  let registry = Cc['@mozilla.org/chrome/chrome-registry;1']
-    .getService(Ci.nsIChromeRegistry);
-  let fileURI = registry.convertChromeURL(Services.io.newURI(FRAME_SCRIPT_URL, null, null)).spec;
-  browser.messageManager.loadFrameScript(fileURI, false);
+  browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
 
   browser.addEventListener("load", function onload() {
     browser.removeEventListener("load", onload, true);
     info("URL '" + url + "' loading complete");
 
     def.resolve(tab);
   }, true);
 
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -4669,16 +4669,17 @@ var Utils = {
       return CATEGORY_CSS;
     }
 
     switch (category) {
       case "Mixed Content Blocker":
       case "Mixed Content Message":
       case "CSP":
       case "Invalid HSTS Headers":
+      case "Invalid HPKP Headers":
       case "Insecure Password Field":
       case "SSL":
       case "CORS":
       case "Iframe Sandbox":
         return CATEGORY_SECURITY;
 
       default:
         return CATEGORY_JS;
--- a/browser/metro/base/content/browser.js
+++ b/browser/metro/base/content/browser.js
@@ -1446,17 +1446,17 @@ Tab.prototype = {
     let notification = this._notification = document.createElement("notificationbox");
 
     let browser = this._browser = document.createElement("browser");
     browser.id = "browser-" + this._id;
     this._chromeTab.linkedBrowser = browser;
 
     browser.setAttribute("type", "content-targetable");
 
-    let useRemote = Services.appinfo.browserTabsRemote;
+    let useRemote = Services.appinfo.browserTabsRemoteAutostart;
     let useLocal = Util.isLocalScheme(aURI);
     browser.setAttribute("remote", (!useLocal && useRemote) ? "true" : "false");
 
     // Append the browser to the document, which should start the page load
     let stack = document.createElementNS(XUL_NS, "stack");
     stack.className = "browserStack";
     stack.appendChild(browser);
     stack.setAttribute("flex", "1");
--- a/browser/metro/profile/metro.js
+++ b/browser/metro/profile/metro.js
@@ -89,18 +89,16 @@ pref("toolkit.browser.cacheRatioHeight",
 // How long before a content view (a handle to a remote scrollable object)
 // expires.
 pref("toolkit.browser.contentViewExpire", 3000);
 
 
 pref("toolkit.defaultChromeURI", "chrome://browser/content/browser.xul");
 pref("browser.chromeURL", "chrome://browser/content/");
 
-pref("browser.tabs.remote", false);
-
 // Telemetry
 #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
 pref("toolkit.telemetry.enabledPreRelease", true);
 #else
 pref("toolkit.telemetry.enabled", true);
 #endif
 pref("toolkit.telemetry.prompted", 2);
 
new file mode 100644
--- /dev/null
+++ b/build/pgo/certs/alternateroot.ca
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2jCCAcKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDExtBbHRl
+cm5hdGUgVHJ1c3RlZCBBdXRob3JpdHkwHhcNMTQwOTI1MjEyMTU0WhcNMjQwOTI1
+MjEyMTU0WjAmMSQwIgYDVQQDExtBbHRlcm5hdGUgVHJ1c3RlZCBBdXRob3JpdHkw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBT+BwAhO52IWgSIdZZifU
+9LHOs3IR/+8DCC0WP5d/OuyKlZ6Rqd0tsd3i7durhQyjHSbLf2lJStcnFjcVEbEn
+NI76RuvlN8xLLn5eV+2Ayr4cZYKztudwRmw+DV/iYAiMSy0hs7m3ssfX7qpoi1aN
+RjUanwU0VTCPQhF1bEKAC2du+C5Z8e92zN5t87w7bYr7lt+m8197XliXEu+0s9Rg
+nGwGaZ296BIRz6NOoJYTa43n06LU1I1+Z4d6lPdzUFrSR0GBaMhUSurUBtOin3yW
+iMhg1VHX/KwqGc4als5GyCVXy8HGrA/0zQPOhetxrlhEVAdK/xBt7CZvByj1Rcc7
+AgMBAAGjEzARMA8GA1UdEwQIMAYBAf8CAQAwDQYJKoZIhvcNAQELBQADggEBAJq/
+hogSRqzPWTwX4wTn/DVSNdWwFLv53qep9YrSMJ8ZsfbfK9Es4VP4dBLRQAVMJ0Z5
+mW1I6d/n0KayTanuUBvemYdxPi/qQNSs8UJcllqdhqWzmzAg6a0LxrMnEeKzPBPD
+6q8PwQ7tYP+B4sBN9tnnsnyPgti9ZiNZn5FwXZliHXseQ7FE9/SqHlLw5LXW3YtK
+juti6RmuV6fq3j+D4oeC5vb1mKgIyoTqGN6ze57v8RHi+pQ8Q+kmoUn/L3Z2YmFe
+4SKN/4WoyXr8TdejpThGOCGCAd3565s5gOx5QfSQX11P8NZKO8hcN0tme3VzmGpH
+K0Z/6MTmdpNaTwQ6odk=
+-----END CERTIFICATE-----
index c56a04063425d15ebef80e5c54417c66b375458e..508b7defb4479958f4530bcdeb01b63c073be182
GIT binary patch
literal 65536
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
z-xbKyc|zn56a3|${C5`s000000000000000000000000000000000000000000000
Y00000000000000000000002h$KaUnv8vp<R
index 5a45b6c4e761fce905755443c48efecf6a89f91b..f3c610fe83155c083cc23beaf04cb0f7d8e85caa
GIT binary patch
literal 98304
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
--- a/build/pgo/server-locations.txt
+++ b/build/pgo/server-locations.txt
@@ -217,8 +217,13 @@ http://example.tw:80                priv
 http://example.cn:80                privileged
 http://example.co.jp:80             privileged
 http://example.fi:80                privileged
 
 # Hosts for testing marketplace apps installations
 https://marketplace.firefox.com:443       privileged
 https://marketplace-dev.allizom.org:443   privileged
 https://marketplace.allizom.org:443       privileged
+
+# Host for HPKP
+https://include-subdomains.pinning-dynamic.example.com:443        privileged,cert=dynamicPinningGood
+https://bad.include-subdomains.pinning-dynamic.example.com:443    privileged,cert=dynamicPinningBad
+
--- a/content/base/test/chrome/test_cpows.xul
+++ b/content/base/test/chrome/test_cpows.xul
@@ -16,15 +16,12 @@
 
   SimpleTest.waitForExplicitFinish();
 
   function done() {
     SimpleTest.finish();
   }
 
   addLoadEvent(function() {
-    // We don't want to set browser.tabs.remote to true, but still have CPOWs enabled.
-    SpecialPowers.pushPrefEnv({"set": [["dom.ipc.cpows.force-enabled", true]]}, function() {
-      window.open("cpows_parent.xul", "", "chrome");
-    });
+    window.open("cpows_parent.xul", "", "chrome");
   });
   ]]></script>
 </window>
--- a/content/html/content/public/HTMLMediaElement.h
+++ b/content/html/content/public/HTMLMediaElement.h
@@ -157,25 +157,19 @@ public:
   virtual void NotifyOwnerDocumentActivityChanged();
 
   // Called by the video decoder object, on the main thread,
   // when it has read the metadata containing video dimensions,
   // etc.
   virtual void MetadataLoaded(const MediaInfo* aInfo,
                               const MetadataTags* aTags) MOZ_FINAL MOZ_OVERRIDE;
 
-  // Called by the video decoder object, on the main thread,
-  // when it has read the first frame of the video
-  // aResourceFullyLoaded should be true if the resource has been
-  // fully loaded and the caller will call ResourceLoaded next.
-  virtual void FirstFrameLoaded(bool aResourceFullyLoaded) MOZ_FINAL MOZ_OVERRIDE;
-
-  // Called by the video decoder object, on the main thread,
-  // when the resource has completed downloading.
-  virtual void ResourceLoaded() MOZ_FINAL MOZ_OVERRIDE;
+  // Called by the decoder object, on the main thread,
+  // when it has read the first frame of the video or audio.
+  virtual void FirstFrameLoaded() MOZ_FINAL MOZ_OVERRIDE;
 
   // Called by the video decoder object, on the main thread,
   // when the resource has a network error during loading.
   virtual void NetworkError() MOZ_FINAL MOZ_OVERRIDE;
 
   // Called by the video decoder object, on the main thread, when the
   // resource has a decode error during metadata loading or decoding.
   virtual void DecodeError() MOZ_FINAL MOZ_OVERRIDE;
@@ -205,16 +199,19 @@ public:
   // has been resumed by the cache or because the element itself
   // asked the decoder to resumed the download.
   // If aForceNetworkLoading is True, ignore the fact that the download has
   // previously finished. We are downloading the middle of the media after
   // having downloaded the end, we need to notify the element a download in
   // ongoing.
   virtual void DownloadResumed(bool aForceNetworkLoading = false) MOZ_FINAL MOZ_OVERRIDE;
 
+  // Called to indicate the download is progressing.
+  virtual void DownloadProgressed() MOZ_FINAL MOZ_OVERRIDE;
+
   // Called by the media decoder to indicate that the download has stalled
   // (no data has arrived for a while).
   virtual void DownloadStalled() MOZ_FINAL MOZ_OVERRIDE;
 
   // Called by the media decoder to indicate whether the media cache has
   // suspended the channel.
   virtual void NotifySuspendedByCache(bool aIsSuspended) MOZ_FINAL MOZ_OVERRIDE;
 
@@ -233,20 +230,16 @@ public:
 
   // Called by the decoder when some data has been downloaded or
   // buffering/seeking has ended. aNextFrameAvailable is true when
   // the data for the next frame is available. This method will
   // decide whether to set the ready state to HAVE_CURRENT_DATA,
   // HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA.
   virtual void UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatus aNextFrame) MOZ_FINAL MOZ_OVERRIDE;
 
-  // Use this method to change the mReadyState member, so required
-  // events can be fired.
-  void ChangeReadyState(nsMediaReadyState aState);
-
   // Return true if we can activate autoplay assuming enough data has arrived.
   bool CanActivateAutoplay();
 
   // Notify that state has changed that might cause an autoplay element to
   // start playing.
   // If the element is 'autoplay' and is ready to play back (not paused,
   // autoplay pref enabled, etc), it should start playing back.
   void CheckAutoplayDataReady();
@@ -535,17 +528,17 @@ public:
 
   // XPCOM MozPreservesPitch() is OK
 
 #ifdef MOZ_EME
   MediaKeys* GetMediaKeys() const;
 
   already_AddRefed<Promise> SetMediaKeys(MediaKeys* mediaKeys,
                                          ErrorResult& aRv);
-  
+
   MediaWaitingFor WaitingFor() const;
 
   mozilla::dom::EventHandlerNonNull* GetOnencrypted();
   void SetOnencrypted(mozilla::dom::EventHandlerNonNull* listener);
 
   void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
                          const nsAString& aInitDataType);
 
@@ -643,16 +636,27 @@ protected:
     void UpdateWakeLock();
 
     bool mValue;
     bool mCanPlay;
     HTMLMediaElement* mOuter;
     nsCOMPtr<nsITimer> mTimer;
   };
 
+  /** Use this method to change the mReadyState member, so required
+   * events can be fired.
+   */
+  void ChangeReadyState(nsMediaReadyState aState);
+
+  /**
+   * Use this method to change the mNetworkState member, so required
+   * actions will be taken during the transition.
+   */
+  void ChangeNetworkState(nsMediaNetworkState aState);
+
   /**
    * These two methods are called by the WakeLockBoolWrapper when the wakelock
    * has to be created or released.
    */
   virtual void WakeLockCreate();
   virtual void WakeLockRelease();
   nsRefPtr<WakeLock> mWakeLock;
 
@@ -928,17 +932,17 @@ protected:
   // This method does the check for muting/fading/unmuting the audio channel.
   nsresult UpdateChannelMuteState(mozilla::dom::AudioChannelState aCanPlay);
 
   // Seeks to aTime seconds. aSeekType can be Exact to seek to exactly the
   // seek target, or PrevSyncPoint if a quicker but less precise seek is
   // desired, and we'll seek to the sync point (keyframe and/or start of the
   // next block of audio samples) preceeding seek target.
   void Seek(double aTime, SeekTarget::Type aSeekType, ErrorResult& aRv);
-  
+
   // Update the audio channel playing state
   void UpdateAudioChannelPlayingState();
 
   // Adds to the element's list of pending text tracks each text track
   // in the element's list of text tracks whose text track mode is not disabled
   // and whose text track readiness state is loading.
   void PopulatePendingTextTrackList();
 
@@ -1099,19 +1103,18 @@ protected:
 
   // Stores the time at the start of the current 'played' range.
   double mCurrentPlayRangeStart;
 
   // If true then we have begun downloading the media content.
   // Set to false when completed, or not yet started.
   bool mBegun;
 
-  // True when the decoder has loaded enough data to display the
-  // first frame of the content.
-  bool mLoadedFirstFrame;
+  // True if loadeddata has been fired.
+  bool mLoadedDataFired;
 
   // Indicates whether current playback is a result of user action
   // (ie. calling of the Play method), or automatic playback due to
   // the 'autoplay' attribute being set. A true value indicates the
   // latter case.
   // The 'autoplay' HTML attribute indicates that the video should
   // start playing when loaded. The 'autoplay' attribute of the object
   // is a mirror of the HTML attribute. These are different from this
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -613,16 +613,21 @@ HTMLMediaElement::OnChannelRedirect(nsIC
 
   return NS_OK;
 }
 
 void HTMLMediaElement::ShutdownDecoder()
 {
   RemoveMediaElementFromURITable();
   NS_ASSERTION(mDecoder, "Must have decoder to shut down");
+  // TODO: This should be handled by ChangeNetworkState() so we have only one
+  // place to call StopProgress().
+  if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
+    mDecoder->StopProgress();
+  }
   mDecoder->Shutdown();
   mDecoder = nullptr;
 }
 
 void HTMLMediaElement::AbortExistingLoads()
 {
   // Abort any already-running instance of the resource selection algorithm.
   mLoadWaitStatus = NOT_WAITING;
@@ -656,31 +661,31 @@ void HTMLMediaElement::AbortExistingLoad
 
   if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING ||
       mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE)
   {
     DispatchAsyncEvent(NS_LITERAL_STRING("abort"));
   }
 
   mError = nullptr;
-  mLoadedFirstFrame = false;
+  mLoadedDataFired = false;
   mAutoplaying = true;
   mIsLoadingFromSourceChildren = false;
   mSuspendedAfterFirstFrame = false;
   mAllowSuspendAfterFirstFrame = true;
   mHaveQueuedSelectResource = false;
   mSuspendedForPreloadNone = false;
   mDownloadSuspendedByCache = false;
   mSourcePointer = nullptr;
 
   mTags = nullptr;
 
   if (mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
-    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
     NS_ASSERTION(!mDecoder && !mSrcStream, "How did someone setup a new stream/decoder already?");
+    ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
     mPaused = true;
 
     if (fireTimeUpdate) {
       // Since we destroyed the decoder above, the current playback position
       // will now be reported as 0. The playback position was non-zero when
       // we destroyed the decoder, so fire a timeupdate event so that the
       // change will be reflected in the controls.
@@ -696,17 +701,17 @@ void HTMLMediaElement::AbortExistingLoad
   mIsRunningSelectResource = false;
 }
 
 void HTMLMediaElement::NoSupportedMediaSourceError()
 {
   NS_ASSERTION(mDelayingLoadEvent, "Load event not delayed during source selection?");
 
   mError = new MediaError(this, nsIDOMMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
+  ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
   DispatchAsyncEvent(NS_LITERAL_STRING("error"));
   // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
   ChangeDelayLoadStatus(false);
 }
 
 typedef void (HTMLMediaElement::*SyncSectionFn)();
 
 // Runs a "synchronous section", a function that must run once the event loop
@@ -740,28 +745,28 @@ void HTMLMediaElement::RunInStableState(
   nsCOMPtr<nsIRunnable> event = new nsSyncSection(this, aRunnable);
   nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
   appShell->RunInStableState(event);
 }
 
 void HTMLMediaElement::QueueLoadFromSourceTask()
 {
   ChangeDelayLoadStatus(true);
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
+  ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
   RunInStableState(
     NS_NewRunnableMethod(this, &HTMLMediaElement::LoadFromSourceChildren));
 }
 
 void HTMLMediaElement::QueueSelectResourceTask()
 {
   // Don't allow multiple async select resource calls to be queued.
   if (mHaveQueuedSelectResource)
     return;
   mHaveQueuedSelectResource = true;
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
+  ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
   RunInStableState(
     NS_NewRunnableMethod(this, &HTMLMediaElement::SelectResourceWrapper));
 }
 
 /* void load (); */
 NS_IMETHODIMP HTMLMediaElement::Load()
 {
   if (mIsRunningLoadMethod)
@@ -812,25 +817,25 @@ void HTMLMediaElement::SelectResourceWra
 }
 
 void HTMLMediaElement::SelectResource()
 {
   if (!mSrcAttrStream && !HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
       !HasSourceChildren(this)) {
     // The media element has neither a src attribute nor any source
     // element children, abort the load.
-    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
+    ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
     // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
     ChangeDelayLoadStatus(false);
     return;
   }
 
   ChangeDelayLoadStatus(true);
 
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
+  ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
   // Load event was delayed, and still is, so no need to call
   // AddRemoveSelfReference, since it must still be held
   DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
 
   // Delay setting mIsRunningSeletResource until after UpdatePreloadAction
   // so that we don't lose our state change by bailing out of the preload
   // state update
   UpdatePreloadAction();
@@ -916,17 +921,17 @@ void HTMLMediaElement::LoadFromSourceChi
   }
 
   while (true) {
     nsIContent* child = GetNextSource();
     if (!child) {
       // Exhausted candidates, wait for more candidates to be appended to
       // the media element.
       mLoadWaitStatus = WAITING_FOR_SOURCE;
-      mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
+      ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
       ChangeDelayLoadStatus(false);
       ReportLoadError("MediaLoadExhaustedCandidates");
       return;
     }
 
     // Must have src attribute.
     nsAutoString src;
     if (!child->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
@@ -985,29 +990,28 @@ void HTMLMediaElement::LoadFromSourceChi
     DispatchAsyncSourceError(child);
   }
   NS_NOTREACHED("Execution should not reach here!");
 }
 
 void HTMLMediaElement::SuspendLoad()
 {
   mSuspendedForPreloadNone = true;
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
-  DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
+  ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
   ChangeDelayLoadStatus(false);
 }
 
 void HTMLMediaElement::ResumeLoad(PreloadAction aAction)
 {
   NS_ASSERTION(mSuspendedForPreloadNone,
     "Must be halted for preload:none to resume from preload:none suspended load.");
   mSuspendedForPreloadNone = false;
   mPreloadAction = aAction;
   ChangeDelayLoadStatus(true);
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
+  ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
   if (!mIsLoadingFromSourceChildren) {
     // We were loading from the element's src attribute.
     if (NS_FAILED(LoadResource())) {
       NoSupportedMediaSourceError();
     }
   } else {
     // We were loading from a child <source> element. Try to resume the
     // load of that child, and if that fails, try the next child.
@@ -2022,17 +2026,17 @@ HTMLMediaElement::HTMLMediaElement(alrea
     mFragmentStart(-1.0),
     mFragmentEnd(-1.0),
     mDefaultPlaybackRate(1.0),
     mPlaybackRate(1.0),
     mPreservesPitch(true),
     mPlayed(new TimeRanges),
     mCurrentPlayRangeStart(-1.0),
     mBegun(false),
-    mLoadedFirstFrame(false),
+    mLoadedDataFired(false),
     mAutoplaying(true),
     mAutoplayEnabled(true),
     mPaused(true),
     mMuted(0),
     mStatsShowing(false),
     mAllowCasting(false),
     mIsCasting(false),
     mAudioCaptured(false),
@@ -2149,21 +2153,20 @@ void HTMLMediaElement::SetPlayedOrSeeked
   frame->PresContext()->PresShell()->FrameNeedsReflow(frame,
                                                       nsIPresShell::eTreeChange,
                                                       NS_FRAME_IS_DIRTY);
 }
 
 void
 HTMLMediaElement::ResetConnectionState()
 {
-  mBegun = false;
   SetCurrentTime(0);
   FireTimeUpdate(false);
   DispatchAsyncEvent(NS_LITERAL_STRING("ended"));
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
+  ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
   AddRemoveSelfReference();
   ChangeDelayLoadStatus(false);
   ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
 }
 
 void
 HTMLMediaElement::Play(ErrorResult& aRv)
 {
@@ -2641,17 +2644,17 @@ nsresult HTMLMediaElement::InitializeDec
   }
 }
 
 nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
                                               MediaResource* aStream,
                                               nsIStreamListener** aListener,
                                               MediaDecoder* aCloneDonor)
 {
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
+  ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
 
   // Force a same-origin check before allowing events for this media resource.
   mMediaSecurityVerified = false;
 
   // The new stream has not been suspended by us.
   mPausedForInactiveDocumentOrChannel = false;
   mEventDeliveryPaused = false;
   mPendingEvents.Clear();
@@ -2662,16 +2665,18 @@ nsresult HTMLMediaElement::FinishDecoder
   // Tell the decoder about its MediaResource now so things like principals are
   // available immediately.
   mDecoder->SetResource(aStream);
   mDecoder->SetAudioChannel(mAudioChannel);
   mDecoder->SetAudioCaptured(mAudioCaptured);
   mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
   mDecoder->SetPreservesPitch(mPreservesPitch);
   mDecoder->SetPlaybackRate(mPlaybackRate);
+  // Start progress timer for we are in NETWORK_LOADING.
+  mDecoder->StartProgress();
 
 #ifdef MOZ_EME
   if (mMediaKeys) {
     mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
   }
 #endif
   if (mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
     mDecoder->SetMinimizePrerollUntilPlaybackStarts();
@@ -2713,17 +2718,16 @@ nsresult HTMLMediaElement::FinishDecoder
 
   if (NS_FAILED(rv)) {
     ShutdownDecoder();
   }
 
   NS_ASSERTION(NS_SUCCEEDED(rv) == (MediaElementTableCount(this, mLoadingSrc) == 1),
     "Media element should have single table entry if decode initialized");
 
-  mBegun = true;
   return rv;
 }
 
 class HTMLMediaElement::StreamListener : public MediaStreamListener {
 public:
   explicit StreamListener(HTMLMediaElement* aElement) :
     mElement(aElement),
     mHaveCurrentData(false),
@@ -2771,17 +2775,17 @@ public:
       mElement->FireTimeUpdate(true);
     }
   }
   void DoNotifyHaveCurrentData()
   {
     mHaveCurrentData = true;
     if (mElement) {
       nsRefPtr<HTMLMediaElement> deathGrip = mElement;
-      mElement->FirstFrameLoaded(false);
+      mElement->FirstFrameLoaded();
     }
     UpdateReadyStateForData();
     DoNotifyOutput();
   }
 
   // These notifications run on the media graph thread so we need to
   // dispatch events to the main thread.
   virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) MOZ_OVERRIDE
@@ -2862,21 +2866,19 @@ void HTMLMediaElement::SetupSrcMediaStre
     GetSrcMediaStream()->AddVideoOutput(container);
   }
 
   mSrcStream->ConstructMediaTracks(AudioTracks(), VideoTracks());
 
   ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
   DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
   DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
-  DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
+  ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
   AddRemoveSelfReference();
-  // FirstFrameLoaded(false) will be called when the stream has current data,
-  // to complete the setup by entering the HAVE_CURRENT_DATA state.
+  // FirstFrameLoaded() will be called when the stream has current data.
 }
 
 void HTMLMediaElement::EndSrcMediaStreamPlayback()
 {
   MediaStream* stream = GetSrcMediaStream();
   if (stream) {
     stream->RemoveListener(mSrcStreamListener);
   }
@@ -2916,16 +2918,17 @@ void HTMLMediaElement::ProcessMediaFragm
   }
 }
 
 void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
                                       const MetadataTags* aTags)
 {
   mHasAudio = aInfo->HasAudio();
   mTags = aTags;
+  mLoadedDataFired = false;
   ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
   DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
   DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
   if (mDecoder && mDecoder->IsTransportSeekable() && mDecoder->IsMediaSeekable()) {
     ProcessMediaFragmentURI();
     mDecoder->SetFragmentEndTime(mFragmentEnd);
   }
 
@@ -2935,66 +2938,28 @@ void HTMLMediaElement::MetadataLoaded(co
   if (!aInfo->HasVideo() && mVideoFrameContainer) {
     // call ForgetElement() such that callbacks from |mVideoFrameContainer|
     // won't reach us anymore.
     mVideoFrameContainer->ForgetElement();
     mVideoFrameContainer = nullptr;
   }
 }
 
-void HTMLMediaElement::FirstFrameLoaded(bool aResourceFullyLoaded)
+void HTMLMediaElement::FirstFrameLoaded()
 {
-  ChangeReadyState(aResourceFullyLoaded ?
-    nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA :
-    nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
+  NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
+
   ChangeDelayLoadStatus(false);
 
-  NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
-
   if (mDecoder && mAllowSuspendAfterFirstFrame && mPaused &&
-      !aResourceFullyLoaded &&
       !HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
       mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
     mSuspendedAfterFirstFrame = true;
     mDecoder->Suspend();
-  } else if (mLoadedFirstFrame &&
-             mDownloadSuspendedByCache &&
-             mDecoder &&
-             !mDecoder->IsEnded()) {
-    // We've already loaded the first frame, and the decoder has signalled
-    // that the download has been suspended by the media cache. So move
-    // readyState into HAVE_ENOUGH_DATA, in case there's script waiting
-    // for a "canplaythrough" event; without this forced transition, we will
-    // never fire the "canplaythrough" event if the media cache is so small
-    // that the download was suspended before the first frame was loaded.
-    // Don't force this transition if the decoder is in ended state; the
-    // readyState should remain at HAVE_CURRENT_DATA in this case.
-    ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
-    return;
-  }
-}
-
-void HTMLMediaElement::ResourceLoaded()
-{
-  NS_ASSERTION(!mSrcStream, "Don't call this for streams");
-
-  mBegun = false;
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
-  AddRemoveSelfReference();
-  if (mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA) {
-    // MediaStream sources are put into HAVE_CURRENT_DATA state here on setup. If the
-    // stream is not blocked, we will receive a notification that will put it
-    // into HAVE_ENOUGH_DATA state.
-    ChangeReadyState(mSrcStream ? nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA
-                     : nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
-  }
-  // Ensure a progress event is dispatched at the end of download.
-  DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
-  // The download has stopped.
-  DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
+  }
 }
 
 void HTMLMediaElement::NetworkError()
 {
   Error(nsIDOMMediaError::MEDIA_ERR_NETWORK);
 }
 
 void HTMLMediaElement::DecodeError()
@@ -3028,23 +2993,22 @@ void HTMLMediaElement::LoadAborted()
 
 void HTMLMediaElement::Error(uint16_t aErrorCode)
 {
   NS_ASSERTION(aErrorCode == nsIDOMMediaError::MEDIA_ERR_DECODE ||
                aErrorCode == nsIDOMMediaError::MEDIA_ERR_NETWORK ||
                aErrorCode == nsIDOMMediaError::MEDIA_ERR_ABORTED,
                "Only use nsIDOMMediaError codes!");
   mError = new MediaError(this, aErrorCode);
-  mBegun = false;
   DispatchAsyncEvent(NS_LITERAL_STRING("error"));
   if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
-    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
+    ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
     DispatchAsyncEvent(NS_LITERAL_STRING("emptied"));
   } else {
-    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
+    ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
   }
   AddRemoveSelfReference();
   ChangeDelayLoadStatus(false);
 }
 
 void HTMLMediaElement::PlaybackEnded()
 {
   // We changed state which can affect AddRemoveSelfReference
@@ -3078,17 +3042,16 @@ void HTMLMediaElement::PlaybackEnded()
 
 void HTMLMediaElement::SeekStarted()
 {
   DispatchAsyncEvent(NS_LITERAL_STRING("seeking"));
   // Set the Variable if the Seekstarted while active playing
   if(mPlayingThroughTheAudioChannel) {
     mPlayingThroughTheAudioChannelBeforeSeek = true;
   }
-  ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
   FireTimeUpdate(false);
 }
 
 void HTMLMediaElement::SeekCompleted()
 {
   mPlayingBeforeSeek = false;
   SetPlayedOrSeeked(true);
   DispatchAsyncEvent(NS_LITERAL_STRING("seeked"));
@@ -3102,80 +3065,86 @@ void HTMLMediaElement::SeekCompleted()
   }
   // Unset the variable on seekend
   mPlayingThroughTheAudioChannelBeforeSeek = false;
 }
 
 void HTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended)
 {
   mDownloadSuspendedByCache = aIsSuspended;
-  // If this is an autoplay element, we may need to kick off its autoplaying
-  // now so we consume data and hopefully free up cache space.
-  CheckAutoplayDataReady();
 }
 
 void HTMLMediaElement::DownloadSuspended()
 {
-  DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
+  DownloadProgressed();
   if (mBegun) {
-    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
+    ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
     AddRemoveSelfReference();
-    DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
   }
 }
 
 void HTMLMediaElement::DownloadResumed(bool aForceNetworkLoading)
 {
   if (mBegun || aForceNetworkLoading) {
-    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
+    ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
     AddRemoveSelfReference();
   }
 }
 
+void HTMLMediaElement::DownloadProgressed()
+{
+  if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
+    DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
+  }
+}
+
 void HTMLMediaElement::DownloadStalled()
 {
   if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
     DispatchAsyncEvent(NS_LITERAL_STRING("stalled"));
   }
 }
 
 bool HTMLMediaElement::ShouldCheckAllowOrigin()
 {
   return mCORSMode != CORS_NONE;
 }
 
 void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatus aNextFrame)
 {
   if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
     // aNextFrame might have a next frame because the decoder can advance
-    // on its own thread before ResourceLoaded or MetadataLoaded gets
-    // a chance to run.
+    // on its own thread before MetadataLoaded gets a chance to run.
     // The arrival of more data can't change us out of this readyState.
     return;
   }
 
   // Section 2.4.3.1 of the Media Source Extensions spec requires
   // changing to HAVE_METADATA when seeking into an unbuffered
   // range.
   if (aNextFrame == MediaDecoderOwner::NEXT_FRAME_WAIT_FOR_MSE_DATA) {
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
     return;
   }
 
-  if (mReadyState > nsIDOMHTMLMediaElement::HAVE_METADATA &&
-      mDownloadSuspendedByCache &&
-      mDecoder &&
-      !mDecoder->IsEnded()) {
-    // The decoder has signalled that the download has been suspended by the
+  if (aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING) {
+    ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
+    return;
+  }
+
+  if (mDownloadSuspendedByCache && mDecoder && !mDecoder->IsEnded()) {
+    // The decoder has signaled that the download has been suspended by the
     // media cache. So move readyState into HAVE_ENOUGH_DATA, in case there's
     // script waiting for a "canplaythrough" event; without this forced
     // transition, we will never fire the "canplaythrough" event if the
     // media cache is too small, and scripts are bound to fail. Don't force
     // this transition if the decoder is in ended state; the readyState
     // should remain at HAVE_CURRENT_DATA in this case.
+    // Note that this state transition includes the case where we finished
+    // downloaded the whole data stream.
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
     return;
   }
 
   if (aNextFrame != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
     if (!mWaitingFired && aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
       FireTimeUpdate(false);
@@ -3205,17 +3174,17 @@ void HTMLMediaElement::UpdateReadyStateF
   {
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
     return;
   }
   ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA);
 }
 
 #ifdef PR_LOGGING
-static const char* gReadyStateToString[] = {
+static const char* const gReadyStateToString[] = {
   "HAVE_NOTHING",
   "HAVE_METADATA",
   "HAVE_CURRENT_DATA",
   "HAVE_FUTURE_DATA",
   "HAVE_ENOUGH_DATA"
 };
 #endif
 
@@ -3230,26 +3199,25 @@ void HTMLMediaElement::ChangeReadyState(
   }
 
   LOG(PR_LOG_DEBUG, ("%p Ready state changed to %s", this, gReadyStateToString[aState]));
 
   UpdateAudioChannelPlayingState();
 
   // Handle raising of "waiting" event during seek (see 4.8.10.9)
   if (mPlayingBeforeSeek &&
-      oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
+      mReadyState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
     DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
   }
 
   if (oldState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
       mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
-      !mLoadedFirstFrame)
-  {
+      !mLoadedDataFired) {
     DispatchAsyncEvent(NS_LITERAL_STRING("loadeddata"));
-    mLoadedFirstFrame = true;
+    mLoadedDataFired = true;
   }
 
   if (mReadyState == nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) {
     mWaitingFired = false;
   }
 
   if (oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
       mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
@@ -3265,26 +3233,69 @@ void HTMLMediaElement::ChangeReadyState(
   }
 
   if (oldState < nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA &&
       mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
     DispatchAsyncEvent(NS_LITERAL_STRING("canplaythrough"));
   }
 }
 
+#ifdef PR_LOGGING
+static const char* const gNetworkStateToString[] = {
+  "EMPTY",
+  "IDLE",
+  "LOADING",
+  "NO_SOURCE"
+ };
+#endif
+
+void HTMLMediaElement::ChangeNetworkState(nsMediaNetworkState aState)
+{
+  if (mNetworkState == aState) {
+    return;
+  }
+
+  nsMediaNetworkState oldState = mNetworkState;
+  mNetworkState = aState;
+  LOG(PR_LOG_DEBUG, ("%p Network state changed to %s", this, gNetworkStateToString[aState]));
+
+  // TODO: |mBegun| reflects the download status. We should be able to remove
+  // it and check |mNetworkState| only.
+
+  if (oldState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
+    // Reset |mBegun| since we're not downloading anymore.
+    mBegun = false;
+    if (mDecoder) {
+      // Stop progress notification when exiting NETWORK_LOADING.
+      mDecoder->StopProgress();
+    }
+  }
+
+  if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
+    // Download is begun.
+    mBegun = true;
+    if (mDecoder) {
+      // Start progress notification when entering NETWORK_LOADING.
+      mDecoder->StartProgress();
+    }
+  } else if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE && !mError) {
+    // Fire 'suspend' event when entering NETWORK_IDLE and no error presented.
+    DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
+  }
+}
+
 bool HTMLMediaElement::CanActivateAutoplay()
 {
   // For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
   // this element itself might be blocking the stream from making progress by
   // being paused.
   return !mPausedForInactiveDocumentOrChannel &&
          mAutoplaying &&
          mPaused &&
-         (mDownloadSuspendedByCache ||
-          (mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
+         ((mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
           (mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)) &&
          HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
          mAutoplayEnabled &&
          !IsEditable();
 }
 
 void HTMLMediaElement::CheckAutoplayDataReady()
 {
@@ -3393,17 +3404,17 @@ bool HTMLMediaElement::IsPotentiallyPlay
     !IsPlaybackEnded();
 }
 
 bool HTMLMediaElement::IsPlaybackEnded() const
 {
   // TODO:
   //   the current playback position is equal to the effective end of the media resource.
   //   See bug 449157.
-  return mNetworkState >= nsIDOMHTMLMediaElement::HAVE_METADATA &&
+  return mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA &&
     mDecoder ? mDecoder->IsEnded() : false;
 }
 
 already_AddRefed<nsIPrincipal> HTMLMediaElement::GetCurrentPrincipal()
 {
   if (mDecoder) {
     return mDecoder->GetCurrentPrincipal();
   }
--- a/content/html/document/reftests/reftests.list
+++ b/content/html/document/reftests/reftests.list
@@ -4,9 +4,9 @@
 == bug448564-4a.html          bug448564-4b.html
 == bug502168-1_malformed.html bug502168-1_well-formed.html
 
 # Test that image documents taken into account CSS properties like
 # image-orientation when determining the size of the image.
 # (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
 # The vast majority of the fuzziness comes from Linux and WinXP.)
 fuzzy(1,149) == bug917595-iframe-1.html    bug917595-1-ref.html
-fuzzy(2,640) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg
+fuzzy(3,640) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg
--- a/content/media/AudioSink.cpp
+++ b/content/media/AudioSink.cpp
@@ -50,20 +50,28 @@ AudioSink::AudioSink(MediaDecoderStateMa
 nsresult
 AudioSink::Init()
 {
   nsresult rv = NS_NewNamedThread("Media Audio",
                                   getter_AddRefs(mThread),
                                   nullptr,
                                   MEDIA_THREAD_STACK_SIZE);
   if (NS_FAILED(rv)) {
+    mStateMachine->OnAudioSinkError();
     return rv;
   }
+
   nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &AudioSink::AudioLoop);
-  return mThread->Dispatch(event, NS_DISPATCH_NORMAL);
+  rv =  mThread->Dispatch(event, NS_DISPATCH_NORMAL);
+  if (NS_FAILED(rv)) {
+    mStateMachine->OnAudioSinkError();
+    return rv;
+  }
+
+  return NS_OK;
 }
 
 int64_t
 AudioSink::GetPosition()
 {
   if (!mAudioStream) {
     return 0;
   }
@@ -133,16 +141,18 @@ AudioSink::StopPlayback()
 void
 AudioSink::AudioLoop()
 {
   AssertOnAudioThread();
   SINK_LOG("AudioLoop started");
 
   if (NS_FAILED(InitializeAudioStream())) {
     NS_WARNING("Initializing AudioStream failed.");
+    ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+    mStateMachine->OnAudioSinkError();
     return;
   }
 
   while (1) {
     {
       ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
       WaitForAudioToPlay();
       if (!IsPlaybackContinuing()) {
@@ -192,20 +202,23 @@ AudioSink::AudioLoop()
 
 nsresult
 AudioSink::InitializeAudioStream()
 {
   // AudioStream initialization can block for extended periods in unusual
   // circumstances, so we take care to drop the decoder monitor while
   // initializing.
   RefPtr<AudioStream> audioStream(new AudioStream());
-  audioStream->Init(mInfo.mChannels, mInfo.mRate,
-                    mChannel, AudioStream::HighLatency);
-  // TODO: Check Init's return value and bail on error.  Unfortunately this
-  // causes some tests to fail due to playback failing.
+  nsresult rv = audioStream->Init(mInfo.mChannels, mInfo.mRate,
+                                  mChannel, AudioStream::HighLatency);
+  if (NS_FAILED(rv)) {
+    audioStream->Shutdown();
+    return rv;
+  }
+
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mAudioStream = audioStream;
   UpdateStreamSettings();
 
   return NS_OK;
 }
 
 void
--- a/content/media/MediaCache.cpp
+++ b/content/media/MediaCache.cpp
@@ -1852,33 +1852,34 @@ MediaCacheStream::NotifyDataEnded(nsresu
 
   if (NS_FAILED(aStatus)) {
     // Disconnect from other streams sharing our resource, since they
     // should continue trying to load. Our load might have been deliberately
     // canceled and that shouldn't affect other streams.
     mResourceID = gMediaCache->AllocateResourceID();
   }
 
+  // It is prudent to update channel/cache status before calling
+  // CacheClientNotifyDataEnded() which will read |mChannelEnded|.
   FlushPartialBlockInternal(true);
+  mChannelEnded = true;
+  gMediaCache->QueueUpdate();
 
   MediaCache::ResourceStreamIterator iter(mResourceID);
   while (MediaCacheStream* stream = iter.Next()) {
     if (NS_SUCCEEDED(aStatus)) {
       // We read the whole stream, so remember the true length
       stream->mStreamLength = mChannelOffset;
     }
     if (!stream->mDidNotifyDataEnded) {
       stream->mDidNotifyDataEnded = true;
       stream->mNotifyDataEndedStatus = aStatus;
       stream->mClient->CacheClientNotifyDataEnded(aStatus);
     }
   }
-
-  mChannelEnded = true;
-  gMediaCache->QueueUpdate();
 }
 
 void
 MediaCacheStream::NotifyChannelRecreated()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
   mChannelEnded = false;
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -134,17 +134,16 @@ void MediaDecoder::SetDormantIfNecessary
       !mDecoderStateMachine->IsDormantNeeded() ||
       mPlayState == PLAY_STATE_SHUTDOWN ||
       mIsDormant == aDormant) {
     return;
   }
 
   if(aDormant) {
     // enter dormant state
-    StopProgress();
     DestroyDecodedStream();
     mDecoderStateMachine->SetDormant(true);
 
     int64_t timeUsecs = 0;
     SecondsToUsecs(mCurrentTime, timeUsecs);
     mRequestedSeekTarget = SeekTarget(timeUsecs, SeekTarget::Accurate);
 
     mNextState = mPlayState;
@@ -435,17 +434,16 @@ MediaDecoder::MediaDecoder() :
   mDuration(-1),
   mMediaSeekable(true),
   mSameOriginMedia(false),
   mReentrantMonitor("media.decoder"),
   mIsDormant(false),
   mIsExitingDormant(false),
   mPlayState(PLAY_STATE_PAUSED),
   mNextState(PLAY_STATE_PAUSED),
-  mCalledResourceLoaded(false),
   mIgnoreProgressData(false),
   mInfiniteStream(false),
   mOwner(nullptr),
   mPlaybackStatistics(new MediaChannelStatistics()),
   mPinnedForSeek(false),
   mShuttingDown(false),
   mPausedForPlaybackRateNull(false),
   mMinimizePreroll(false),
@@ -496,17 +494,18 @@ void MediaDecoder::Shutdown()
   // Force any outstanding seek and byterange requests to complete
   // to prevent shutdown from deadlocking.
   if (mResource) {
     mResource->Close();
   }
 
   ChangeState(PLAY_STATE_SHUTDOWN);
 
-  StopProgress();
+  // If we hit this assertion, there might be a bug in network state transition.
+  NS_ASSERTION(!mProgressTimer, "Progress timer should've been stopped.");
   mOwner = nullptr;
 
   MediaShutdownManager::Instance().Unregister(this);
 }
 
 MediaDecoder::~MediaDecoder()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -719,30 +718,18 @@ void MediaDecoder::MetadataLoaded(MediaI
 
   if (mOwner) {
     // Make sure the element and the frame (if any) are told about
     // our new size.
     Invalidate();
     mOwner->MetadataLoaded(aInfo, aTags);
   }
 
-  if (!mCalledResourceLoaded) {
-    StartProgress();
-  } else if (mOwner) {
-    // Resource was loaded during metadata loading, when progress
-    // events are being ignored. Fire the final progress event.
-    mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
-  }
-
-  // Only inform the element of FirstFrameLoaded if not doing a load() in order
-  // to fulfill a seek, otherwise we'll get multiple loadedfirstframe events.
-  bool notifyResourceIsLoaded = !mCalledResourceLoaded &&
-                                IsDataCachedToEndOfResource();
   if (mOwner) {
-    mOwner->FirstFrameLoaded(notifyResourceIsLoaded);
+    mOwner->FirstFrameLoaded();
   }
 
   // This can run cache callbacks.
   mResource->EnsureCacheUpToDate();
 
   // The element can run javascript via events
   // before reaching here, so only change the
   // state if we're still set to the original
@@ -751,55 +738,21 @@ void MediaDecoder::MetadataLoaded(MediaI
     if (mRequestedSeekTarget.IsValid()) {
       ChangeState(PLAY_STATE_SEEKING);
     }
     else {
       ChangeState(mNextState);
     }
   }
 
-  if (notifyResourceIsLoaded) {
-    ResourceLoaded();
-  }
-
   // Run NotifySuspendedStatusChanged now to give us a chance to notice
   // that autoplay should run.
   NotifySuspendedStatusChanged();
 }
 
-void MediaDecoder::ResourceLoaded()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // Don't handle ResourceLoaded if we are shutting down, or if
-  // we need to ignore progress data due to seeking (in the case
-  // that the seek results in reaching end of file, we get a bogus call
-  // to ResourceLoaded).
-  if (mShuttingDown)
-    return;
-
-  {
-    // If we are seeking or loading then the resource loaded notification we get
-    // should be ignored, since it represents the end of the seek request.
-    ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-    if (mIgnoreProgressData || mCalledResourceLoaded || mPlayState == PLAY_STATE_LOADING)
-      return;
-
-    Progress(false);
-
-    mCalledResourceLoaded = true;
-    StopProgress();
-  }
-
-  // Ensure the final progress event gets fired
-  if (mOwner) {
-    mOwner->ResourceLoaded();
-  }
-}
-
 void MediaDecoder::ResetConnectionState()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mShuttingDown)
     return;
 
   if (mOwner) {
     // Notify the media element that connection gets lost.
@@ -984,33 +937,30 @@ void MediaDecoder::UpdatePlaybackRate()
     rate = std::max(rate, 10000u);
   }
   mResource->SetPlaybackRate(rate);
 }
 
 void MediaDecoder::NotifySuspendedStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  if (!mResource)
-    return;
-  bool suspended = mResource->IsSuspendedByCache();
-  if (mOwner) {
+  if (mResource && mOwner) {
+    bool suspended = mResource->IsSuspendedByCache();
     mOwner->NotifySuspendedByCache(suspended);
     UpdateReadyStateForData();
   }
 }
 
 void MediaDecoder::NotifyBytesDownloaded()
 {
   MOZ_ASSERT(NS_IsMainThread());
   {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     UpdatePlaybackRate();
   }
-  UpdateReadyStateForData();
   Progress(false);
 }
 
 void MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   DECODER_LOG("NotifyDownloadEnded, status=%x", aStatus);
@@ -1024,22 +974,23 @@ void MediaDecoder::NotifyDownloadEnded(n
   }
 
   {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     UpdatePlaybackRate();
   }
 
   if (NS_SUCCEEDED(aStatus)) {
-    ResourceLoaded();
-  }
-  else if (aStatus != NS_BASE_STREAM_CLOSED) {
+    // A final progress event will be fired by the MediaResource calling
+    // DownloadSuspended on the element.
+    // Also NotifySuspendedStatusChanged() will be called to update readyState
+    // if download ended with success.
+  } else if (aStatus != NS_BASE_STREAM_CLOSED) {
     NetworkError();
   }
-  UpdateReadyStateForData();
 }
 
 void MediaDecoder::NotifyPrincipalChanged()
 {
   if (mOwner) {
     mOwner->NotifyDecoderPrincipalChanged();
   }
 }
@@ -1561,59 +1512,60 @@ MediaDecoderOwner* MediaDecoder::GetMedi
 static void ProgressCallback(nsITimer* aTimer, void* aClosure)
 {
   MediaDecoder* decoder = static_cast<MediaDecoder*>(aClosure);
   decoder->Progress(true);
 }
 
 void MediaDecoder::Progress(bool aTimer)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   if (!mOwner)
     return;
 
   TimeStamp now = TimeStamp::Now();
 
   if (!aTimer) {
     mDataTime = now;
   }
 
   // If PROGRESS_MS has passed since the last progress event fired and more
   // data has arrived since then, fire another progress event.
   if ((mProgressTime.IsNull() ||
        now - mProgressTime >= TimeDuration::FromMilliseconds(PROGRESS_MS)) &&
       !mDataTime.IsNull() &&
       now - mDataTime <= TimeDuration::FromMilliseconds(PROGRESS_MS)) {
-    mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
+    mOwner->DownloadProgressed();
     mProgressTime = now;
   }
 
   if (!mDataTime.IsNull() &&
       now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
     mOwner->DownloadStalled();
     // Null it out
     mDataTime = TimeStamp();
   }
 }
 
 nsresult MediaDecoder::StartProgress()
 {
-  if (mProgressTimer)
-    return NS_OK;
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ASSERTION(!mProgressTimer, "Already started progress timer.");
 
   mProgressTimer = do_CreateInstance("@mozilla.org/timer;1");
   return mProgressTimer->InitWithFuncCallback(ProgressCallback,
                                               this,
                                               PROGRESS_MS,
                                               nsITimer::TYPE_REPEATING_SLACK);
 }
 
 nsresult MediaDecoder::StopProgress()
 {
-  if (!mProgressTimer)
-    return NS_OK;
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ASSERTION(mProgressTimer, "Already stopped progress timer.");
 
   nsresult rv = mProgressTimer->Cancel();
   mProgressTimer = nullptr;
 
   return rv;
 }
 
 void MediaDecoder::FireTimeUpdate()
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -303,19 +303,16 @@ public:
   // point of the first frame of data.
   // This is called at most once per decoder, after Init().
   virtual nsresult Load(nsIStreamListener** aListener,
                         MediaDecoder* aCloneDonor);
 
   // Called in |Load| to open mResource.
   nsresult OpenResource(nsIStreamListener** aStreamListener);
 
-  // Called when the video file has completed downloading.
-  virtual void ResourceLoaded();
-
   // Called if the media file encounters a network error.
   virtual void NetworkError();
 
   // Get the current MediaResource being used. Its URI will be returned
   // by currentSrc. Returns what was passed to Load(), if Load() has been called.
   // Note: The MediaResource is refcounted, but it outlives the MediaDecoder,
   // so it's OK to use the reference returned by this function without
   // refcounting, *unless* you need to store and use the reference after the
@@ -687,16 +684,22 @@ public:
   layers::ImageContainer* GetImageContainer() MOZ_OVERRIDE;
 
   // Return the current state. Can be called on any thread. If called from
   // a non-main thread, the decoder monitor must be held.
   PlayState GetState() {
     return mPlayState;
   }
 
+  // Called by the media element to start timer to update download progress.
+  nsresult StartProgress();
+
+  // Called by the media element to stop progress information timer.
+  nsresult StopProgress();
+
   // Fire progress events if needed according to the time and byte
   // constraints outlined in the specification. aTimer is true
   // if the method is called as a result of the progress timer rather
   // than the result of downloaded data.
   void Progress(bool aTimer);
 
   // Fire timeupdate events if needed according to the time constraints
   // outlined in the specification.
@@ -1154,37 +1157,26 @@ protected:
   // decode thread.
   // This can only be changed on the main thread while holding the decoder
   // monitor. Thus, it can be safely read while holding the decoder monitor
   // OR on the main thread.
   // If the SeekTarget's IsValid() accessor returns false, then no seek has
   // been requested. When a seek is started this is reset to invalid.
   SeekTarget mRequestedSeekTarget;
 
-  // True when we have fully loaded the resource and reported that
-  // to the element (i.e. reached NETWORK_LOADED state).
-  // Accessed on the main thread only.
-  bool mCalledResourceLoaded;
-
   // True when seeking or otherwise moving the play position around in
   // such a manner that progress event data is inaccurate. This is set
   // during seek and duration operations to prevent the progress indicator
   // from jumping around. Read/Write from any thread. Must have decode monitor
   // locked before accessing.
   bool mIgnoreProgressData;
 
   // True if the stream is infinite (e.g. a webradio).
   bool mInfiniteStream;
 
-  // Start timer to update download progress information.
-  nsresult StartProgress();
-
-  // Stop progress information timer.
-  nsresult StopProgress();
-
   // Ensures our media stream has been pinned.
   void PinForSeek();
 
   // Ensures our media stream has been unpinned.
   void UnpinForSeek();
 
   // Timer used for updating progress events
   nsCOMPtr<nsITimer> mProgressTimer;
--- a/content/media/MediaDecoderOwner.h
+++ b/content/media/MediaDecoderOwner.h
@@ -13,16 +13,18 @@ class VideoFrameContainer;
 
 namespace dom {
 class HTMLMediaElement;
 }
 
 class MediaDecoderOwner
 {
 public:
+  // Called by the media decoder to indicate that the download is progressing.
+  virtual void DownloadProgressed() = 0;
   // Called by the media decoder to indicate that the download has stalled
   // (no data has arrived for a while).
   virtual void DownloadStalled() = 0;
 
   // Dispatch a synchronous event to the decoder owner
   virtual nsresult DispatchEvent(const nsAString& aName) = 0;
 
   // Dispatch an asynchronous event to the decoder owner
@@ -47,25 +49,19 @@ public:
   virtual bool GetPaused() = 0;
 
   // Called by the video decoder object, on the main thread,
   // when it has read the metadata containing video dimensions,
   // etc.
   virtual void MetadataLoaded(const MediaInfo* aInfo,
                               const MetadataTags* aTags) = 0;
 
-  // Called by the video decoder object, on the main thread,
-  // when it has read the first frame of the video
-  // aResourceFullyLoaded should be true if the resource has been
-  // fully loaded and the caller will call ResourceLoaded next.
-  virtual void FirstFrameLoaded(bool aResourceFullyLoaded) = 0;
-
-  // Called by the video decoder object, on the main thread,
-  // when the resource has completed downloading.
-  virtual void ResourceLoaded() = 0;
+  // Called by the decoder object, on the main thread,
+  // when it has read the first frame of the video or audio.
+  virtual void FirstFrameLoaded() = 0;
 
   // Called by the video decoder object, on the main thread,
   // when the resource has a network error during loading.
   virtual void NetworkError() = 0;
 
   // Called by the video decoder object, on the main thread, when the
   // resource has a decode error during metadata loading or decoding.
   virtual void DecodeError() = 0;
@@ -109,16 +105,18 @@ public:
 
   // The status of the next frame which might be available from the decoder
   enum NextFrameStatus {
     // The next frame of audio/video is available
     NEXT_FRAME_AVAILABLE,
     // The next frame of audio/video is unavailable because the decoder
     // is paused while it buffers up data
     NEXT_FRAME_UNAVAILABLE_BUFFERING,
+    // The next frame of audio/video is unavailable for the decoder is seeking.
+    NEXT_FRAME_UNAVAILABLE_SEEKING,
     // The next frame of audio/video is unavailable for some other reasons
     NEXT_FRAME_UNAVAILABLE,
     // The next frame is unavailable due to waiting for more Media Source
     // Extensions data to become available.
     NEXT_FRAME_WAIT_FOR_MSE_DATA,
     // Sentinel value
     NEXT_FRAME_UNINITIALIZED
   };
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -1149,19 +1149,19 @@ void MediaDecoderStateMachine::StartPlay
     DECODER_LOG("Offloading playback");
     return;
   }
 
   mDecoder->NotifyPlaybackStarted();
   SetPlayStartTime(TimeStamp::Now());
 
   NS_ASSERTION(IsPlaying(), "Should report playing by end of StartPlayback()");
-  if (NS_FAILED(StartAudioThread())) {
-    DECODER_WARN("Failed to create audio thread");
-  }
+  nsresult rv = StartAudioThread();
+  NS_ENSURE_SUCCESS_VOID(rv);
+
   mDecoder->GetReentrantMonitor().NotifyAll();
   mDecoder->UpdateStreamBlockingForStateMachinePlaying();
   DispatchDecodeTasksIfNeeded();
 }
 
 void MediaDecoderStateMachine::UpdatePlaybackPositionInternal(int64_t aTime)
 {
   SAMPLE_LOG("UpdatePlaybackPositionInternal(%lld) (mStartTime=%lld)", aTime, mStartTime);
@@ -1207,18 +1207,20 @@ void MediaDecoderStateMachine::ClearPosi
   AssertCurrentThreadInMonitor();
 
   mPositionChangeQueued = false;
 }
 
 MediaDecoderOwner::NextFrameStatus MediaDecoderStateMachine::GetNextFrameStatus()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  if (IsBuffering() || IsSeeking()) {
+  if (IsBuffering()) {
     return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING;
+  } else if (IsSeeking()) {
+    return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING;
   } else if (HaveNextFrameData()) {
     return MediaDecoderOwner::NEXT_FRAME_AVAILABLE;
   }
   return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
 }
 
 static const char* const gMachineStateStr[] = {
   "NONE",
@@ -1784,25 +1786,22 @@ MediaDecoderStateMachine::StartAudioThre
   if (mAudioCaptured) {
     NS_ASSERTION(mStopAudioThread, "mStopAudioThread must always be true if audio is captured");
     return NS_OK;
   }
 
   mStopAudioThread = false;
   if (HasAudio() && !mAudioSink) {
     mAudioCompleted = false;
-    mAudioSink = new AudioSink(this,
-                               mAudioStartTime, mInfo.mAudio, mDecoder->GetAudioChannel());
+    mAudioSink = new AudioSink(this, mAudioStartTime,
+                               mInfo.mAudio, mDecoder->GetAudioChannel());
+    // OnAudioSinkError() will be called before Init() returns if an error
+    // occurs during initialization.
     nsresult rv = mAudioSink->Init();
-    if (NS_FAILED(rv)) {
-      DECODER_WARN("Changed state to SHUTDOWN because audio sink initialization failed");
-      SetState(DECODER_STATE_SHUTDOWN);
-      mScheduler->ScheduleAndShutdown();
-      return rv;
-    }
+    NS_ENSURE_SUCCESS(rv, rv);
 
     mAudioSink->SetVolume(mVolume);
     mAudioSink->SetPlaybackRate(mPlaybackRate);
     mAudioSink->SetPreservesPitch(mPreservesPitch);
   }
   return NS_OK;
 }
 
@@ -2881,16 +2880,20 @@ void MediaDecoderStateMachine::SetStartT
   mAudioStartTime = mStartTime;
   DECODER_LOG("Set media start time to %lld", mStartTime);
 }
 
 void MediaDecoderStateMachine::UpdateReadyState() {
   AssertCurrentThreadInMonitor();
 
   MediaDecoderOwner::NextFrameStatus nextFrameStatus = GetNextFrameStatus();
+  // FIXME: This optimization could result in inconsistent next frame status
+  // between the decoder and state machine when GetNextFrameStatus() is called
+  // by the decoder without updating mLastFrameStatus.
+  // Note not to regress bug 882027 when fixing this bug.
   if (nextFrameStatus == mLastFrameStatus) {
     return;
   }
   mLastFrameStatus = nextFrameStatus;
 
   /* This is a bit tricky. MediaDecoder::UpdateReadyStateForData will run on
    * the main thread and re-evaluate GetNextFrameStatus there, passing it to
    * HTMLMediaElement::UpdateReadyStateForData. It doesn't use the value of
@@ -3113,15 +3116,34 @@ void MediaDecoderStateMachine::OnAudioSi
     return;
   }
   mAudioCompleted = true;
   UpdateReadyState();
   // Kick the decode thread; it may be sleeping waiting for this to finish.
   mDecoder->GetReentrantMonitor().NotifyAll();
 }
 
+void MediaDecoderStateMachine::OnAudioSinkError()
+{
+  AssertCurrentThreadInMonitor();
+  // AudioSink not used with captured streams, so ignore errors in this case.
+  if (mAudioCaptured) {
+    return;
+  }
+
+  mAudioCompleted = true;
+
+  // Notify media decoder/element about this error.
+  RefPtr<nsIRunnable> task(
+    NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnDecodeError));
+  nsresult rv = mDecodeTaskQueue->Dispatch(task);
+  if (NS_FAILED(rv)) {
+    DECODER_WARN("Failed to dispatch OnDecodeError");
+  }
+}
+
 } // namespace mozilla
 
 // avoid redefined macro in unified build
 #undef DECODER_LOG
 #undef VERBOSE_LOG
 #undef DECODER_WARN
 #undef DECODER_WARN_HELPER
--- a/content/media/MediaDecoderStateMachine.h
+++ b/content/media/MediaDecoderStateMachine.h
@@ -631,16 +631,19 @@ protected:
 
   // Update mDecoder's playback offset.
   void OnPlaybackOffsetUpdate(int64_t aPlaybackOffset);
 
   // Called by the AudioSink to signal that all outstanding work is complete
   // and the sink is shutting down.
   void OnAudioSinkComplete();
 
+  // Called by the AudioSink to signal errors.
+  void OnAudioSinkError();
+
   // The decoder object that created this state machine. The state machine
   // holds a strong reference to the decoder to ensure that the decoder stays
   // alive once media element has started the decoder shutdown process, and has
   // dropped its reference to the decoder. This enables the state machine to
   // keep using the decoder's monitor until the state machine has finished
   // shutting down, without fear of the monitor being destroyed. After
   // shutting down, the state machine will then release this reference,
   // causing the decoder to be destroyed. This is accessed on the decode,
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -900,18 +900,21 @@ void ChannelMediaResource::Resume()
       // seek to it. The seek will fail and be wasted anyway. We can leave
       // the channel dead; if the media cache wants to read some other data
       // in the future, it will call CacheClientSeek itself which will reopen the
       // channel.
       if (totalLength < 0 || mOffset < totalLength) {
         // There is (or may be) data to read at mOffset, so start reading it.
         // Need to recreate the channel.
         CacheClientSeek(mOffset, false);
+        element->DownloadResumed();
+      } else {
+        // The channel remains dead. Do not notify DownloadResumed() which
+        // will leave the media element in NETWORK_LOADING state.
       }
-      element->DownloadResumed();
     }
   }
 }
 
 nsresult
 ChannelMediaResource::RecreateChannel()
 {
   nsLoadFlags loadFlags =
@@ -979,21 +982,34 @@ ChannelMediaResource::CacheClientNotifyD
 }
 
 class DataEnded : public nsRunnable {
 public:
   DataEnded(MediaDecoder* aDecoder, nsresult aStatus) :
     mDecoder(aDecoder), mStatus(aStatus) {}
   NS_IMETHOD Run() {
     mDecoder->NotifyDownloadEnded(mStatus);
+    if (NS_SUCCEEDED(mStatus)) {
+      MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
+      if (owner) {
+        dom::HTMLMediaElement* element = owner->GetMediaElement();
+        if (element) {
+          element->DownloadSuspended();
+        }
+      }
+      // NotifySuspendedStatusChanged will tell the element that download
+      // has been suspended "by the cache", which is true since we never download
+      // anything. The element can then transition to HAVE_ENOUGH_DATA.
+      mDecoder->NotifySuspendedStatusChanged();
+    }
     return NS_OK;
   }
 private:
   nsRefPtr<MediaDecoder> mDecoder;
-  nsresult                 mStatus;
+  nsresult               mStatus;
 };
 
 void
 ChannelMediaResource::CacheClientNotifyDataEnded(nsresult aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
   // NOTE: this can be called with the media cache lock held, so don't
   // block or do anything which might try to acquire a lock!
@@ -1243,18 +1259,18 @@ public:
   }
   virtual int64_t GetCachedDataEnd(int64_t aOffset) {
     MutexAutoLock lock(mLock);
 
     EnsureSizeInitialized();
     return std::max(aOffset, mSize);
   }
   virtual bool    IsDataCachedToEndOfResource(int64_t aOffset) { return true; }
-  virtual bool    IsSuspendedByCache() { return false; }
-  virtual bool    IsSuspended() { return false; }
+  virtual bool    IsSuspendedByCache() { return true; }
+  virtual bool    IsSuspended() { return true; }
   virtual bool    IsTransportSeekable() MOZ_OVERRIDE { return true; }
 
   nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges);
 
   virtual size_t SizeOfExcludingThis(
                         MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   {
     // Might be useful to track in the future:
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2854,18 +2854,21 @@ MediaStreamGraphImpl::CollectReports(nsI
 {
   // Clears out the report array after we're done with it.
   ArrayClearer reportCleanup(mAudioStreamSizes);
 
   {
     MonitorAutoLock memoryReportLock(mMemoryReportMonitor);
     mNeedsMemoryReport = true;
 
-    // Wake up the MSG thread.
-    CurrentDriver()->WakeUp();
+    {
+      // Wake up the MSG thread.
+      MonitorAutoLock monitorLock(mMonitor);
+      CurrentDriver()->WakeUp();
+    }
 
     if (mLifecycleState >= LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN) {
       // Shutting down, nothing to report.
       return NS_OK;
     }
 
     // Wait for up to one second for the report to complete.
     nsresult rv;
--- a/content/media/fmp4/wmf/WMFAudioMFTManager.cpp
+++ b/content/media/fmp4/wmf/WMFAudioMFTManager.cpp
@@ -251,16 +251,23 @@ WMFAudioMFTManager::Output(int64_t aStre
     NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
     if (mAudioFrameOffset < 0) {
       // First sample has a negative timestamp. Strip off the samples until
       // we reach positive territory.
       numFramesToStrip = -mAudioFrameOffset;
       mAudioFrameOffset = 0;
     }
     mMustRecaptureAudioPosition = false;
+
+    // Also update the output type, in case this segment has a different
+    // rate. This also triggers on the first sample, which can have a
+    // different rate than is advertised in the container, and sometimes
+    // we don't get a MF_E_TRANSFORM_STREAM_CHANGE when the rate changes.
+    hr = UpdateOutputType();
+    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   }
   MOZ_ASSERT(numFramesToStrip >= 0);
   int32_t offset = std::min<int32_t>(numFramesToStrip, numFrames);
   numFrames -= offset;
   numSamples -= offset * mAudioChannels;
   MOZ_ASSERT(numFrames >= 0);
   MOZ_ASSERT(numSamples >= 0);
   if (numFrames == 0) {
--- a/content/media/omx/AudioOffloadPlayer.cpp
+++ b/content/media/omx/AudioOffloadPlayer.cpp
@@ -664,17 +664,17 @@ nsresult AudioOffloadPlayer::StopTimeUpd
   mTimeUpdateTimer = nullptr;
   return rv;
 }
 
 MediaDecoderOwner::NextFrameStatus AudioOffloadPlayer::GetNextFrameStatus()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mPlayState == MediaDecoder::PLAY_STATE_SEEKING) {
-    return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING;
+    return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING;
   } else if (mPlayState == MediaDecoder::PLAY_STATE_ENDED) {
     return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
   } else {
     return MediaDecoderOwner::NEXT_FRAME_AVAILABLE;
   }
 }
 
 void AudioOffloadPlayer::SendMetaDataToHal(sp<AudioSink>& aSink,
--- a/content/media/omx/MediaOmxCommonDecoder.cpp
+++ b/content/media/omx/MediaOmxCommonDecoder.cpp
@@ -96,17 +96,16 @@ void
 MediaOmxCommonDecoder::PauseStateMachine()
 {
   MOZ_ASSERT(NS_IsMainThread());
   GetReentrantMonitor().AssertCurrentThreadIn();
   DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
   if (!mDecoderStateMachine) {
     return;
   }
-  StopProgress();
   mDecoderStateMachine->SetDormant(true);
 }
 
 void
 MediaOmxCommonDecoder::ResumeStateMachine()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f39ab5bcb8c86009c7d77d52360a5c3c340add18
GIT binary patch
literal 19636
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
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-discard_on_multi_blocks.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5b34aca1a7d64f36afc12cc125816121bb30211e
GIT binary patch
literal 18442
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
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-excess_discard.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2bfad6ed21c611d6bfebd9a31fdd0f2da70dffc4
GIT binary patch
literal 18442
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
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-excess_neg_discard.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3f665c0b5966314ff01613dd7516dfbd40c3d9b6
GIT binary patch
literal 18442
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
new file mode 100644
--- /dev/null
+++ b/content/media/test/invalid-neg_discard.webm^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -246,16 +246,23 @@ var gInvalidTests = [
   { name:"invalid-m2c1.opus", type:"audio/ogg; codecs=opus"},
   { name:"invalid-cmap-short.opus", type:"audio/ogg; codecs=opus"},
   { name:"invalid-cmap-s0c0.opus", type:"audio/ogg; codecs=opus"},
   { name:"invalid-cmap-s0c2.opus", type:"audio/ogg; codecs=opus"},
   { name:"invalid-cmap-s1c2.opus", type:"audio/ogg; codecs=opus"},
   { name:"invalid-preskip.webm", type:"audio/webm; codecs=opus"},
 ];
 
+var gInvalidPlayTests = [
+  { name:"invalid-excess_discard.webm", type:"audio/webm; codecs=opus"},
+  { name:"invalid-excess_neg_discard.webm", type:"audio/webm; codecs=opus"},
+  { name:"invalid-neg_discard.webm", type:"audio/webm; codecs=opus"},
+  { name:"invalid-discard_on_multi_blocks.webm", type:"audio/webm; codecs=opus"},
+];
+
 // Files to check different cases of ogg skeleton information.
 // sample-fisbone-skeleton4.ogv
 // - Skeleton v4, w/ Content-Type,Role,Name,Language,Title for both theora/vorbis
 // sample-fisbone-wrong-header.ogv
 // - Skeleton v4, wrong message field sequence for vorbis
 // multiple-bos-more-header-fields.ogg
 // - Skeleton v3, w/ Content-Type,Role,Name,Language,Title for both theora/vorbis
 // seek.ogv
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -17,17 +17,17 @@
 # throws an error (and does not cause a crash or hang), just add it to
 # gErrorTests in manifest.js.
 
 # To test for a specific bug in handling a specific resource type, make the
 # test first check canPlayType for the type, and if it's not supported, just
 # do ok(true, "Type not supported") and stop the test.
 
 [DEFAULT]
-skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') # b2g-desktop(bug 918299)
+skip-if = buildapp == 'mulet'
 support-files =
   320x240.ogv
   320x240.ogv^headers^
   448636.ogv
   448636.ogv^headers^
   VID_0001.ogg
   VID_0001.ogg^headers^
   allowed.sjs
@@ -152,28 +152,36 @@ support-files =
   invalid-cmap-s0c0.opus
   invalid-cmap-s0c0.opus^headers^
   invalid-cmap-s0c2.opus
   invalid-cmap-s0c2.opus^headers^
   invalid-cmap-s1c2.opus
   invalid-cmap-s1c2.opus^headers^
   invalid-cmap-short.opus
   invalid-cmap-short.opus^headers^
+  invalid-discard_on_multi_blocks.webm
+  invalid-discard_on_multi_blocks.webm^headers^
+  invalid-excess_discard.webm
+  invalid-excess_discard.webm^headers^
+  invalid-excess_neg_discard.webm
+  invalid-excess_neg_discard.webm^headers^
   invalid-m0c0.opus
   invalid-m0c0.opus^headers^
   invalid-m0c3.opus
   invalid-m0c3.opus^headers^
   invalid-m1c0.opus
   invalid-m1c0.opus^headers^
   invalid-m1c9.opus
   invalid-m1c9.opus^headers^
   invalid-m2c0.opus
   invalid-m2c0.opus^headers^
   invalid-m2c1.opus
   invalid-m2c1.opus^headers^
+  invalid-neg_discard.webm
+  invalid-neg_discard.webm^headers^
   invalid-preskip.webm
   invalid-preskip.webm^headers^
   long.vtt
   manifest.js
   multiple-bos.ogg
   multiple-bos.ogg^headers^
   multiple-bos-more-header-fileds.ogg
   multiple-bos-more-header-fileds.ogg^headers^
@@ -286,16 +294,17 @@ support-files =
   wave_metadata_utf8.wav
   wave_metadata_utf8.wav^headers^
   wavedata_s16.wav
   wavedata_s16.wav^headers^
   wavedata_u8.wav
   wavedata_u8.wav^headers^
 
 [test_access_control.html]
+skip-if = buildapp == 'b2g' && toolkit != 'gonk' # crash on b2g-desktop
 [test_aspectratio_mp4.html]
 [test_audio1.html]
 [test_audio2.html]
 [test_audioDocumentTitle.html]
 skip-if = true # bug 475110 - disabled since we don't play Wave files standalone
 [test_autoplay.html]
 [test_autoplay_contentEditable.html]
 [test_buffered.html]
@@ -345,16 +354,17 @@ skip-if = buildapp == 'b2g' || toolkit =
 [test_error_in_video_document.html]
 skip-if = toolkit == 'android' # bug 608634
 [test_error_on_404.html]
 [test_fastSeek.html]
 [test_fastSeek-forwards.html]
 [test_imagecapture.html]
 [test_info_leak.html]
 [test_invalid_reject.html]
+[test_invalid_reject_play.html]
 [test_invalid_seek.html]
 [test_load.html]
 [test_load_candidates.html]
 [test_load_same_resource.html]
 [test_load_source.html]
 [test_loop.html]
 [test_media_selection.html]
 skip-if = toolkit == 'gonk' && !debug # bug 1021677
--- a/content/media/test/test_invalid_reject.html
+++ b/content/media/test/test_invalid_reject.html
@@ -26,20 +26,20 @@ function startTest(test, token) {
       'canplay', 'canplaythrough',
       'playing'
   ];
   events.forEach( function(e) {
     v.addEventListener(e, badEvent(e));
   });
 
   // Seeing a decoder error is a success.
-  v.addEventListener("error", function(e) {
+  v.addEventListener("error", function onerror(e) {
     is(v.error.code, v.error.MEDIA_ERR_DECODE,
       "decoder should reject " + test.name);
-    v.removeEventListener('error', arguments.callee, false);
+    v.removeEventListener('error', onerror, false);
     manager.finished(token);
   });
 
   // Now try to load and play the file, which should result in the
   // error event handler above being called, terminating the test.
   document.body.appendChild(v);
   v.src = test.name;
   v.play();
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_invalid_reject_play.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="UTF-8" />
+  <title>Test rejection of invalid files during playback</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+  var v = document.createElement('video');
+  manager.started(token);
+
+  // Seeing a decoder error is a success.
+  v.addEventListener("error", function onerror(e) {
+    is(v.error.code, v.error.MEDIA_ERR_DECODE,
+       "decoder should reject " + test.name);
+    v.removeEventListener("error", onerror, false);
+    manager.finished(token);
+  });
+
+  v.addEventListener("ended", function onended(e) {
+    ok(false, "decoder should have rejected file before playback ended");
+    v.removeEventListener("ended", onended, false);
+    manager.finished(token);
+  });
+
+  document.body.appendChild(v);
+  v.src = test.name;
+  v.play();
+}
+
+manager.runTests(gInvalidPlayTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/media/test/test_media_selection.html
+++ b/content/media/test/test_media_selection.html
@@ -25,22 +25,22 @@ function maketest(attach_media, name, ty
           // The load can go idle due to cache size limits
           ok(e.networkState >= HTMLMediaElement.NETWORK_IDLE,
               'test ' + token + ' networkState = ' + e.networkState + ' expected >= ' + HTMLMediaElement.NETWORK_IDLE);
           check_metadata(e);
           removeNodeAndSource(e);
           manager.finished(token);
         }, false);
     } else {
-      e.addEventListener('error', function(event) {
+      e.addEventListener('error', function onerror(event) {
         is(errorRun, false, "error handler should run once only!");
         errorRun = true;
         is(e.readyState, HTMLMediaElement.HAVE_NOTHING,
            'test ' + token + ' readyState should be HAVE_NOTHING when load fails.');
-        e.removeEventListener('error', arguments.callee, true);
+        e.removeEventListener('error', onerror, true);
         removeNodeAndSource(e);
         manager.finished(token);
       }, true);
     }
     attach_media(e, name, type);
   }
 }
 
--- a/content/media/test/test_playback_rate.html
+++ b/content/media/test/test_playback_rate.html
@@ -31,17 +31,18 @@ function checkPlaybackRate(wallclock, me
 let VERY_SLOW_RATE = 0.1,
     SLOW_RATE = 0.25,
     FAST_RATE = 5,
     VERY_FAST_RATE = 20,
     NULL_RATE = 0.0;
 
 function ontimeupdate(e) {
   var t = e.target;
-  if (t.gotEnded) {
+  // Skip short files for SoundTouch doesn't work well on small number of samples.
+  if (t.gotEnded || t.duration < 2) {
     return;
   }
   t.testedForSlowdown = true;
   if (t.currentTime > t.duration / 2) {
     t.oldCurrentTime = t.currentTime;
     t.timestamp = Date.now();
     var delta = t.oldCurrentTime,
         delta_wallclock = (t.timestamp - t.startTimestamp - t.bufferingTime) / 1000;
--- a/content/media/webm/WebMReader.cpp
+++ b/content/media/webm/WebMReader.cpp
@@ -19,31 +19,33 @@
 #include "vpx/vp8dx.h"
 #include "vpx/vpx_decoder.h"
 
 #include "OggReader.h"
 
 using mozilla::NesteggPacketHolder;
 
 template <>
-class nsAutoRefTraits<NesteggPacketHolder> : public nsPointerRefTraits<NesteggPacketHolder>
+class nsAutoRefTraits<NesteggPacketHolder> :
+  public nsPointerRefTraits<NesteggPacketHolder>
 {
 public:
   static void Release(NesteggPacketHolder* aHolder) { delete aHolder; }
 };
 
 namespace mozilla {
 
 using namespace gfx;
 using namespace layers;
 
 // Un-comment to enable logging of seek bisections.
 //#define SEEK_LOGGING
 
 #ifdef PR_LOGGING
+#include "prprf.h"
 extern PRLogModuleInfo* gMediaDecoderLog;
 PRLogModuleInfo* gNesteggLog;
 #define LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
 #ifdef SEEK_LOGGING
 #define SEEK_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
 #else
 #define SEEK_LOG(type, msg)
 #endif
@@ -55,18 +57,19 @@ PRLogModuleInfo* gNesteggLog;
 static const unsigned NS_PER_USEC = 1000;
 static const double NS_PER_S = 1e9;
 
 // Functions for reading and seeking using MediaResource required for
 // nestegg_io. The 'user data' passed to these functions is the
 // decoder from which the media resource is obtained.
 static int webm_read(void *aBuffer, size_t aLength, void *aUserData)
 {
-  NS_ASSERTION(aUserData, "aUserData must point to a valid AbstractMediaDecoder");
-  AbstractMediaDecoder* decoder = reinterpret_cast<AbstractMediaDecoder*>(aUserData);
+  MOZ_ASSERT(aUserData);
+  AbstractMediaDecoder* decoder =
+    reinterpret_cast<AbstractMediaDecoder*>(aUserData);
   MediaResource* resource = decoder->GetResource();
   NS_ASSERTION(resource, "Decoder has no media resource");
 
   nsresult rv = NS_OK;
   bool eof = false;
 
   char *p = static_cast<char *>(aBuffer);
   while (NS_SUCCEEDED(rv) && aLength > 0) {
@@ -80,28 +83,30 @@ static int webm_read(void *aBuffer, size
     p += bytes;
   }
 
   return NS_FAILED(rv) ? -1 : eof ? 0 : 1;
 }
 
 static int webm_seek(int64_t aOffset, int aWhence, void *aUserData)
 {
-  NS_ASSERTION(aUserData, "aUserData must point to a valid AbstractMediaDecoder");
-  AbstractMediaDecoder* decoder = reinterpret_cast<AbstractMediaDecoder*>(aUserData);
+  MOZ_ASSERT(aUserData);
+  AbstractMediaDecoder* decoder =
+    reinterpret_cast<AbstractMediaDecoder*>(aUserData);
   MediaResource* resource = decoder->GetResource();
   NS_ASSERTION(resource, "Decoder has no media resource");
   nsresult rv = resource->Seek(aWhence, aOffset);
   return NS_SUCCEEDED(rv) ? 0 : -1;
 }
 
 static int64_t webm_tell(void *aUserData)
 {
-  NS_ASSERTION(aUserData, "aUserData must point to a valid AbstractMediaDecoder");
-  AbstractMediaDecoder* decoder = reinterpret_cast<AbstractMediaDecoder*>(aUserData);
+  MOZ_ASSERT(aUserData);
+  AbstractMediaDecoder* decoder =
+    reinterpret_cast<AbstractMediaDecoder*>(aUserData);
   MediaResource* resource = decoder->GetResource();
   NS_ASSERTION(resource, "Decoder has no media resource");
   return resource->Tell();
 }
 
 static void webm_log(nestegg * context,
                      unsigned int severity,
                      char const * format, ...)
@@ -137,36 +142,51 @@ static void webm_log(nestegg * context,
   PR_snprintf(msg, sizeof(msg), "%p [Nestegg-%s] ", context, sevStr);
   PR_vsnprintf(msg+strlen(msg), sizeof(msg)-strlen(msg), format, args);
   PR_LOG(gNesteggLog, PR_LOG_DEBUG, (msg));
 
   va_end(args);
 #endif
 }
 
+ogg_packet
+InitOggPacket(const unsigned char* aData, size_t aLength, bool aBOS, bool aEOS,
+              int64_t aGranulepos, int64_t aPacketNo)
+{
+  ogg_packet packet;
+  packet.packet = const_cast<unsigned char*>(aData);
+  packet.bytes = aLength;
+  packet.b_o_s = aBOS;
+  packet.e_o_s = aEOS;
+  packet.granulepos = aGranulepos;
+  packet.packetno = aPacketNo;
+  return packet;
+}
+
 WebMReader::WebMReader(AbstractMediaDecoder* aDecoder)
-  : MediaDecoderReader(aDecoder),
-  mContext(nullptr),
-  mPacketCount(0),
-  mChannels(0),
+  : MediaDecoderReader(aDecoder)
+  , mContext(nullptr)
+  , mPacketCount(0)
 #ifdef MOZ_OPUS
-  mOpusParser(nullptr),
-  mOpusDecoder(nullptr),
-  mSkip(0),
-  mSeekPreroll(0),
+  , mOpusDecoder(nullptr)
+  , mSkip(0)
+  , mSeekPreroll(0)
 #endif
-  mVideoTrack(0),
-  mAudioTrack(0),
-  mAudioStartUsec(-1),
-  mAudioFrames(0),
-  mLastVideoFrameTime(0),
-  mAudioCodec(-1),
-  mVideoCodec(-1),
-  mHasVideo(false),
-  mHasAudio(false)
+  , mVideoTrack(0)
+  , mAudioTrack(0)
+  , mAudioStartUsec(-1)
+  , mAudioFrames(0)
+  , mLastVideoFrameTime(0)
+  , mAudioCodec(-1)
+  , mVideoCodec(-1)
+  , mHasVideo(false)
+  , mHasAudio(false)
+#ifdef MOZ_OPUS
+  , mPaddingDiscarded(false)
+#endif
 {
   MOZ_COUNT_CTOR(WebMReader);
 #ifdef PR_LOGGING
   if (!gNesteggLog) {
     gNesteggLog = PR_NewLogModule("Nestegg");
   }
 #endif
   // Zero these member vars to avoid crashes in VP8 destroy and Vorbis clear
@@ -232,16 +252,17 @@ nsresult WebMReader::ResetDecode()
     // time when no vorbis data has been read.
     vorbis_synthesis_restart(&mVorbisDsp);
 #ifdef MOZ_OPUS
   } else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
     if (mOpusDecoder) {
       // Reset the decoder.
       opus_multistream_decoder_ctl(mOpusDecoder, OPUS_RESET_STATE);
       mSkip = mOpusParser->mPreSkip;
+      mPaddingDiscarded = false;
     }
 #endif
   }
 
   mVideoPackets.Reset();
   mAudioPackets.Reset();
 
   return res;
@@ -309,35 +330,37 @@ nsresult WebMReader::ReadMetadata(MediaI
       }
       if (!dx || vpx_codec_dec_init(&mVPX, dx, nullptr, 0)) {
         Cleanup();
         return NS_ERROR_FAILURE;
       }
 
       // Picture region, taking into account cropping, before scaling
       // to the display size.
+      unsigned int cropH = params.crop_right + params.crop_left;
+      unsigned int cropV = params.crop_bottom + params.crop_top;
       nsIntRect pictureRect(params.crop_left,
                             params.crop_top,
-                            params.width - (params.crop_right + params.crop_left),
-                            params.height - (params.crop_bottom + params.crop_top));
+                            params.width - cropH,
+                            params.height - cropV);
 
       // If the cropping data appears invalid then use the frame data
       if (pictureRect.width <= 0 ||
           pictureRect.height <= 0 ||
           pictureRect.x < 0 ||
           pictureRect.y < 0)
       {
         pictureRect.x = 0;
         pictureRect.y = 0;
         pictureRect.width = params.width;
         pictureRect.height = params.height;
       }
 
-      // Validate the container-reported frame and pictureRect sizes. This ensures
-      // that our video frame creation code doesn't overflow.
+      // Validate the container-reported frame and pictureRect sizes. This
+      // ensures that our video frame creation code doesn't overflow.
       nsIntSize displaySize(params.display_width, params.display_height);
       nsIntSize frameSize(params.width, params.height);
       if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
         // Video track's frame sizes will overflow. Ignore the video track.
         continue;
       }
 
       mVideoTrack = track;
@@ -393,17 +416,18 @@ nsresult WebMReader::ReadMetadata(MediaI
           unsigned char* data = 0;
           size_t length = 0;
 
           r = nestegg_track_codec_data(mContext, track, header, &data, &length);
           if (r == -1) {
             Cleanup();
             return NS_ERROR_FAILURE;
           }
-          ogg_packet opacket = InitOggPacket(data, length, header == 0, false, 0);
+          ogg_packet opacket = InitOggPacket(data, length, header == 0, false,
+                                             0, mPacketCount++);
 
           r = vorbis_synthesis_headerin(&mVorbisInfo,
                                         &mVorbisComment,
                                         &opacket);
           if (r != 0) {
             Cleanup();
             return NS_ERROR_FAILURE;
           }
@@ -418,17 +442,16 @@ nsresult WebMReader::ReadMetadata(MediaI
         r = vorbis_block_init(&mVorbisDsp, &mVorbisBlock);
         if (r != 0) {
           Cleanup();
           return NS_ERROR_FAILURE;
         }
 
         mInfo.mAudio.mRate = mVorbisDsp.vi->rate;
         mInfo.mAudio.mChannels = mVorbisDsp.vi->channels;
-        mChannels = mInfo.mAudio.mChannels;
 #ifdef MOZ_OPUS
       } else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
         unsigned char* data = 0;
         size_t length = 0;
         r = nestegg_track_codec_data(mContext, track, 0, &data, &length);
         if (r == -1) {
           Cleanup();
           return NS_ERROR_FAILURE;
@@ -440,27 +463,27 @@ nsresult WebMReader::ReadMetadata(MediaI
           return NS_ERROR_FAILURE;
         }
 
         if (!InitOpusDecoder()) {
           Cleanup();
           return NS_ERROR_FAILURE;
         }
 
-        if (static_cast<int64_t>(mCodecDelay) != FramesToUsecs(mOpusParser->mPreSkip, mOpusParser->mRate).value()) {
+        if (int64_t(mCodecDelay) != FramesToUsecs(mOpusParser->mPreSkip,
+                                                  mOpusParser->mRate).value()) {
           LOG(PR_LOG_WARNING,
-              ("Invalid Opus header: CodecDelay and pre-skip do not match!\n"));
+              ("Invalid Opus header: CodecDelay and pre-skip do not match!"));
           Cleanup();
           return NS_ERROR_FAILURE;
         }
 
         mInfo.mAudio.mRate = mOpusParser->mRate;
 
         mInfo.mAudio.mChannels = mOpusParser->mChannels;
-        mChannels = mInfo.mAudio.mChannels;
         mSeekPreroll = params.seek_preroll;
 #endif
       } else {
         Cleanup();
         return NS_ERROR_FAILURE;
       }
     }
   }
@@ -481,43 +504,28 @@ WebMReader::IsMediaSeekable()
 #ifdef MOZ_OPUS
 bool WebMReader::InitOpusDecoder()
 {
   int r;
 
   NS_ASSERTION(mOpusDecoder == nullptr, "leaking OpusDecoder");
 
   mOpusDecoder = opus_multistream_decoder_create(mOpusParser->mRate,
-                                             mOpusParser->mChannels,
-                                             mOpusParser->mStreams,
-                                             mOpusParser->mCoupledStreams,
-                                             mOpusParser->mMappingTable,
-                                             &r);
+                                                 mOpusParser->mChannels,
+                                                 mOpusParser->mStreams,
+                                                 mOpusParser->mCoupledStreams,
+                                                 mOpusParser->mMappingTable,
+                                                 &r);
   mSkip = mOpusParser->mPreSkip;
+  mPaddingDiscarded = false;
 
   return r == OPUS_OK;
 }
 #endif
 
-ogg_packet WebMReader::InitOggPacket(unsigned char* aData,
-                                       size_t aLength,
-                                       bool aBOS,
-                                       bool aEOS,
-                                       int64_t aGranulepos)
-{
-  ogg_packet packet;
-  packet.packet = aData;
-  packet.bytes = aLength;
-  packet.b_o_s = aBOS;
-  packet.e_o_s = aEOS;
-  packet.granulepos = aGranulepos;
-  packet.packetno = mPacketCount++;
-  return packet;
-}
- 
 bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
   int r = 0;
   unsigned int count = 0;
   r = nestegg_packet_count(aPacket, &count);
   if (r == -1) {
@@ -525,251 +533,289 @@ bool WebMReader::DecodeAudioPacket(neste
   }
 
   uint64_t tstamp = 0;
   r = nestegg_packet_tstamp(aPacket, &tstamp);
   if (r == -1) {
     return false;
   }
 
-  const uint32_t rate = mInfo.mAudio.mRate;
   uint64_t tstamp_usecs = tstamp / NS_PER_USEC;
   if (mAudioStartUsec == -1) {
     // This is the first audio chunk. Assume the start time of our decode
     // is the start of this chunk.
     mAudioStartUsec = tstamp_usecs;
   }
   // If there's a gap between the start of this audio chunk and the end of
   // the previous audio chunk, we need to increment the packet count so that
   // the vorbis decode doesn't use data from before the gap to help decode
   // from after the gap.
-  CheckedInt64 tstamp_frames = UsecsToFrames(tstamp_usecs, rate);
-  CheckedInt64 decoded_frames = UsecsToFrames(mAudioStartUsec, rate);
+  CheckedInt64 tstamp_frames = UsecsToFrames(tstamp_usecs, mInfo.mAudio.mRate);
+  CheckedInt64 decoded_frames = UsecsToFrames(mAudioStartUsec,
+                                              mInfo.mAudio.mRate);
   if (!tstamp_frames.isValid() || !decoded_frames.isValid()) {
     NS_WARNING("Int overflow converting WebM times to frames");
     return false;
   }
   decoded_frames += mAudioFrames;
   if (!decoded_frames.isValid()) {
     NS_WARNING("Int overflow adding decoded_frames");
     return false;
   }
   if (tstamp_frames.value() > decoded_frames.value()) {
 #ifdef DEBUG
-    CheckedInt64 usecs = FramesToUsecs(tstamp_frames.value() - decoded_frames.value(), rate);
-    LOG(PR_LOG_DEBUG, ("WebMReader detected gap of %lld, %lld frames, in audio stream\n",
+    int64_t gap_frames = tstamp_frames.value() - decoded_frames.value();
+    CheckedInt64 usecs = FramesToUsecs(gap_frames, mInfo.mAudio.mRate);
+    LOG(PR_LOG_DEBUG, ("WebMReader detected gap of %lld, %lld frames, in audio",
                        usecs.isValid() ? usecs.value() : -1,
-                       tstamp_frames.value() - decoded_frames.value()));
+                       gap_frames));
 #endif
     mPacketCount++;
     mAudioStartUsec = tstamp_usecs;
     mAudioFrames = 0;
   }
 
   int32_t total_frames = 0;
   for (uint32_t i = 0; i < count; ++i) {
     unsigned char* data;
     size_t length;
     r = nestegg_packet_data(aPacket, i, &data, &length);
     if (r == -1) {
       return false;
     }
     if (mAudioCodec == NESTEGG_CODEC_VORBIS) {
-      ogg_packet opacket = InitOggPacket(data, length, false, false, -1);
-
-      if (vorbis_synthesis(&mVorbisBlock, &opacket) != 0) {
-        return false;
-      }
-
-      if (vorbis_synthesis_blockin(&mVorbisDsp,
-                                   &mVorbisBlock) != 0) {
+      if (!DecodeVorbis(data, length, aOffset, tstamp_usecs, &total_frames)) {
         return false;
       }
-
-      VorbisPCMValue** pcm = 0;
-      int32_t frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm);
-      // If the first packet of audio in the media produces no data, we
-      // still need to produce an AudioData for it so that the correct media
-      // start time is calculated.  Otherwise we'd end up with a media start
-      // time derived from the timecode of the first packet that produced
-      // data.
-      if (frames == 0 && mAudioFrames == 0) {
-        AudioQueue().Push(new AudioData(aOffset, tstamp_usecs, 0, 0, nullptr, mChannels, rate));
-      }
-      while (frames > 0) {
-        nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[frames * mChannels]);
-        for (uint32_t j = 0; j < mChannels; ++j) {
-          VorbisPCMValue* channel = pcm[j];
-          for (uint32_t i = 0; i < uint32_t(frames); ++i) {
-            buffer[i*mChannels + j] = MOZ_CONVERT_VORBIS_SAMPLE(channel[i]);
-          }
-        }
-
-        CheckedInt64 duration = FramesToUsecs(frames, rate);
-        if (!duration.isValid()) {
-          NS_WARNING("Int overflow converting WebM audio duration");
-          return false;
-        }
-        CheckedInt64 total_duration = FramesToUsecs(total_frames, rate);
-        if (!total_duration.isValid()) {
-          NS_WARNING("Int overflow converting WebM audio total_duration");
-          return false;
-        }
-
-        CheckedInt64 time = total_duration + tstamp_usecs;
-        if (!time.isValid()) {
-          NS_WARNING("Int overflow adding total_duration and tstamp_usecs");
-          return false;
-        };
-
-        total_frames += frames;
-        AudioQueue().Push(new AudioData(aOffset,
-                                        time.value(),
-                                        duration.value(),
-                                        frames,
-                                        buffer.forget(),
-                                        mChannels,
-                                        rate));
-        mAudioFrames += frames;
-        if (vorbis_synthesis_read(&mVorbisDsp, frames) != 0) {
-          return false;
-        }
-
-        frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm);
-      }
     } else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
 #ifdef MOZ_OPUS
-      uint32_t channels = mOpusParser->mChannels;
-
-      // Maximum value is 63*2880, so there's no chance of overflow.
-      int32_t frames_number = opus_packet_get_nb_frames(data, length);
-
-      if (frames_number <= 0)
-        return false; // Invalid packet header.
-      int32_t samples = opus_packet_get_samples_per_frame(data,
-                                                          (opus_int32) rate);
-      int32_t frames = frames_number*samples;
-
-      // A valid Opus packet must be between 2.5 and 120 ms long.
-      if (frames < 120 || frames > 5760)
-        return false;
-      nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[frames * channels]);
-
-      // Decode to the appropriate sample type.
-#ifdef MOZ_SAMPLE_TYPE_FLOAT32
-      int ret = opus_multistream_decode_float(mOpusDecoder,
-                                              data, length,
-                                              buffer, frames, false);
-#else
-      int ret = opus_multistream_decode(mOpusDecoder,
-                                        data, length,
-                                        buffer, frames, false);
-#endif
-      if (ret < 0)
+      if (!DecodeOpus(data, length, aOffset, tstamp_usecs, aPacket)) {
         return false;
-      NS_ASSERTION(ret == frames, "Opus decoded too few audio samples");
-      CheckedInt64 startTime = tstamp_usecs;
-
-      // Trim the initial frames while the decoder is settling.
-      if (mSkip > 0) {
-        int32_t skipFrames = std::min(mSkip, frames);
-        if (skipFrames == frames) {
-          // discard the whole packet
-          mSkip -= frames;
-          LOG(PR_LOG_DEBUG, ("Opus decoder skipping %d frames"
-                             " (whole packet)", frames));
-          return true;
-        }
-        int32_t keepFrames = frames - skipFrames;
-        int samples = keepFrames * channels;
-        nsAutoArrayPtr<AudioDataValue> trimBuffer(new AudioDataValue[samples]);
-        PodCopy(trimBuffer.get(), buffer.get() + skipFrames*channels, samples);
-        startTime = startTime + FramesToUsecs(skipFrames, rate);
-        frames = keepFrames;
-        buffer = trimBuffer;
-
-        mSkip -= skipFrames;
-        LOG(PR_LOG_DEBUG, ("Opus decoder skipping %d frames", skipFrames));
-      }
-
-      int64_t discardPadding = 0;
-      r = nestegg_packet_discard_padding(aPacket, &discardPadding);
-      if (discardPadding > 0) {
-        CheckedInt64 discardFrames = UsecsToFrames(discardPadding / NS_PER_USEC, rate);
-        if (!discardFrames.isValid()) {
-          NS_WARNING("Int overflow in DiscardPadding");
-          return false;
-        }
-        if (discardFrames.value() >= frames) {
-          LOG(PR_LOG_DEBUG, ("Opus decoder discarding whole packet"
-                             " (%d frames) as padding (%lld discarded)",
-                             frames, discardFrames.value()));
-          return true;
-        }
-        int32_t keepFrames = frames - discardFrames.value();
-        int32_t samples = keepFrames * channels;
-        nsAutoArrayPtr<AudioDataValue> trimBuffer(new AudioDataValue[samples]);
-        PodCopy(trimBuffer.get(), buffer.get(), samples);
-        frames = keepFrames;
-        buffer = trimBuffer;
-      }
-
-      // Apply the header gain if one was specified.
-#ifdef MOZ_SAMPLE_TYPE_FLOAT32
-      if (mOpusParser->mGain != 1.0f) {
-        float gain = mOpusParser->mGain;
-        int samples = frames * channels;
-        for (int i = 0; i < samples; i++) {
-          buffer[i] *= gain;
-        }
-      }
-#else
-      if (mOpusParser->mGain_Q16 != 65536) {
-        int64_t gain_Q16 = mOpusParser->mGain_Q16;
-        int samples = frames * channels;
-        for (int i = 0; i < samples; i++) {
-          int32_t val = static_cast<int32_t>((gain_Q16*buffer[i] + 32768)>>16);
-          buffer[i] = static_cast<AudioDataValue>(MOZ_CLIP_TO_15(val));
-        }
       }
 #endif
-
-      // No channel mapping for more than 8 channels.
-      if (channels > 8) {
-        return false;
-      }
-
-      CheckedInt64 duration = FramesToUsecs(frames, rate);
-      if (!duration.isValid()) {
-        NS_WARNING("Int overflow converting WebM audio duration");
-        return false;
-      }
-      CheckedInt64 time = startTime - mCodecDelay;
-      if (!time.isValid()) {
-        NS_WARNING("Int overflow shifting tstamp by codec delay");
-        return false;
-      };
-      AudioQueue().Push(new AudioData(mDecoder->GetResource()->Tell(),
-                                      time.value(),
-                                      duration.value(),
-                                      frames,
-                                      buffer.forget(),
-                                      mChannels,
-                                      rate));
-
-      mAudioFrames += frames;
-#else
-      return false;
-#endif /* MOZ_OPUS */
     }
   }
 
   return true;
 }
 
+bool WebMReader::DecodeVorbis(const unsigned char* aData, size_t aLength,
+                              int64_t aOffset, uint64_t aTstampUsecs,
+                              int32_t* aTotalFrames)
+{
+  ogg_packet opacket = InitOggPacket(aData, aLength, false, false, -1,
+                                     mPacketCount++);
+
+  if (vorbis_synthesis(&mVorbisBlock, &opacket) != 0) {
+    return false;
+  }
+
+  if (vorbis_synthesis_blockin(&mVorbisDsp,
+                               &mVorbisBlock) != 0) {
+    return false;
+  }
+
+  VorbisPCMValue** pcm = 0;
+  int32_t frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm);
+  // If the first packet of audio in the media produces no data, we
+  // still need to produce an AudioData for it so that the correct media
+  // start time is calculated.  Otherwise we'd end up with a media start
+  // time derived from the timecode of the first packet that produced
+  // data.
+  if (frames == 0 && mAudioFrames == 0) {
+    AudioQueue().Push(new AudioData(aOffset, aTstampUsecs, 0, 0, nullptr,
+                                    mInfo.mAudio.mChannels,
+                                    mInfo.mAudio.mRate));
+  }
+  while (frames > 0) {
+    uint32_t channels = mInfo.mAudio.mChannels;
+    nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[frames*channels]);
+    for (uint32_t j = 0; j < channels; ++j) {
+      VorbisPCMValue* channel = pcm[j];
+      for (uint32_t i = 0; i < uint32_t(frames); ++i) {
+        buffer[i*channels + j] = MOZ_CONVERT_VORBIS_SAMPLE(channel[i]);
+      }
+    }
+
+    CheckedInt64 duration = FramesToUsecs(frames, mInfo.mAudio.mRate);
+    if (!duration.isValid()) {
+      NS_WARNING("Int overflow converting WebM audio duration");
+      return false;
+    }
+    CheckedInt64 total_duration = FramesToUsecs(*aTotalFrames,
+                                                mInfo.mAudio.mRate);
+    if (!total_duration.isValid()) {
+      NS_WARNING("Int overflow converting WebM audio total_duration");
+      return false;
+    }
+
+    CheckedInt64 time = total_duration + aTstampUsecs;
+    if (!time.isValid()) {
+      NS_WARNING("Int overflow adding total_duration and aTstampUsecs");
+      return false;
+    };
+
+    *aTotalFrames += frames;
+    AudioQueue().Push(new AudioData(aOffset,
+                                    time.value(),
+                                    duration.value(),
+                                    frames,
+                                    buffer.forget(),
+                                    mInfo.mAudio.mChannels,
+                                    mInfo.mAudio.mRate));
+    mAudioFrames += frames;
+    if (vorbis_synthesis_read(&mVorbisDsp, frames) != 0) {
+      return false;
+    }
+
+    frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm);
+  }
+
+  return true;
+}
+
+#ifdef MOZ_OPUS
+bool WebMReader::DecodeOpus(const unsigned char* aData, size_t aLength,
+                            int64_t aOffset, uint64_t aTstampUsecs,
+                            nestegg_packet* aPacket)
+{
+  uint32_t channels = mOpusParser->mChannels;
+  // No channel mapping for more than 8 channels.
+  if (channels > 8) {
+    return false;
+  }
+
+  if (mPaddingDiscarded) {
+    // Discard padding should be used only on the final packet, so
+    // decoding after a padding discard is invalid.
+    LOG(PR_LOG_DEBUG, ("Opus error, discard padding on interstitial packet"));
+    GetCallback()->OnDecodeError();
+    return false;
+  }
+
+  // Maximum value is 63*2880, so there's no chance of overflow.
+  int32_t frames_number = opus_packet_get_nb_frames(aData, aLength);
+  if (frames_number <= 0) {
+    return false; // Invalid packet header.
+  }
+
+  int32_t samples =
+    opus_packet_get_samples_per_frame(aData, opus_int32(mInfo.mAudio.mRate));
+
+  // A valid Opus packet must be between 2.5 and 120 ms long (48kHz).
+  int32_t frames = frames_number*samples;
+  if (frames < 120 || frames > 5760)
+    return false;
+
+  nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[frames * channels]);
+
+  // Decode to the appropriate sample type.
+#ifdef MOZ_SAMPLE_TYPE_FLOAT32
+  int ret = opus_multistream_decode_float(mOpusDecoder,
+                                          aData, aLength,
+                                          buffer, frames, false);
+#else
+  int ret = opus_multistream_decode(mOpusDecoder,
+                                    aData, aLength,
+                                    buffer, frames, false);
+#endif
+  if (ret < 0)
+    return false;
+  NS_ASSERTION(ret == frames, "Opus decoded too few audio samples");
+  CheckedInt64 startTime = aTstampUsecs;
+
+  // Trim the initial frames while the decoder is settling.
+  if (mSkip > 0) {
+    int32_t skipFrames = std::min<int32_t>(mSkip, frames);
+    int32_t keepFrames = frames - skipFrames;
+    LOG(PR_LOG_DEBUG, ("Opus decoder skipping %d of %d frames",
+                       skipFrames, frames));
+    PodMove(buffer.get(),
+            buffer.get() + skipFrames * channels,
+            keepFrames * channels);
+    startTime = startTime + FramesToUsecs(skipFrames, mInfo.mAudio.mRate);
+    frames = keepFrames;
+    mSkip -= skipFrames;
+  }
+
+  int64_t discardPadding = 0;
+  (void) nestegg_packet_discard_padding(aPacket, &discardPadding);
+  if (discardPadding < 0) {
+    // Negative discard padding is invalid.
+    LOG(PR_LOG_DEBUG, ("Opus error, negative discard padding"));
+    GetCallback()->OnDecodeError();
+    return false;
+  }
+  if (discardPadding > 0) {
+    CheckedInt64 discardFrames = UsecsToFrames(discardPadding / NS_PER_USEC,
+                                               mInfo.mAudio.mRate);
+    if (!discardFrames.isValid()) {
+      NS_WARNING("Int overflow in DiscardPadding");
+      return false;
+    }
+    if (discardFrames.value() > frames) {
+      // Discarding more than the entire packet is invalid.
+      LOG(PR_LOG_DEBUG, ("Opus error, discard padding larger than packet"));
+      GetCallback()->OnDecodeError();
+      return false;
+    }
+    LOG(PR_LOG_DEBUG, ("Opus decoder discarding %d of %d frames",
+                       int32_t(discardFrames.value()), frames));
+    // Padding discard is only supposed to happen on the final packet.
+    // Record the discard so we can return an error if another packet is
+    // decoded.
+    mPaddingDiscarded = true;
+    int32_t keepFrames = frames - discardFrames.value();
+    frames = keepFrames;
+  }
+
+  // Apply the header gain if one was specified.
+#ifdef MOZ_SAMPLE_TYPE_FLOAT32
+  if (mOpusParser->mGain != 1.0f) {
+    float gain = mOpusParser->mGain;
+    int samples = frames * channels;
+    for (int i = 0; i < samples; i++) {
+      buffer[i] *= gain;
+    }
+  }
+#else
+  if (mOpusParser->mGain_Q16 != 65536) {
+    int64_t gain_Q16 = mOpusParser->mGain_Q16;
+    int samples = frames * channels;
+    for (int i = 0; i < samples; i++) {
+      int32_t val = static_cast<int32_t>((gain_Q16*buffer[i] + 32768)>>16);
+      buffer[i] = static_cast<AudioDataValue>(MOZ_CLIP_TO_15(val));
+    }
+  }
+#endif
+
+  CheckedInt64 duration = FramesToUsecs(frames, mInfo.mAudio.mRate);
+  if (!duration.isValid()) {
+    NS_WARNING("Int overflow converting WebM audio duration");
+    return false;
+  }
+  CheckedInt64 time = startTime - mCodecDelay;
+  if (!time.isValid()) {
+    NS_WARNING("Int overflow shifting tstamp by codec delay");
+    return false;
+  };
+  AudioQueue().Push(new AudioData(aOffset,
+                                  time.value(),
+                                  duration.value(),
+                                  frames,
+                                  buffer.forget(),
+                                  mInfo.mAudio.mChannels,
+                                  mInfo.mAudio.mRate));
+
+  mAudioFrames += frames;
+
+  return true;
+}
+#endif /* MOZ_OPUS */
+
 nsReturnRef<NesteggPacketHolder> WebMReader::NextPacket(TrackType aTrackType)
 {
   // The packet queue that packets will be pushed on if they
   // are not the type we are interested in.
   WebMPacketQueue& otherPackets =
     aTrackType == VIDEO ? mAudioPackets : mVideoPackets;
 
   // The packet queue for the type that we are interested in.
@@ -930,19 +976,19 @@ bool WebMReader::DecodeVideoFrame(bool &
       parsed++; // Assume 1 frame per chunk.
       continue;
     }
 
     vpx_codec_iter_t  iter = nullptr;
     vpx_image_t      *img;
 
     while ((img = vpx_codec_get_frame(&mVPX, &iter))) {
-      NS_ASSERTION(img->fmt == VPX_IMG_FMT_I420, "WebM image format is not I420");
+      NS_ASSERTION(img->fmt == VPX_IMG_FMT_I420, "WebM image format not I420");
 
-      // Chroma shifts are rounded down as per the decoding examples in the VP8 SDK
+      // Chroma shifts are rounded down as per the decoding examples in the SDK
       VideoData::YCbCrBuffer b;
       b.mPlanes[0].mData = img->planes[0];
       b.mPlanes[0].mStride = img->stride[0];
       b.mPlanes[0].mHeight = img->d_h;
       b.mPlanes[0].mWidth = img->d_w;
       b.mPlanes[0].mOffset = b.mPlanes[0].mSkip = 0;
 
       b.mPlanes[1].mData = img->planes[1];
@@ -955,30 +1001,31 @@ bool WebMReader::DecodeVideoFrame(bool &
       b.mPlanes[2].mStride = img->stride[2];
       b.mPlanes[2].mHeight = (img->d_h + 1) >> img->y_chroma_shift;
       b.mPlanes[2].mWidth = (img->d_w + 1) >> img->x_chroma_shift;
       b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0;
 
       IntRect picture = ToIntRect(mPicture);
       if (img->d_w != static_cast<uint32_t>(mInitialFrame.width) ||
           img->d_h != static_cast<uint32_t>(mInitialFrame.height)) {
-        // Frame size is different from what the container reports. This is legal
-        // in WebM, and we will preserve the ratio of the crop rectangle as it
-        // was reported relative to the picture size reported by the container.
+        // Frame size is different from what the container reports. This is
+        // legal in WebM, and we will preserve the ratio of the crop rectangle
+        // as it was reported relative to the picture size reported by the
+        // container.
         picture.x = (mPicture.x * img->d_w) / mInitialFrame.width;
         picture.y = (mPicture.y * img->d_h) / mInitialFrame.height;
         picture.width = (img->d_w * mPicture.width) / mInitialFrame.width;
         picture.height = (img->d_h * mPicture.height) / mInitialFrame.height;
       }
 
       VideoData *v = VideoData::Create(mInfo.mVideo,
                                        mDecoder->GetImageContainer(),
                                        holder->mOffset,
                                        tstamp_usecs,
-                                       (next_tstamp / NS_PER_USEC) - tstamp_usecs,
+                                       (next_tstamp / NS_PER_USEC)-tstamp_usecs,
                                        b,
                                        si.is_kf,
                                        -1,
                                        picture);
       if (!v) {
         return false;
       }
       parsed++;
@@ -1007,30 +1054,34 @@ nsresult WebMReader::Seek(int64_t aTarge
                      this, mDecoder, double(aTarget) / USECS_PER_S));
   if (NS_FAILED(ResetDecode())) {
     return NS_ERROR_FAILURE;
   }
   uint32_t trackToSeek = mHasVideo ? mVideoTrack : mAudioTrack;
   uint64_t target = aTarget * NS_PER_USEC;
 
   if (mSeekPreroll) {
-    target = std::max(static_cast<uint64_t>(aStartTime * NS_PER_USEC), target - mSeekPreroll);
+    target = std::max(uint64_t(aStartTime * NS_PER_USEC),
+                      target - mSeekPreroll);
   }
   int r = nestegg_track_seek(mContext, trackToSeek, target);
   if (r != 0) {
+    LOG(PR_LOG_DEBUG, ("Reader [%p]: track_seek for track %u failed, r=%d",
+                       this, trackToSeek, r));
+
     // Try seeking directly based on cluster information in memory.
     int64_t offset = 0;
     bool rv = mBufferedState->GetOffsetForTime(target, &offset);
     if (!rv) {
       return NS_ERROR_FAILURE;
     }
 
     r = nestegg_offset_seek(mContext, offset);
-    LOG(PR_LOG_DEBUG, ("Reader [%p]: track_seek for %u failed, offset_seek to %lld r=%d",
-                       this, trackToSeek, offset, r));
+    LOG(PR_LOG_DEBUG, ("Reader [%p]: attempted offset_seek to %lld r=%d",
+                       this, offset, r));
     if (r != 0) {
       return NS_ERROR_FAILURE;
     }
   }
   return NS_OK;
 }
 
 nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
@@ -1067,31 +1118,33 @@ nsresult WebMReader::GetBuffered(dom::Ti
                    "startOffset negative or larger than start time");
       if (!(startOffset >= 0 && uint64_t(startOffset) <= start)) {
         startOffset = 0;
       }
       double startTime = (start - startOffset) / NS_PER_S;
       double endTime = (end - startOffset) / NS_PER_S;
       // If this range extends to the end of the file, the true end time
       // is the file's duration.
-      if (mContext && resource->IsDataCachedToEndOfResource(ranges[index].mStart)) {
+      if (mContext &&
+          resource->IsDataCachedToEndOfResource(ranges[index].mStart)) {
         uint64_t duration = 0;
         if (nestegg_duration(mContext, &duration) == 0) {
           endTime = duration / NS_PER_S;
         }
       }
 
       aBuffered->Add(startTime, endTime);
     }
   }
 
   return NS_OK;
 }
 
-void WebMReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
+void WebMReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength,
+                                   int64_t aOffset)
 {
   mBufferedState->NotifyDataArrived(aBuffer, aLength, aOffset);
 }
 
 int64_t WebMReader::GetEvictionOffset(double aTime)
 {
   int64_t offset;
   if (!mBufferedState->GetOffsetForTime(aTime * NS_PER_S, &offset)) {
--- a/content/media/webm/WebMReader.h
+++ b/content/media/webm/WebMReader.h
@@ -129,19 +129,21 @@ public:
   virtual bool HasVideo()
   {
     NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
     return mHasVideo;
   }
 
   virtual nsresult ReadMetadata(MediaInfo* aInfo,
                                 MetadataTags** aTags);
-  virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
+  virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
+                        int64_t aCurrentTime);
   virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
+  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength,
+                                 int64_t aOffset);
   virtual int64_t GetEvictionOffset(double aTime);
 
   virtual bool IsMediaSeekable() MOZ_OVERRIDE;
 
 protected:
   // Value passed to NextPacket to determine if we are reading a video or an
   // audio packet.
   enum TrackType {
@@ -152,35 +154,36 @@ protected:
   // Read a packet from the nestegg file. Returns nullptr if all packets for
   // the particular track have been read. Pass VIDEO or AUDIO to indicate the
   // type of the packet we want to read.
   nsReturnRef<NesteggPacketHolder> NextPacket(TrackType aTrackType);
 
   // Pushes a packet to the front of the video packet queue.
   virtual void PushVideoPacket(NesteggPacketHolder* aItem);
 
-  // Returns an initialized ogg packet with data obtained from the WebM container.
-  ogg_packet InitOggPacket(unsigned char* aData,
-                           size_t aLength,
-                           bool aBOS,
-                           bool aEOS,
-                           int64_t aGranulepos);
-
 #ifdef MOZ_OPUS
   // Setup opus decoder
   bool InitOpusDecoder();
 #endif
 
   // Decode a nestegg packet of audio data. Push the audio data on the
   // audio queue. Returns true when there's more audio to decode,
   // false if the audio is finished, end of file has been reached,
   // or an un-recoverable read error has occured. The reader's monitor
   // must be held during this call. The caller is responsible for freeing
   // aPacket.
   bool DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset);
+  bool DecodeVorbis(const unsigned char* aData, size_t aLength,
+                    int64_t aOffset, uint64_t aTstampUsecs,
+                    int32_t* aTotalFrames);
+#ifdef MOZ_OPUS
+  bool DecodeOpus(const unsigned char* aData, size_t aLength,
+                  int64_t aOffset, uint64_t aTstampUsecs,
+                  nestegg_packet* aPacket);
+#endif
 
   // Release context and set to null. Called when an error occurs during
   // reading metadata or destruction of the reader itself.
   void Cleanup();
 
 private:
   // libnestegg context for webm container. Access on state machine thread
   // or decoder thread only.
@@ -189,26 +192,24 @@ private:
   // VP8 decoder state
   vpx_codec_ctx_t mVPX;
 
   // Vorbis decoder state
   vorbis_info mVorbisInfo;
   vorbis_comment mVorbisComment;
   vorbis_dsp_state mVorbisDsp;
   vorbis_block mVorbisBlock;
-  uint32_t mPacketCount;
-  uint32_t mChannels;
-
+  int64_t mPacketCount;
 
 #ifdef MOZ_OPUS
   // Opus decoder state
   nsAutoPtr<OpusParser> mOpusParser;
   OpusMSDecoder *mOpusDecoder;
-  int mSkip;        // Number of samples left to trim before playback.
-  uint64_t mSeekPreroll; // Number of nanoseconds that must be discarded after seeking.
+  uint16_t mSkip;        // Samples left to trim before playback.
+  uint64_t mSeekPreroll; // Nanoseconds to discard after seeking.
 #endif
 
   // Queue of video and audio packets that have been read but not decoded. These
   // must only be accessed from the state machine thread.
   WebMPacketQueue mVideoPackets;
   WebMPacketQueue mAudioPackets;
 
   // Index of video and audio track to play
@@ -242,13 +243,20 @@ private:
   // Codec ID of audio track
   int mAudioCodec;
   // Codec ID of video track
   int mVideoCodec;
 
   // Booleans to indicate if we have audio and/or video data
   bool mHasVideo;
   bool mHasAudio;
+
+#ifdef MOZ_OPUS
+  // Opus padding should only be discarded on the final packet.  Once this
+  // is set to true, if the reader attempts to decode any further packets it
+  // will raise an error so we can indicate that the file is invalid.
+  bool mPaddingDiscarded;
+#endif
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1,15 +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 "CanvasRenderingContext2D.h"
 
+#include "mozilla/gfx/Helpers.h"
 #include "nsXULElement.h"
 
 #include "nsIServiceManager.h"
 #include "nsMathUtils.h"
 #include "SVGImageContext.h"
 
 #include "nsContentUtils.h"
 
@@ -371,17 +372,17 @@ public:
 
     RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
 
     RefPtr<SourceSurface> fillPaint =
       DoSourcePaint(mFillPaintRect, CanvasRenderingContext2D::Style::FILL);
     RefPtr<SourceSurface> strokePaint =
       DoSourcePaint(mStrokePaintRect, CanvasRenderingContext2D::Style::STROKE);
 
-    AutoSaveTransform autoSaveTransform(mFinalTarget);
+    AutoRestoreTransform autoRestoreTransform(mFinalTarget);
     mFinalTarget->SetTransform(Matrix());
 
     mgfx::FilterSupport::RenderFilterDescription(
       mFinalTarget, mCtx->CurrentState().filter,
       mgfx::Rect(mPostFilterBounds),
       snapshot, mSourceGraphicRect,
       fillPaint, mFillPaintRect,
       strokePaint, mStrokePaintRect,
@@ -2163,17 +2164,18 @@ public:
                                    nsPresContext::AppUnitsPerCSSPixel());
   }
 
   virtual float GetExLength() const MOZ_OVERRIDE
   {
     gfxTextPerfMetrics* tp = mPresContext->GetTextPerfMetrics();
     nsRefPtr<nsFontMetrics> fontMetrics;
     nsDeviceContext* dc = mPresContext->DeviceContext();
-    dc->GetMetricsFor(mFont, mFontLanguage, nullptr, tp,
+    dc->GetMetricsFor(mFont, mFontLanguage, gfxFont::eHorizontal,
+                      nullptr, tp,
                       *getter_AddRefs(fontMetrics));
     return NSAppUnitsToFloatPixels(fontMetrics->XHeight(),
                                    nsPresContext::AppUnitsPerCSSPixel());
   }
 
   virtual gfx::Size GetSize() const MOZ_OVERRIDE
   { return Size(mSize); }
 
@@ -3437,17 +3439,17 @@ CanvasRenderingContext2D::DrawOrMeasureT
     anchorX = 1;
   }
 
   processor.mPt.x -= anchorX * totalWidth;
 
   // offset pt.y based on text baseline
   processor.mFontgrp->UpdateUserFonts(); // ensure user font generation is current
   const gfxFont::Metrics& fontMetrics =
-    processor.mFontgrp->GetFirstValidFont()->GetMetrics();
+    processor.mFontgrp->GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal); // XXX vertical?
 
   gfxFloat anchorY;
 
   switch (state.textBaseline)
   {
   case TextBaseline::HANGING:
       // fall through; best we can do with the information available
   case TextBaseline::TOP:
@@ -3978,16 +3980,20 @@ CanvasRenderingContext2D::DrawDirectlyTo
   dest.Scale(contextScale.width, contextScale.height);
 
   // Scale the image size to the dest rect, and adjust the source rect to match.
   gfxSize scale(dest.width / src.width, dest.height / src.height);
   nsIntSize scaledImageSize(std::ceil(imgSize.width * scale.width),
                             std::ceil(imgSize.height * scale.height));
   src.Scale(scale.width, scale.height);
 
+  // We're wrapping tempTarget's (our) DrawTarget here, so we need to restore
+  // the matrix even though this is a temp gfxContext.
+  AutoRestoreTransform autoRestoreTransform(mTarget);
+
   nsRefPtr<gfxContext> context = new gfxContext(tempTarget);
   context->SetMatrix(contextMatrix.
                        Scale(1.0 / contextScale.width,
                              1.0 / contextScale.height).
                        Translate(dest.x - src.x, dest.y - src.y));
 
   // FLAG_CLAMP is added for increased performance, since we never tile here.
   uint32_t modifiedFlags = image.mDrawingFlags | imgIContainer::FLAG_CLAMP;
--- a/dom/fetch/Headers.cpp
+++ b/dom/fetch/Headers.cpp
@@ -292,19 +292,23 @@ Headers::IsForbiddenRequestNoCorsHeader(
 bool
 Headers::IsForbiddenResponseHeader(const nsACString& aName) const
 {
   return mGuard == HeadersGuardEnum::Response &&
          nsContentUtils::IsForbiddenResponseHeader(aName);
 }
 
 void
-Headers::Fill(const Headers& aInit, ErrorResult&)
+Headers::Fill(const Headers& aInit, ErrorResult& aRv)
 {
-  mList = aInit.mList;
+  const nsTArray<Entry>& list = aInit.mList;
+  for (uint32_t i = 0; i < list.Length() && !aRv.Failed(); ++i) {
+    const Entry& entry = list[i];
+    Append(entry.mName, entry.mValue, aRv);
+  }
 }
 
 void
 Headers::Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv)
 {
   for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) {
     const Sequence<nsCString>& tuple = aInit[i];
     if (tuple.Length() != 2) {
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -3905,30 +3905,17 @@ public:
     return !mMaybeBlockedDatabases.IsEmpty();
   }
 #endif
 
 protected:
   FactoryOp(Factory* aFactory,
             already_AddRefed<ContentParent> aContentParent,
             const CommonFactoryRequestParams& aCommonParams,
-            bool aDeleting)
-    : mFactory(aFactory)
-    , mContentParent(Move(aContentParent))
-    , mCommonParams(aCommonParams)
-    , mState(State_Initial)
-    , mStoragePrivilege(mozilla::dom::quota::Content)
-    , mEnforcingQuota(true)
-    , mDeleting(aDeleting)
-    , mBlockedQuotaManager(false)
-    , mChromeWriteAccessAllowed(false)
-  {
-    AssertIsOnBackgroundThread();
-    MOZ_ASSERT(aFactory);
-  }
+            bool aDeleting);
 
   virtual
   ~FactoryOp()
   {
     // Normally this would be out-of-line since it is a virtual function but
     // MSVC 2010 fails to link for some reason if it is not inlined here...
     MOZ_ASSERT_IF(OperationMayProceed(),
                   mState == State_Initial || mState == State_Completed);
@@ -5070,30 +5057,52 @@ class QuotaClient MOZ_FINAL
   bool mShutdownRequested;
 
 public:
   QuotaClient();
 
   static QuotaClient*
   GetInstance()
   {
+    MOZ_ASSERT(NS_IsMainThread());
+
     return sInstance;
   }
 
+  static bool
+  IsShuttingDownOnMainThread()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (sInstance) {
+      return sInstance->mShutdownRequested;
+    }
+
+    return QuotaManager::IsShuttingDown();
+  }
+
+  static bool
+  IsShuttingDownOnNonMainThread()
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    return QuotaManager::IsShuttingDown();
+  }
+
+  bool
+  IsShuttingDown() const
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    return mShutdownRequested;
+  }
+
   void
   NoteBackgroundThread(nsIEventTarget* aBackgroundThread);
 
-  bool
-  HasShutDown() const
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    return mShutdownRequested;
-  }
-
   NS_INLINE_DECL_REFCOUNTING(QuotaClient)
 
   virtual mozilla::dom::quota::Client::Type
   GetType() MOZ_OVERRIDE;
 
   virtual nsresult
   InitOrigin(PersistenceType aPersistenceType,
              const nsACString& aGroup,
@@ -5552,27 +5561,32 @@ AllocPBackgroundIDBFactoryParent(PBackgr
 
   if (BackgroundParent::IsOtherProcessActor(aManager)) {
     if (NS_WARN_IF(aOptionalWindowId.type() != OptionalWindowId::Tvoid_t)) {
       ASSERT_UNLESS_FUZZING();
       return nullptr;
     }
   }
 
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread())) {
+    return nullptr;
+  }
+
   nsRefPtr<Factory> actor = Factory::Create(aOptionalWindowId);
   return actor.forget().take();
 }
 
 bool
 RecvPBackgroundIDBFactoryConstructor(PBackgroundParent* /* aManager */,
                                      PBackgroundIDBFactoryParent* aActor,
                                      const OptionalWindowId& aOptionalWindowId)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread());
 
   return true;
 }
 
 bool
 DeallocPBackgroundIDBFactoryParent(PBackgroundIDBFactoryParent* aActor)
 {
   AssertIsOnBackgroundThread();
@@ -5746,28 +5760,30 @@ FullDatabaseMetadata::Duplicate() const
 
 uint64_t Factory::sFactoryInstanceCount = 0;
 
 Factory::Factory(const OptionalWindowId& aOptionalWindowId)
   : mOptionalWindowId(aOptionalWindowId)
   , mActorDestroyed(false)
 {
   AssertIsOnBackgroundThread();
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread());
 }
 
 Factory::~Factory()
 {
   MOZ_ASSERT(mActorDestroyed);
 }
 
 // static
 already_AddRefed<Factory>
 Factory::Create(const OptionalWindowId& aOptionalWindowId)
 {
   AssertIsOnBackgroundThread();
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread());
 
   // If this is the first instance then we need to do some initialization.
   if (!sFactoryInstanceCount) {
     if (!gTransactionThreadPool) {
       nsRefPtr<TransactionThreadPool> threadPool =
         TransactionThreadPool::Create();
       if (NS_WARN_IF(!threadPool)) {
         return nullptr;
@@ -5867,16 +5883,20 @@ Factory::RecvDeleteMe()
 
 PBackgroundIDBFactoryRequestParent*
 Factory::AllocPBackgroundIDBFactoryRequestParent(
                                             const FactoryRequestParams& aParams)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aParams.type() != FactoryRequestParams::T__None);
 
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread())) {
+    return nullptr;
+  }
+
   const CommonFactoryRequestParams* commonParams;
 
   switch (aParams.type()) {
     case FactoryRequestParams::TOpenDatabaseRequestParams: {
       const OpenDatabaseRequestParams& params =
          aParams.get_OpenDatabaseRequestParams();
       commonParams = &params.commonParams();
       break;
@@ -5928,16 +5948,17 @@ Factory::AllocPBackgroundIDBFactoryReque
 bool
 Factory::RecvPBackgroundIDBFactoryRequestConstructor(
                                      PBackgroundIDBFactoryRequestParent* aActor,
                                      const FactoryRequestParams& aParams)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
   MOZ_ASSERT(aParams.type() != FactoryRequestParams::T__None);
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread());
 
   auto* op = static_cast<FactoryOp*>(aActor);
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(op)));
   return true;
 }
 
 bool
@@ -10299,27 +10320,47 @@ AutoSetProgressHandler::Register(
   MOZ_ASSERT(!oldProgressHandler);
 
   mConnection = aConnection;
   mDEBUGDatabaseOp = aDatabaseOp;
 
   return NS_OK;
 }
 
+FactoryOp::FactoryOp(Factory* aFactory,
+                     already_AddRefed<ContentParent> aContentParent,
+                     const CommonFactoryRequestParams& aCommonParams,
+                     bool aDeleting)
+  : mFactory(aFactory)
+  , mContentParent(Move(aContentParent))
+  , mCommonParams(aCommonParams)
+  , mState(State_Initial)
+  , mStoragePrivilege(mozilla::dom::quota::Content)
+  , mEnforcingQuota(true)
+  , mDeleting(aDeleting)
+  , mBlockedQuotaManager(false)
+  , mChromeWriteAccessAllowed(false)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aFactory);
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread());
+}
+
 nsresult
 FactoryOp::Open()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == State_Initial);
 
   // Swap this to the stack now to ensure that we release it on this thread.
   nsRefPtr<ContentParent> contentParent;
   mContentParent.swap(contentParent);
 
-  if (!OperationMayProceed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnMainThread()) ||
+      !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   PermissionRequestBase::PermissionValue permission;
   nsresult rv = CheckPermission(contentParent, &permission);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -10387,17 +10428,18 @@ FactoryOp::RetryCheckPermission()
   MOZ_ASSERT(mState == State_PermissionRetry);
   MOZ_ASSERT(mCommonParams.principalInfo().type() ==
                PrincipalInfo::TContentPrincipalInfo);
 
   // Swap this to the stack now to ensure that we release it on this thread.
   nsRefPtr<ContentParent> contentParent;
   mContentParent.swap(contentParent);
 
-  if (!OperationMayProceed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnMainThread()) ||
+      !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   PermissionRequestBase::PermissionValue permission;
   nsresult rv = CheckPermission(contentParent, &permission);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -10423,26 +10465,24 @@ FactoryOp::RetryCheckPermission()
 }
 
 nsresult
 FactoryOp::SendToIOThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == State_OpenPending);
 
-  if (!OperationMayProceed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnMainThread()) ||
+      !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   QuotaManager* quotaManager = QuotaManager::Get();
-  if (NS_WARN_IF(!quotaManager)) {
-    IDB_REPORT_INTERNAL_ERR();
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
+  MOZ_ASSERT(quotaManager);
 
   // Must set this before dispatching otherwise we will race with the IO thread.
   mState = State_DatabaseWorkOpen;
 
   nsresult rv = quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -10814,31 +10854,30 @@ nsresult
 FactoryOp::FinishOpen()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == State_Initial || mState == State_PermissionRetry);
   MOZ_ASSERT(!mOrigin.IsEmpty());
   MOZ_ASSERT(!mDatabaseId.IsEmpty());
   MOZ_ASSERT(!mBlockedQuotaManager);
   MOZ_ASSERT(!mContentParent);
+  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnMainThread());
 
   PersistenceType persistenceType = mCommonParams.metadata().persistenceType();
 
   // XXX This is temporary, but we don't currently support the explicit
   //     'persistent' storage type.
   if (persistenceType == PERSISTENCE_TYPE_PERSISTENT &&
       mCommonParams.metadata().persistenceTypeIsExplicit()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
-  QuotaManager* quotaManager;
-
-  if (QuotaManager::IsShuttingDown() ||
-      !(quotaManager = QuotaManager::GetOrCreate())) {
+  QuotaManager* quotaManager = QuotaManager::GetOrCreate();
+  if (NS_WARN_IF(!quotaManager)) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   nsresult rv =
     quotaManager->
       WaitForOpenAllowed(OriginOrPatternString::FromOrigin(mOrigin),
                          Nullable<PersistenceType>(persistenceType),
@@ -10997,19 +11036,18 @@ OpenDatabaseOp::OpenDatabaseOp(Factory* 
 nsresult
 OpenDatabaseOp::QuotaManagerOpen()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == State_OpenPending);
   MOZ_ASSERT(!mOfflineStorage);
 
   QuotaClient* quotaClient = QuotaClient::GetInstance();
-  MOZ_ASSERT(quotaClient);
-
-  if (NS_WARN_IF(quotaClient->HasShutDown())) {
+  if (NS_WARN_IF(!quotaClient) ||
+      NS_WARN_IF(quotaClient->IsShuttingDown())) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   QuotaManager* quotaManager = QuotaManager::Get();
   MOZ_ASSERT(quotaManager);
 
   nsRefPtr<DatabaseOfflineStorage> offlineStorage =
@@ -11046,17 +11084,18 @@ OpenDatabaseOp::DoDatabaseWork()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mState == State_DatabaseWorkOpen);
 
   PROFILER_LABEL("IndexedDB",
                  "OpenDatabaseHelper::DoDatabaseWork",
                  js::ProfileEntry::Category::STORAGE);
 
-  if (NS_WARN_IF(QuotaManager::IsShuttingDown()) || !OperationMayProceed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
+      !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   const nsString& databaseName = mCommonParams.metadata().name();
   PersistenceType persistenceType = mCommonParams.metadata().persistenceType();
 
   QuotaManager* quotaManager = QuotaManager::Get();
@@ -11497,17 +11536,19 @@ OpenDatabaseOp::BeginVersionChange()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State_BeginVersionChange);
   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   MOZ_ASSERT(mMetadata->mCommonMetadata.version() <= mRequestedVersion);
   MOZ_ASSERT(!mDatabase);
   MOZ_ASSERT(!mVersionChangeTransaction);
 
-  if (IsActorDestroyed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
+      !OperationMayProceed() ||
+      IsActorDestroyed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   EnsureDatabaseActor();
 
   if (mDatabase->IsInvalidated()) {
     IDB_REPORT_INTERNAL_ERR();
@@ -11653,17 +11694,19 @@ OpenDatabaseOp::SendUpgradeNeeded()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State_DatabaseWorkVersionChange);
   MOZ_ASSERT(mVersionChangeTransaction);
   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
   MOZ_ASSERT_IF(!IsActorDestroyed(), mDatabase);
 
-  if (IsActorDestroyed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
+      !OperationMayProceed() ||
+      IsActorDestroyed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   nsRefPtr<VersionChangeTransaction> transaction;
   mVersionChangeTransaction.swap(transaction);
 
   nsresult rv = EnsureDatabaseActorIsAlive();
@@ -12061,16 +12104,22 @@ OpenDatabaseOp::AssertMetadataConsistenc
 nsresult
 OpenDatabaseOp::
 VersionChangeOp::DoDatabaseWork(TransactionBase* aTransaction)
 {
   MOZ_ASSERT(aTransaction);
   aTransaction->AssertIsOnTransactionThread();
   MOZ_ASSERT(mOpenDatabaseOp->mState == State_DatabaseWorkVersionChange);
 
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
+      !OperationMayProceed()) {
+    IDB_REPORT_INTERNAL_ERR();
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
   PROFILER_LABEL("IndexedDB",
                  "VersionChangeOp::DoDatabaseWork",
                  js::ProfileEntry::Category::STORAGE);
 
   mozIStorageConnection* connection = aTransaction->Connection();
   MOZ_ASSERT(connection);
 
   TransactionBase::AutoSavepoint autoSave;
@@ -12262,17 +12311,18 @@ DeleteDatabaseOp::DoDatabaseWork()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mState == State_DatabaseWorkOpen);
 
   PROFILER_LABEL("IndexedDB",
                  "DeleteDatabaseOp::DoDatabaseWork",
                  js::ProfileEntry::Category::STORAGE);
 
-  if (!OperationMayProceed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
+      !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   const nsString& databaseName = mCommonParams.metadata().name();
   PersistenceType persistenceType = mCommonParams.metadata().persistenceType();
 
   QuotaManager* quotaManager = QuotaManager::Get();
@@ -12338,17 +12388,19 @@ DeleteDatabaseOp::DoDatabaseWork()
 
 nsresult
 DeleteDatabaseOp::BeginVersionChange()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State_BeginVersionChange);
   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
 
-  if (IsActorDestroyed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
+      !OperationMayProceed() ||
+      IsActorDestroyed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   DatabaseActorInfo* info;
   if (gLiveDatabaseHashtable->Get(mDatabaseId, &info)) {
     MOZ_ASSERT(!info->mWaitingFactoryOp);
 
@@ -12376,17 +12428,19 @@ DeleteDatabaseOp::BeginVersionChange()
 
 nsresult
 DeleteDatabaseOp::DispatchToWorkThread()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State_WaitingForTransactionsToComplete);
   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
 
-  if (IsActorDestroyed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
+      !OperationMayProceed() ||
+      IsActorDestroyed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   mState = State_DatabaseWorkVersionChange;
 
   nsRefPtr<VersionChangeOp> versionChangeOp = new VersionChangeOp(this);
 
@@ -12469,16 +12523,22 @@ DeleteDatabaseOp::SendResults()
 
 nsresult
 DeleteDatabaseOp::
 VersionChangeOp::RunOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mDeleteDatabaseOp->mState == State_DatabaseWorkVersionChange);
 
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnMainThread()) ||
+      !OperationMayProceed()) {
+    IDB_REPORT_INTERNAL_ERR();
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
   QuotaManager* quotaManager = QuotaManager::Get();
   MOZ_ASSERT(quotaManager);
 
   nsresult rv = quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
@@ -12492,17 +12552,18 @@ VersionChangeOp::RunOnIOThread()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mDeleteDatabaseOp->mState == State_DatabaseWorkVersionChange);
 
   PROFILER_LABEL("IndexedDB",
                  "DeleteDatabaseOp::VersionChangeOp::RunOnIOThread",
                  js::ProfileEntry::Category::STORAGE);
 
-  if (!OperationMayProceed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
+      !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   nsCOMPtr<nsIFile> directory =
     GetFileForPath(mDeleteDatabaseOp->mDatabaseDirectoryPath);
   if (NS_WARN_IF(!directory)) {
     IDB_REPORT_INTERNAL_ERR();
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -14,16 +14,17 @@
 
 #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"
@@ -702,16 +703,30 @@ 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,16 +375,18 @@ 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,16 +25,18 @@
 #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"
@@ -2692,16 +2694,44 @@ 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*
@@ -3817,19 +3847,16 @@ ContentParent::RecvKeywordToURI(const ns
 
     SerializeURI(uri, *aURI);
     return true;
 }
 
 bool
 ContentParent::ShouldContinueFromReplyTimeout()
 {
-    // The only time ContentParent sends blocking messages is for CPOWs, so
-    // timeouts should only ever occur in electrolysis-enabled sessions.
-    MOZ_ASSERT(BrowserTabsRemote());
     return false;
 }
 
 bool
 ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
                                          const nsString& aPageURL,
                                          const bool& aIsAudio,
                                          const bool& aIsVideo)
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -661,16 +661,21 @@ 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;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -9,16 +9,17 @@ 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;
@@ -327,16 +328,17 @@ 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;
@@ -484,16 +486,24 @@ 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/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -101,17 +101,16 @@ using namespace mozilla::jsipc;
 
 NS_IMPL_ISUPPORTS(ContentListener, nsIDOMEventListener)
 
 static const CSSSize kDefaultViewportSize(980, 480);
 
 static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect";
 static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
 
-static bool sCpowsEnabled = false;
 static int32_t sActiveDurationMs = 10;
 static bool sActiveDurationMsSet = false;
 
 typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
 static TabChildMap* sTabChildren;
 
 class TabChild::DelayedFireSingleTapEvent MOZ_FINAL : public nsITimerCallback
 {
@@ -2778,22 +2777,16 @@ TabChild::InitRenderingState()
     if (observerService) {
         observerService->AddObserver(this,
                                      BROWSER_ZOOM_TO_RECT,
                                      false);
         observerService->AddObserver(this,
                                      BEFORE_FIRST_PAINT,
                                      false);
     }
-
-    // This state can't change during the lifetime of the child.
-    sCpowsEnabled = BrowserTabsRemote();
-    if (Preferences::GetBool("dom.ipc.cpows.force-enabled", false))
-      sCpowsEnabled = true;
-
     return true;
 }
 
 void
 TabChild::SetBackgroundColor(const nscolor& aColor)
 {
   if (mLastBackgroundColor != aColor) {
     mLastBackgroundColor = aColor;
@@ -2912,20 +2905,18 @@ TabChild::DoSendBlockingMessage(JSContex
                                 InfallibleTArray<nsString>* aJSONRetVal,
                                 bool aIsSync)
 {
   ClonedMessageData data;
   if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
     return false;
   }
   InfallibleTArray<CpowEntry> cpows;
-  if (sCpowsEnabled) {
-    if (!Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
-      return false;
-    }
+  if (!Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
+    return false;
   }
   if (aIsSync) {
     return SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
                            Principal(aPrincipal), aJSONRetVal);
   }
 
   return CallRpcMessage(PromiseFlatString(aMessage), data, cpows,
                         Principal(aPrincipal), aJSONRetVal);
@@ -2938,20 +2929,18 @@ TabChild::DoSendAsyncMessage(JSContext* 
                              JS::Handle<JSObject *> aCpows,
                              nsIPrincipal* aPrincipal)
 {
   ClonedMessageData data;
   if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
     return false;
   }
   InfallibleTArray<CpowEntry> cpows;
-  if (sCpowsEnabled) {
-    if (!Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
-      return false;
-    }
+  if (!Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
+    return false;
   }
   return SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
                           Principal(aPrincipal));
 }
 
 TabChild*
 TabChild::GetFrom(nsIPresShell* aPresShell)
 {
--- a/dom/locales/en-US/chrome/security/security.properties
+++ b/dom/locales/en-US/chrome/security/security.properties
@@ -3,15 +3,17 @@
 BlockMixedDisplayContent = Blocked loading mixed display content "%1$S"
 BlockMixedActiveContent = Blocked loading mixed active content "%1$S"
 
 # CORS
 CrossSiteRequestBlocked=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. This can be fixed by moving the resource to the same domain or enabling CORS.
 
 # LOCALIZATION NOTE: Do not translate "Strict-Transport-Security" or "HSTS"
 InvalidSTSHeaders=The site specified an invalid Strict-Transport-Security header.
+# LOCALIZATION NOTE: Do not translate "Public-Key-Pins or HPKP"
+InvalidPKPHeaders=The site specified an invalid Public-Key-Pins header.
 InsecurePasswordsPresentOnPage=Password fields present on an insecure (http://) page. This is a security risk that allows user login credentials to be stolen.
 InsecureFormActionPasswordsPresent=Password fields present in a form with an insecure (http://) form action. This is a security risk that allows user login credentials to be stolen.
 InsecurePasswordsPresentOnIframe=Password fields present on an insecure (http://) iframe. This is a security risk that allows user login credentials to be stolen.
 LoadingMixedActiveContent=Loading mixed (insecure) active content on a secure page "%1$S"
 LoadingMixedDisplayContent=Loading mixed (insecure) display content on a secure page "%1$S"
 # LOCALIZATION NOTE: Do not translate "allow-scripts", "allow-same-origin", "sandbox" or "iframe"
 BothAllowScriptsAndSameOriginPresent=An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can remove its sandboxing.
--- a/dom/tests/browser/browser_test_new_window_from_content.js
+++ b/dom/tests/browser/browser_test_new_window_from_content.js
@@ -151,27 +151,17 @@ WindowOpenListener.prototype = {
  *
  * @return a Promise that resolves once the tab is loaded and ready.
  */
 function loadAndSelectTestTab() {
   let tab = gBrowser.addTab(kContentDoc);
   gBrowser.selectedTab = tab;
 
   let browser = gBrowser.getBrowserForTab(tab);
-
-  // Bug 687194 - Mochitest registers its chrome URLs after browser
-  // initialization, so the content processes don't pick them up. That
-  // means we can't load our frame script from its chrome URI, because
-  // the content process won't be able to find it.
-  //
-  // Instead, we resolve the chrome URI for the script to a file URI, which
-  // we can then pass to the content process, which it is able to find.
-  let registry = Cc['@mozilla.org/chrome/chrome-registry;1'].getService(Ci.nsIChromeRegistry);
-  let fileURI = registry.convertChromeURL(Services.io.newURI(kContentScript, null, null)).spec;
-  browser.messageManager.loadFrameScript(fileURI, false);
+  browser.messageManager.loadFrameScript(kContentScript, false);
 
   let deferred = Promise.defer();
   browser.addEventListener("DOMContentLoaded", function onBrowserLoad(aEvent) {
     browser.removeEventListener("DOMContentLoaded", onBrowserLoad);
     deferred.resolve(tab);
   });
 
   return deferred.promise;
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -3072,16 +3072,22 @@ WifiWorker.prototype = {
     dns1 = this.tetheringSettings[SETTINGS_WIFI_DNS1];
     dns2 = this.tetheringSettings[SETTINGS_WIFI_DNS2];
 
     // Check the format to prevent netd from crash.
     if (!ssid || ssid == "") {
       debug("Invalid SSID value.");
       return null;
     }
+    // Truncate ssid if its length of encoded to utf8 is longer than 32.
+    while (unescape(encodeURIComponent(ssid)).length > 32)
+    {
+      ssid = ssid.substring(0, ssid.length-1);
+    }
+
     if (securityType != WIFI_SECURITY_TYPE_NONE &&
         securityType != WIFI_SECURITY_TYPE_WPA_PSK &&
         securityType != WIFI_SECURITY_TYPE_WPA2_PSK) {
 
       debug("Invalid security type.");
       return null;
     }
     if (securityType != WIFI_SECURITY_TYPE_NONE && !securityId) {
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -131,17 +131,17 @@ InterpolationQualityFromFilter(Filter aF
 {
   switch (aFilter) {
     default:
     case Filter::LINEAR:
       return kCGInterpolationLow;
     case Filter::POINT:
       return kCGInterpolationNone;
     case Filter::GOOD:
-      return kCGInterpolationDefault;
+      return kCGInterpolationLow;
   }
 }
 
 
 DrawTargetCG::DrawTargetCG()
   : mColorSpace(nullptr)
   , mCg(nullptr)
 {
--- a/gfx/2d/Helpers.h
+++ b/gfx/2d/Helpers.h
@@ -6,27 +6,39 @@
 #ifndef MOZILLA_GFX_2D_HELPERS_H_
 #define MOZILLA_GFX_2D_HELPERS_H_
 
 #include "2D.h"
 
 namespace mozilla {
 namespace gfx {
 
-class AutoSaveTransform
+class AutoRestoreTransform
 {
  public:
-  explicit AutoSaveTransform(DrawTarget *aTarget)
+  explicit AutoRestoreTransform(DrawTarget *aTarget)
    : mDrawTarget(aTarget),
      mOldTransform(aTarget->GetTransform())
   {
   }
-  ~AutoSaveTransform()
+
+  void Init(DrawTarget *aTarget)
   {
-    mDrawTarget->SetTransform(mOldTransform);
+    MOZ_ASSERT(!mDrawTarget || aTarget == mDrawTarget);
+    if (!mDrawTarget) {
+      mDrawTarget = aTarget;
+      mOldTransform = aTarget->GetTransform();
+    }
+  }
+
+  ~AutoRestoreTransform()
+  {
+    if (mDrawTarget) {
+      mDrawTarget->SetTransform(mOldTransform);
+    }
   }
 
  private:
   RefPtr<DrawTarget> mDrawTarget;
   Matrix mOldTransform;
 };
 
 } // namespace gfx
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -246,17 +246,17 @@ BasicCompositor::DrawQuad(const gfx::Rec
 {
   RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget;
 
   // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing,
   // |dest| is a temporary surface.
   RefPtr<DrawTarget> dest = buffer;
 
   buffer->PushClipRect(aClipRect);
-  AutoSaveTransform autoSaveTransform(dest);
+  AutoRestoreTransform autoRestoreTransform(dest);
 
   Matrix newTransform;
   Rect transformBounds;
   gfx3DMatrix new3DTransform;
   IntPoint offset = mRenderTarget->GetOrigin();
 
   if (aTransform.Is2D()) {
     newTransform = aTransform.As2D();
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -57,16 +57,17 @@ public:
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
 
     void Init(nsDeviceContext* aContext);
     void Destroy();
 
     nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
+                           gfxFont::Orientation aOrientation,
                            gfxUserFontSet* aUserFontSet,
                            gfxTextPerfMetrics* aTextPerf,
                            nsFontMetrics*& aMetrics);
 
     void FontMetricsDeleted(const nsFontMetrics* aFontMetrics);
     void Compact();
     void Flush();
 
@@ -117,48 +118,50 @@ nsFontCache::Observe(nsISupports*, const
 {
     if (!nsCRT::strcmp(aTopic, "memory-pressure"))
         Compact();
     return NS_OK;
 }
 
 nsresult
 nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
+                           gfxFont::Orientation aOrientation,
                            gfxUserFontSet* aUserFontSet,
                            gfxTextPerfMetrics* aTextPerf,
                            nsFontMetrics*& aMetrics)
 {
     if (!aLanguage)
         aLanguage = mLocaleLanguage;
 
     // First check our cache
     // start from the end, which is where we put the most-recent-used element
 
     nsFontMetrics* fm;
     int32_t n = mFontMetrics.Length() - 1;
     for (int32_t i = n; i >= 0; --i) {
         fm = mFontMetrics[i];
         if (fm->Font().Equals(aFont) && fm->GetUserFontSet() == aUserFontSet &&
-            fm->Language() == aLanguage) {
+            fm->Language() == aLanguage && fm->Orientation() == aOrientation) {
             if (i != n) {
                 // promote it to the end of the cache
                 mFontMetrics.RemoveElementAt(i);
                 mFontMetrics.AppendElement(fm);
             }
             fm->GetThebesFontGroup()->UpdateUserFonts();
             NS_ADDREF(aMetrics = fm);
             return NS_OK;
         }
     }
 
     // It's not in the cache. Get font metrics and then cache them.
 
     fm = new nsFontMetrics();
     NS_ADDREF(fm);
-    nsresult rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet, aTextPerf);
+    nsresult rv = fm->Init(aFont, aLanguage, aOrientation, mContext,
+                           aUserFontSet, aTextPerf);
     if (NS_SUCCEEDED(rv)) {
         // the mFontMetrics list has the "head" at the end, because append
         // is cheaper than insert
         mFontMetrics.AppendElement(fm);
         aMetrics = fm;
         NS_ADDREF(aMetrics);
         return NS_OK;
     }
@@ -167,17 +170,18 @@ nsFontCache::GetMetricsFor(const nsFont&
 
     // One reason why Init() fails is because the system is running out of
     // resources. e.g., on Win95/98 only a very limited number of GDI
     // objects are available. Compact the cache and try again.
 
     Compact();
     fm = new nsFontMetrics();
     NS_ADDREF(fm);
-    rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet, aTextPerf);
+    rv = fm->Init(aFont, aLanguage, aOrientation, mContext, aUserFontSet,
+                  aTextPerf);
     if (NS_SUCCEEDED(rv)) {
         mFontMetrics.AppendElement(fm);
         aMetrics = fm;
         return NS_OK;
     }
     fm->Destroy();
     NS_RELEASE(fm);
 
@@ -255,28 +259,29 @@ nsDeviceContext::~nsDeviceContext()
         mFontCache->Destroy();
         NS_RELEASE(mFontCache);
     }
 }
 
 nsresult
 nsDeviceContext::GetMetricsFor(const nsFont& aFont,
                                nsIAtom* aLanguage,
+                               gfxFont::Orientation aOrientation,
                                gfxUserFontSet* aUserFontSet,
                                gfxTextPerfMetrics* aTextPerf,
                                nsFontMetrics*& aMetrics)
 {
     if (!mFontCache) {
         mFontCache = new nsFontCache();
         NS_ADDREF(mFontCache);
         mFontCache->Init(this);
     }
 
-    return mFontCache->GetMetricsFor(aFont, aLanguage, aUserFontSet,
-                                     aTextPerf, aMetrics);
+    return mFontCache->GetMetricsFor(aFont, aLanguage, aOrientation,
+                                     aUserFontSet, aTextPerf, aMetrics);
 }
 
 nsresult
 nsDeviceContext::FlushFontCache(void)
 {
     if (mFontCache)
         mFontCache->Flush();
     return NS_OK;
--- a/gfx/src/nsDeviceContext.h
+++ b/gfx/src/nsDeviceContext.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _NS_DEVICECONTEXT_H_
 #define _NS_DEVICECONTEXT_H_
 
 #include <stdint.h>                     // for uint32_t
 #include <sys/types.h>                  // for int32_t
 #include "gfxTypes.h"                   // for gfxFloat
+#include "gfxFont.h"                    // for gfxFont::Orientation
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsCoord.h"                    // for nscoord
 #include "nsError.h"                    // for nsresult
 #include "nsISupports.h"                // for NS_INLINE_DECL_REFCOUNTING
 #include "nsMathUtils.h"                // for NS_round
 #include "nscore.h"                     // for char16_t, nsAString
@@ -113,16 +114,17 @@ public:
      * an nsFont.
      * @param aFont font description to obtain metrics for
      * @param aLanguage the language of the document
      * @param aMetrics out parameter for font metrics
      * @param aUserFontSet user font set
      * @return error status
      */
     nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
+                           gfxFont::Orientation aOrientation,
                            gfxUserFontSet* aUserFontSet,
                            gfxTextPerfMetrics* aTextPerf,
                            nsFontMetrics*& aMetrics);
 
     /**
      * Notification when a font metrics instance created for this device is
      * about to be deleted
      */
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -99,24 +99,26 @@ nsFontMetrics::nsFontMetrics()
 nsFontMetrics::~nsFontMetrics()
 {
     if (mDeviceContext)
         mDeviceContext->FontMetricsDeleted(this);
 }
 
 nsresult
 nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage,
+                    gfxFont::Orientation aOrientation,
                     nsDeviceContext *aContext,
                     gfxUserFontSet *aUserFontSet,
                     gfxTextPerfMetrics *aTextPerf)
 {
     NS_ABORT_IF_FALSE(mP2A == 0, "already initialized");
 
     mFont = aFont;
     mLanguage = aLanguage;
+    mOrientation = aOrientation;
     mDeviceContext = aContext;
     mP2A = mDeviceContext->AppUnitsPerDevPixel();
 
     gfxFontStyle style(aFont.style,
                        aFont.weight,
                        aFont.stretch,
                        gfxFloat(aFont.size) / mP2A,
                        aLanguage,
@@ -142,17 +144,17 @@ nsFontMetrics::Destroy()
 }
 
 // XXXTODO get rid of this macro
 #define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
 #define CEIL_TO_TWIPS(x) (nscoord)ceil((x) * mP2A)
 
 const gfxFont::Metrics& nsFontMetrics::GetMetrics() const
 {
-    return mFontGroup->GetFirstValidFont()->GetMetrics();
+    return mFontGroup->GetFirstValidFont()->GetMetrics(mOrientation);
 }
 
 nscoord
 nsFontMetrics::XHeight()
 {
     return ROUND_TO_TWIPS(GetMetrics().xHeight);
 }
 
--- a/gfx/src/nsFontMetrics.h
+++ b/gfx/src/nsFontMetrics.h
@@ -52,16 +52,17 @@ public:
 
     /**
      * Initialize the font metrics. Call this after creating the font metrics.
      * Font metrics you get from the font cache do NOT need to be initialized
      *
      * @see nsDeviceContext#GetMetricsFor()
      */
     nsresult Init(const nsFont& aFont, nsIAtom* aLanguage,
+                  gfxFont::Orientation aOrientation,
                   nsDeviceContext *aContext,
                   gfxUserFontSet *aUserFontSet,
                   gfxTextPerfMetrics *aTextPerf);
 
     /**
      * Destroy this font metrics. This breaks the association between
      * the font metrics and the device context.
      */
@@ -169,16 +170,21 @@ public:
      */
     const nsFont &Font() { return mFont; }
 
     /**
      * Returns the language associated with these metrics
      */
     nsIAtom* Language() { return mLanguage; }
 
+    /**
+     * Returns the orientation (horizontal/vertical) of these metrics.
+     */
+    gfxFont::Orientation Orientation() { return mOrientation; }
+
     int32_t GetMaxStringLength();
 
     // Get the width for this string.  aWidth will be updated with the
     // width in points, not twips.  Callers must convert it if they
     // want it in another format.
     nscoord GetWidth(const char* aString, uint32_t aLength,
                      nsRenderingContext *aContext);
     nscoord GetWidth(const char16_t* aString, uint32_t aLength,
@@ -218,11 +224,12 @@ private:
     const gfxFont::Metrics& GetMetrics() const;
 
     nsFont mFont;
     nsRefPtr<gfxFontGroup> mFontGroup;
     nsCOMPtr<nsIAtom> mLanguage;
     nsDeviceContext *mDeviceContext;
     int32_t mP2A;
     bool mTextRunRTL;
+    gfxFont::Orientation mOrientation;
 };
 
 #endif /* NSFONTMETRICS__H__ */
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -168,23 +168,28 @@ IsJapaneseLocale()
             }
         } while (false);
     }
 
     return sIsJapanese;
 }
 
 void
-gfxAndroidPlatform::GetCommonFallbackFonts(const uint32_t aCh,
+gfxAndroidPlatform::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                            int32_t aRunScript,
                                            nsTArray<const char*>& aFontList)
 {
     static const char kDroidSansJapanese[] = "Droid Sans Japanese";
     static const char kMotoyaLMaru[] = "MotoyaLMaru";
 
+    if (aNextCh == 0xfe0fu) {
+        // if char is followed by VS16, try for a color emoji glyph
+        aFontList.AppendElement("Noto Color Emoji");
+    }
+
     if (IS_IN_BMP(aCh)) {
         // try language-specific "Droid Sans *" and "Noto Sans *" fonts for
         // certain blocks, as most devices probably have these
         uint8_t block = (aCh >> 8) & 0xff;
         switch (block) {
         case 0x05:
             aFontList.AppendElement("Droid Sans Hebrew");
             aFontList.AppendElement("Droid Sans Armenian");
--- a/gfx/thebes/gfxAndroidPlatform.h
+++ b/gfx/thebes/gfxAndroidPlatform.h
@@ -53,17 +53,17 @@ public:
                                           bool aItalic);
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
                                            uint16_t aWeight,
                                            int16_t aStretch,
                                            bool aItalic,
                                            const uint8_t* aFontData,
                                            uint32_t aLength);
 
-    virtual void GetCommonFallbackFonts(const uint32_t aCh,
+    virtual void GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                         int32_t aRunScript,
                                         nsTArray<const char*>& aFontList);
 
     virtual nsresult GetFontList(nsIAtom *aLangGroup,
                                  const nsACString& aGenericFamily,
                                  nsTArray<nsString>& aListOfFonts);
 
     virtual nsresult UpdateFontList();
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -121,17 +121,17 @@ gfxDWriteFont::~gfxDWriteFont()
 gfxFont*
 gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
 {
     return new gfxDWriteFont(static_cast<gfxDWriteFontEntry*>(mFontEntry.get()),
                              &mStyle, mNeedsBold, anAAOption);
 }
 
 const gfxFont::Metrics&
-gfxDWriteFont::GetMetrics()
+gfxDWriteFont::GetHorizontalMetrics()
 {
     return *mMetrics;
 }
 
 bool
 gfxDWriteFont::GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics)
 {
     gfxFontStyle style(mStyle);
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -25,18 +25,16 @@ public:
     gfxDWriteFont(gfxFontEntry *aFontEntry,
                   const gfxFontStyle *aFontStyle,
                   bool aNeedsBold = false,
                   AntialiasOption = kAntialiasDefault);
     ~gfxDWriteFont();
 
     virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption);
 
-    virtual const gfxFont::Metrics& GetMetrics();
-
     virtual uint32_t GetSpaceGlyph();
 
     virtual bool SetupCairoFont(gfxContext *aContext);
 
     virtual bool AllowSubpixelAA() { return mAllowManualShowGlyphs; }
 
     virtual bool IsValid();
 
@@ -66,33 +64,35 @@ public:
 
     virtual FontType GetType() const { return FONT_TYPE_DWRITE; }
 
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget);
 
     virtual cairo_scaled_font_t *GetCairoScaledFont();
 
 protected:
+    virtual const Metrics& GetHorizontalMetrics();
+
     bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics);
 
     void ComputeMetrics(AntialiasOption anAAOption);
 
     bool HasBitmapStrikeForSize(uint32_t aSize);
 
     cairo_font_face_t *CairoFontFace();
 
     gfxFloat MeasureGlyphWidth(uint16_t aGlyph);
 
     DWRITE_MEASURING_MODE GetMeasuringMode();
     bool GetForceGDIClassic();
 
     nsRefPtr<IDWriteFontFace> mFontFace;
     cairo_font_face_t *mCairoFontFace;
 
-    gfxFont::Metrics          *mMetrics;
+    Metrics *mMetrics;
 
     // cache of glyph widths in 16.16 fixed-point pixels
     nsAutoPtr<nsDataHashtable<nsUint32HashKey,int32_t> > mGlyphWidths;
 
     bool mNeedsOblique;
     bool mNeedsBold;
     bool mUseSubpixelPositions;
     bool mAllowManualShowGlyphs;
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -103,17 +103,17 @@ gfxFT2FontBase::GetGlyphExtents(uint32_t
     // made by caching more.  It is usually only the advance that is needed,
     // so caching only the advance could allow many requests to be cached with
     // little memory use.  Ideally this cache would be merged with
     // gfxGlyphExtents.
     cairo_scaled_font_glyph_extents(CairoScaledFont(), glyphs, 1, aExtents);
 }
 
 const gfxFont::Metrics&
-gfxFT2FontBase::GetMetrics()
+gfxFT2FontBase::GetHorizontalMetrics()
 {
     if (mHasMetrics)
         return mMetrics;
 
     if (MOZ_UNLIKELY(GetStyle()->size <= 0.0)) {
         new(&mMetrics) gfxFont::Metrics(); // zero initialize
         mSpaceGlyph = 0;
     } else {
@@ -141,17 +141,17 @@ gfxFT2FontBase::GetMetrics()
 }
 
 // Get the glyphID of a space
 uint32_t
 gfxFT2FontBase::GetSpaceGlyph()
 {
     NS_ASSERTION(GetStyle()->size != 0,
                  "forgot to short-circuit a text run with zero-sized font?");
-    GetMetrics();
+    GetHorizontalMetrics();
     return mSpaceGlyph;
 }
 
 uint32_t
 gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
 {
     if (variation_selector) {
         uint32_t id =
--- a/gfx/thebes/gfxFT2FontBase.h
+++ b/gfx/thebes/gfxFT2FontBase.h
@@ -16,30 +16,32 @@ public:
     gfxFT2FontBase(cairo_scaled_font_t *aScaledFont,
                    gfxFontEntry *aFontEntry,
                    const gfxFontStyle *aFontStyle);
     virtual ~gfxFT2FontBase();
 
     uint32_t GetGlyph(uint32_t aCharCode);
     void GetGlyphExtents(uint32_t aGlyph,
                          cairo_text_extents_t* aExtents);
-    virtual const gfxFont::Metrics& GetMetrics();
     virtual uint32_t GetSpaceGlyph();
     virtual bool ProvidesGetGlyph() const { return true; }
     virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector);
     virtual bool ProvidesGlyphWidths() const { return true; }
     virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
 
     cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; };
     virtual bool SetupCairoFont(gfxContext *aContext);
 
     virtual FontType GetType() const { return FONT_TYPE_FT2; }
 
     mozilla::gfx::FontOptions* GetFontOptions() { return &mFontOptions; }
+
 protected:
+    virtual const Metrics& GetHorizontalMetrics();
+
     uint32_t mSpaceGlyph;
     bool mHasMetrics;
     Metrics mMetrics;
 
     // Azure font description
     mozilla::gfx::FontOptions  mFontOptions;
     void ConstructFontOptions();
 };
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -653,17 +653,17 @@ gfxShapedText::SetMissingGlyph(uint32_t 
     DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
 
     details->mGlyphID = aChar;
     if (IsDefaultIgnorable(aChar)) {
         // Setting advance width to zero will prevent drawing the hexbox
         details->mAdvance = 0;
     } else {
         gfxFloat width =
-            std::max(aFont->GetMetrics().aveCharWidth,
+            std::max(aFont->GetMetrics(gfxFont::eHorizontal).aveCharWidth,
                      gfxFontMissingGlyphs::GetDesiredMinWidth(aChar,
                          mAppUnitsPerDevUnit));
         details->mAdvance = uint32_t(width * mAppUnitsPerDevUnit);
     }
     details->mXOffset = 0;
     details->mYOffset = 0;
     GetCharacterGlyphs()[aIndex].SetMissing(1);
 }
@@ -783,17 +783,17 @@ gfxFont::GetGlyphHAdvance(gfxContext *aC
 {
     if (!SetupCairoFont(aCtx)) {
         return 0;
     }
     if (ProvidesGlyphWidths()) {
         return GetGlyphWidth(aCtx, aGID) / 65536.0;
     }
     if (mFUnitsConvFactor == 0.0f) {
-        GetMetrics();
+        GetMetrics(eHorizontal);
     }
     NS_ASSERTION(mFUnitsConvFactor > 0.0f,
                  "missing font unit conversion factor");
     if (!mHarfBuzzShaper) {
         mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
     }
     gfxHarfBuzzShaper* shaper =
         static_cast<gfxHarfBuzzShaper*>(mHarfBuzzShaper.get());
@@ -1775,17 +1775,17 @@ gfxFont::DrawGlyphs(gfxShapedText       
                             double glyphX = aPt->x;
                             if (aRunParams.isRTL) {
                                 glyphX -= advance;
                             }
                             gfxPoint pt(ToDeviceUnits(glyphX, aRunParams.devPerApp),
                                         ToDeviceUnits(aPt->y, aRunParams.devPerApp));
                             gfxFloat advanceDevUnits =
                                 ToDeviceUnits(advance, aRunParams.devPerApp);
-                            gfxFloat height = GetMetrics().maxAscent;
+                            gfxFloat height = GetMetrics(eHorizontal).maxAscent;
                             gfxRect glyphRect(pt.x, pt.y - height,
                                               advanceDevUnits, height);
 
                             // If there's a fake-italic skew in effect as part
                             // of the drawTarget's transform, we need to remove
                             // this before drawing the hexbox. (Bug 983985)
                             Matrix oldMat;
                             if (aFontParams.passedInvMatrix) {
@@ -2054,17 +2054,19 @@ gfxFont::Measure(gfxTextRun *aTextRun,
             return mNonAAFont->Measure(aTextRun, aStart, aEnd,
                                        TIGHT_HINTED_OUTLINE_EXTENTS,
                                        aRefContext, aSpacing);
         }
     }
 
     const int32_t appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
     // Current position in appunits
-    const gfxFont::Metrics& fontMetrics = GetMetrics();
+    gfxFont::Orientation orientation =
+        aTextRun->IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal;
+    const gfxFont::Metrics& fontMetrics = GetMetrics(orientation);
 
     RunMetrics metrics;
     metrics.mAscent = fontMetrics.maxAscent*appUnitsPerDevUnit;
     metrics.mDescent = fontMetrics.maxDescent*appUnitsPerDevUnit;
     if (aStart == aEnd) {
         // exit now before we look at aSpacing[0], which is undefined
         metrics.mBoundingBox = gfxRect(0, -metrics.mAscent, 0, metrics.mAscent + metrics.mDescent);
         return metrics;
@@ -2098,16 +2100,17 @@ gfxFont::Measure(gfxTextRun *aTextRun,
                 uint16_t extentsWidth = extents->GetContainedGlyphWidthAppUnits(glyphIndex);
                 if (extentsWidth != gfxGlyphExtents::INVALID_WIDTH &&
                     aBoundingBoxType == LOOSE_INK_EXTENTS) {
                     UnionRange(x, &advanceMin, &advanceMax);
                     UnionRange(x + direction*extentsWidth, &advanceMin, &advanceMax);
                 } else {
                     gfxRect glyphRect;
                     if (!extents->GetTightGlyphExtentsAppUnits(this,
+                            orientation,
                             aRefContext, glyphIndex, &glyphRect)) {
                         glyphRect = gfxRect(0, metrics.mBoundingBox.Y(),
                             advance, metrics.mBoundingBox.Height());
                     }
                     if (isRTL) {
                         glyphRect -= gfxPoint(advance, 0);
                     }
                     glyphRect += gfxPoint(x, 0);
@@ -2125,16 +2128,17 @@ gfxFont::Measure(gfxTextRun *aTextRun,
                 uint32_t j;
                 for (j = 0; j < glyphCount; ++j, ++details) {
                     uint32_t glyphIndex = details->mGlyphID;
                     gfxPoint glyphPt(x + details->mXOffset, details->mYOffset);
                     double advance = details->mAdvance;
                     gfxRect glyphRect;
                     if (glyphData->IsMissing() || !extents ||
                         !extents->GetTightGlyphExtentsAppUnits(this,
+                                orientation,
                                 aRefContext, glyphIndex, &glyphRect)) {
                         // We might have failed to get glyph extents due to
                         // OOM or something
                         glyphRect = gfxRect(0, -metrics.mAscent,
                             advance, metrics.mAscent + metrics.mDescent);
                     }
                     if (isRTL) {
                         glyphRect -= gfxPoint(advance, 0);
@@ -2932,17 +2936,18 @@ gfxFont::GetOrCreateGlyphExtents(int32_t
         // Initialize the extents of a space glyph, assuming that spaces don't
         // render anything!
         glyphExtents->SetContainedGlyphWidthAppUnits(GetSpaceGlyph(), 0);
     }
     return glyphExtents;
 }
 
 void
-gfxFont::SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID, bool aNeedTight,
+gfxFont::SetupGlyphExtents(gfxContext *aContext, Orientation aOrientation, 
+                           uint32_t aGlyphID, bool aNeedTight,
                            gfxGlyphExtents *aExtents)
 {
     gfxContextMatrixAutoSaveRestore matrixRestore(aContext);
     aContext->SetMatrix(gfxMatrix());
 
     gfxRect svgBounds;
     if (mFontEntry->TryGetSVGData(this) && mFontEntry->HasSVGGlyph(aGlyphID) &&
         mFontEntry->GetSVGGlyphExtents(aContext, aGlyphID, &svgBounds)) {
@@ -2957,17 +2962,17 @@ gfxFont::SetupGlyphExtents(gfxContext *a
 
     cairo_glyph_t glyph;
     glyph.index = aGlyphID;
     glyph.x = 0;
     glyph.y = 0;
     cairo_text_extents_t extents;
     cairo_glyph_extents(aContext->GetCairo(), &glyph, 1, &extents);
 
-    const Metrics& fontMetrics = GetMetrics();
+    const Metrics& fontMetrics = GetMetrics(aOrientation);
     int32_t appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit();
     if (!aNeedTight && extents.x_bearing >= 0 &&
         extents.y_bearing >= -fontMetrics.maxAscent &&
         extents.height + extents.y_bearing <= fontMetrics.maxDescent) {
         uint32_t appUnitsWidth =
             uint32_t(ceil((extents.x_bearing + extents.width)*appUnitsPerDevUnit));
         if (appUnitsWidth < gfxGlyphExtents::INVALID_WIDTH) {
             aExtents->SetContainedGlyphWidthAppUnits(aGlyphID, uint16_t(appUnitsWidth));
@@ -3075,16 +3080,19 @@ gfxFont::InitMetricsFromSfntTables(Metri
                 mFontEntry->HasFontTable(TRUETYPE_TAG('M','A','T','H'))) {
                 SET_SIGNED(maxAscent, os2->sTypoAscender);
                 SET_SIGNED(maxDescent, - int16_t(os2->sTypoDescender));
                 SET_SIGNED(externalLeading, os2->sTypoLineGap);
             }
         }
     }
 
+#undef SET_SIGNED
+#undef SET_UNSIGNED
+
     mIsValid = true;
 
     return true;
 }
 
 static double
 RoundToNearestMultiple(double aValue, double aFraction)
 {
@@ -3200,32 +3208,178 @@ gfxFont::SanitizeMetrics(gfxFont::Metric
     }
 
     // If overline is larger than the ascent, the line should be resized.
     if (aMetrics->underlineSize > aMetrics->maxAscent) {
         aMetrics->underlineSize = aMetrics->maxAscent;
     }
 }
 
+// Create a Metrics record to be used for vertical layout. This should never
+// fail, as we've already decided this is a valid font. We do not have the
+// option of marking it invalid (as can happen if we're unable to read
+// horizontal metrics), because that could break a font that we're already
+// using for horizontal text.
+// So we will synthesize *something* usable here even if there aren't any of the
+// usual font tables (which can happen in the case of a legacy bitmap or Type1
+// font for which the platform-specific backend used platform APIs instead of
+// sfnt tables to create the horizontal metrics).
+const gfxFont::Metrics*
+gfxFont::CreateVerticalMetrics()
+{
+    const uint32_t kHheaTableTag = TRUETYPE_TAG('h','h','e','a');
+    const uint32_t kVheaTableTag = TRUETYPE_TAG('v','h','e','a');
+    const uint32_t kPostTableTag = TRUETYPE_TAG('p','o','s','t');
+    const uint32_t kOS_2TableTag = TRUETYPE_TAG('O','S','/','2');
+    uint32_t len;
+
+    Metrics* metrics = new Metrics;
+    ::memset(metrics, 0, sizeof(Metrics));
+
+    // Some basic defaults, in case the font lacks any real metrics tables.
+    // TODO: consider what rounding (if any) we should apply to these.
+    metrics->emHeight = GetAdjustedSize();
+    metrics->emAscent = metrics->emHeight / 2;
+    metrics->emDescent = metrics->emHeight - metrics->emAscent;
+
+    metrics->maxAscent = metrics->emAscent;
+    metrics->maxDescent = metrics->emDescent;
+
+    const float UNINITIALIZED_LEADING = -10000.0f;
+    metrics->externalLeading = UNINITIALIZED_LEADING;
+
+#define SET_UNSIGNED(field,src) metrics->field = uint16_t(src) * mFUnitsConvFactor
+#define SET_SIGNED(field,src)   metrics->field = int16_t(src) * mFUnitsConvFactor
+
+    gfxFontEntry::AutoTable os2Table(mFontEntry, kOS_2TableTag);
+    if (os2Table) {
+        const OS2Table *os2 =
+            reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
+        // These fields should always be present in any valid OS/2 table
+        if (len >= offsetof(OS2Table, sTypoLineGap) + sizeof(int16_t)) {
+            SET_SIGNED(strikeoutSize, os2->yStrikeoutSize);
+            SET_SIGNED(aveCharWidth, int16_t(os2->sTypoAscender) -
+                                     int16_t(os2->sTypoDescender));
+            metrics->maxAscent =
+                std::max(metrics->maxAscent, int16_t(os2->xAvgCharWidth) *
+                                             gfxFloat(mFUnitsConvFactor));
+            metrics->maxDescent =
+                std::max(metrics->maxDescent, int16_t(os2->xAvgCharWidth) *
+                                              gfxFloat(mFUnitsConvFactor));
+        }
+    }
+
+    // If we didn't set aveCharWidth from OS/2, try to read 'hhea' metrics
+    // and use the line height from its ascent/descent.
+    if (!metrics->aveCharWidth) {
+        gfxFontEntry::AutoTable hheaTable(mFontEntry, kHheaTableTag);
+        if (hheaTable) {
+            const HheaTable* hhea =
+                reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable,
+                                                                    &len));
+            if (len >= sizeof(HheaTable)) {
+                SET_SIGNED(aveCharWidth, int16_t(hhea->ascender) -
+                                         int16_t(hhea->descender));
+                metrics->maxAscent = metrics->aveCharWidth / 2;
+                metrics->maxDescent =
+                    metrics->aveCharWidth - metrics->maxAscent;
+            }
+        }
+    }
+
+    // Read real vertical metrics if available.
+    gfxFontEntry::AutoTable vheaTable(mFontEntry, kVheaTableTag);
+    if (vheaTable) {
+        const HheaTable* vhea =
+            reinterpret_cast<const HheaTable*>(hb_blob_get_data(vheaTable,
+                                                                &len));
+        if (len >= sizeof(HheaTable)) {
+            SET_UNSIGNED(maxAdvance, vhea->advanceWidthMax);
+            SET_SIGNED(maxAscent, vhea->ascender);
+            SET_SIGNED(maxDescent, -int16_t(vhea->descender));
+            SET_SIGNED(externalLeading, vhea->lineGap);
+        }
+    }
+
+    // If we didn't set aveCharWidth above, we must be dealing with a non-sfnt
+    // font of some kind (Type1, bitmap, vector, ...), so fall back to using
+    // whatever the platform backend figured out for horizontal layout.
+    // And if we haven't set externalLeading yet, then copy that from the
+    // horizontal metrics as well, to help consistency of CSS line-height.
+    if (!metrics->aveCharWidth ||
+        metrics->externalLeading == UNINITIALIZED_LEADING) {
+        const Metrics& horizMetrics = GetHorizontalMetrics();
+        if (!metrics->aveCharWidth) {
+            metrics->aveCharWidth = horizMetrics.maxAscent + horizMetrics.maxDescent;
+        }
+        if (metrics->externalLeading == UNINITIALIZED_LEADING) {
+            metrics->externalLeading = horizMetrics.externalLeading;
+        }
+    }
+
+    // Get underline thickness from the 'post' table if available.
+    gfxFontEntry::AutoTable postTable(mFontEntry, kPostTableTag);
+    if (postTable) {
+        const PostTable *post =
+            reinterpret_cast<const PostTable*>(hb_blob_get_data(postTable,
+                                                                &len));
+        if (len >= offsetof(PostTable, underlineThickness) +
+                       sizeof(uint16_t)) {
+            SET_UNSIGNED(underlineSize, post->underlineThickness);
+            // Also use for strikeout if we didn't find that in OS/2 above.
+            if (!metrics->strikeoutSize) {
+                metrics->strikeoutSize = metrics->underlineSize;
+            }
+        }
+    }
+
+#undef SET_UNSIGNED
+#undef SET_SIGNED
+
+    // If we didn't read this from a vhea table, it will still be zero.
+    // In any case, let's make sure it is not less than the value we've
+    // come up with for aveCharWidth.
+    metrics->maxAdvance = std::max(metrics->maxAdvance, metrics->aveCharWidth);
+
+    // Thickness of underline and strikeout may have been read from tables,
+    // but in case they were not present, ensure a minimum of 1 pixel.
+    // We synthesize our own positions, as font metrics don't provide these
+    // for vertical layout.
+    metrics->underlineSize = std::max(1.0, metrics->underlineSize);
+    metrics->underlineOffset = 0; // XXX to be adjusted
+
+    metrics->strikeoutSize = std::max(1.0, metrics->strikeoutSize);
+    metrics->strikeoutOffset =
+        metrics->maxDescent - 0.5 * metrics->strikeoutSize;
+
+    // Somewhat arbitrary values for now, subject to future refinement...
+    metrics->spaceWidth = metrics->aveCharWidth;
+    metrics->zeroOrAveCharWidth = metrics->aveCharWidth;
+    metrics->maxHeight = metrics->maxAscent + metrics->maxDescent;
+    metrics->xHeight = metrics->emHeight / 2;
+
+    return metrics;
+}
+
 gfxFloat
 gfxFont::SynthesizeSpaceWidth(uint32_t aCh)
 {
     // return an appropriate width for various Unicode space characters
     // that we "fake" if they're not actually present in the font;
     // returns negative value if the char is not a known space.
     switch (aCh) {
     case 0x2000:                                 // en quad
     case 0x2002: return GetAdjustedSize() / 2;   // en space
     case 0x2001:                                 // em quad
     case 0x2003: return GetAdjustedSize();       // em space
     case 0x2004: return GetAdjustedSize() / 3;   // three-per-em space
     case 0x2005: return GetAdjustedSize() / 4;   // four-per-em space
     case 0x2006: return GetAdjustedSize() / 6;   // six-per-em space
-    case 0x2007: return GetMetrics().zeroOrAveCharWidth; // figure space
-    case 0x2008: return GetMetrics().spaceWidth; // punctuation space 
+    case 0x2007: return GetMetrics(eHorizontal).zeroOrAveCharWidth; // figure space
+    case 0x2008: return GetMetrics(eHorizontal).spaceWidth; // punctuation space
     case 0x2009: return GetAdjustedSize() / 5;   // thin space
     case 0x200a: return GetAdjustedSize() / 10;  // hair space
     case 0x202f: return GetAdjustedSize() / 5;   // narrow no-break space
     default: return -1.0;
     }
 }
 
 void
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1436,17 +1436,32 @@ public:
         gfxFloat maxAdvance;
 
         gfxFloat aveCharWidth;
         gfxFloat spaceWidth;
         gfxFloat zeroOrAveCharWidth;  // width of '0', or if there is
                                       // no '0' glyph in this font,
                                       // equal to .aveCharWidth
     };
-    virtual const gfxFont::Metrics& GetMetrics() = 0;
+
+    enum Orientation {
+        eHorizontal,
+        eVertical
+    };
+
+    const Metrics& GetMetrics(Orientation aOrientation)
+    {
+        if (aOrientation == eHorizontal) {
+            return GetHorizontalMetrics();
+        }
+        if (!mVerticalMetrics) {
+            mVerticalMetrics = CreateVerticalMetrics();
+        }
+        return *mVerticalMetrics;
+    }
 
     /**
      * We let layout specify spacing on either side of any
      * character. We need to specify both before and after
      * spacing so that substring measurement can do the right things.
      * These values are in appunits. They're always an integral number of
      * appunits, but we specify them in floats in case very large spacing
      * values are required.
@@ -1553,17 +1568,18 @@ public:
     nsExpirationState *GetExpirationState() { return &mExpirationState; }
 
     // Get the glyphID of a space
     virtual uint32_t GetSpaceGlyph() = 0;
 
     gfxGlyphExtents *GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit);
 
     // You need to call SetupCairoFont on the aCR just before calling this
-    virtual void SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID,
+    virtual void SetupGlyphExtents(gfxContext *aContext,
+                                   Orientation aOrientation, uint32_t aGlyphID,
                                    bool aNeedTight, gfxGlyphExtents *aExtents);
 
     // This is called by the default Draw() implementation above.
     virtual bool SetupCairoFont(gfxContext *aContext) = 0;
 
     virtual bool AllowSubpixelAA() { return true; }
 
     bool IsSyntheticBold() { return mApplySyntheticBold; }
@@ -1730,16 +1746,20 @@ public:
         return mFontEntry->GetMathConstant(aConstant);
     }
 
     // return a cloned font resized and offset to simulate sub/superscript glyphs
     virtual already_AddRefed<gfxFont>
     GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel);
 
 protected:
+    virtual const Metrics& GetHorizontalMetrics() = 0;
+
+    const Metrics* CreateVerticalMetrics();
+
     // Output a single glyph at *aPt, which is updated by the glyph's advance.
     // Normal glyphs are simply accumulated in aBuffer until it is full and
     // gets flushed, but SVG or color-font glyphs will instead be rendered
     // directly to the destination (found from the buffer's parameters).
     void DrawOneGlyph(uint32_t           aGlyphID,
                       double             aAdvance,
                       gfxPoint          *aPt,
                       GlyphBufferAzure&  aBuffer,
@@ -1967,33 +1987,36 @@ protected:
     // we create either or both of these shapers when needed, depending
     // whether the font has graphite tables, and whether graphite shaping
     // is actually enabled
     nsAutoPtr<gfxFontShaper>   mHarfBuzzShaper;
     nsAutoPtr<gfxFontShaper>   mGraphiteShaper;
 
     mozilla::RefPtr<mozilla::gfx::ScaledFont> mAzureScaledFont;
 
+    // For vertical metrics, created on demand.
+    nsAutoPtr<const Metrics> mVerticalMetrics;
+
     // Helper for subclasses that want to initialize standard metrics from the
     // tables of sfnt (TrueType/OpenType) fonts.
     // This will use mFUnitsConvFactor if it is already set, else compute it
     // from mAdjustedSize and the unitsPerEm in the font's 'head' table.
     // Returns TRUE and sets mIsValid=TRUE if successful;
     // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken.
     // Returns FALSE if the font does not appear to be an sfnt at all,
     // and should be handled (if possible) using other APIs.
     bool InitMetricsFromSfntTables(Metrics& aMetrics);
 
     // Helper to calculate various derived metrics from the results of
     // InitMetricsFromSfntTables or equivalent platform code
     void CalculateDerivedMetrics(Metrics& aMetrics);
 
     // some fonts have bad metrics, this method sanitize them.
     // if this font has bad underline offset, aIsBadUnderlineFont should be true.
-    void SanitizeMetrics(gfxFont::Metrics *aMetrics, bool aIsBadUnderlineFont);
+    void SanitizeMetrics(Metrics *aMetrics, bool aIsBadUnderlineFont);
 
     bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
                         uint32_t aGlyphId, gfxTextContextPaint *aContextPaint) const;
     bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
                         uint32_t aGlyphId, gfxTextContextPaint *aContextPaint,
                         gfxTextRunDrawCallbacks *aCallbacks,
                         bool& aEmittedGlyphs) const;
 
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -101,17 +101,17 @@ gfxGDIFont::ShapeText(gfxContext     *aC
         return false;
     }
 
     return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
                               aShapedText);
 }
 
 const gfxFont::Metrics&
-gfxGDIFont::GetMetrics()
+gfxGDIFont::GetHorizontalMetrics()
 {
     if (!mMetrics) {
         Initialize();
     }
     return *mMetrics;
 }
 
 uint32_t
--- a/gfx/thebes/gfxGDIFont.h
+++ b/gfx/thebes/gfxGDIFont.h
@@ -29,18 +29,16 @@ public:
     HFONT GetHFONT() { if (!mMetrics) Initialize(); return mFont; }
 
     gfxFloat GetAdjustedSize() { if (!mMetrics) Initialize(); return mAdjustedSize; }
 
     cairo_font_face_t   *CairoFontFace() { return mFontFace; }
     cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; }
 
     /* overrides for the pure virtual methods in gfxFont */
-    virtual const gfxFont::Metrics& GetMetrics();
-
     virtual uint32_t GetSpaceGlyph();
 
     virtual bool SetupCairoFont(gfxContext *aContext);
 
     /* override Measure to add padding for antialiasing */
     virtual RunMetrics Measure(gfxTextRun *aTextRun,
                                uint32_t aStart, uint32_t aEnd,
                                BoundingBoxType aBoundingBoxType,
@@ -66,16 +64,18 @@ public:
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontCacheSizes* aSizes) const;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontCacheSizes* aSizes) const;
 
     virtual FontType GetType() const { return FONT_TYPE_GDI; }
 
 protected:
+    virtual const Metrics& GetHorizontalMetrics();
+
     /* override to ensure the cairo font is set up properly */
     virtual bool ShapeText(gfxContext     *aContext,
                            const char16_t *aText,
                            uint32_t        aOffset,
                            uint32_t        aLength,
                            int32_t         aScript,
                            gfxShapedText  *aShapedText);
 
--- a/gfx/thebes/gfxGlyphExtents.cpp
+++ b/gfx/thebes/gfxGlyphExtents.cpp
@@ -31,30 +31,32 @@ gfxGlyphExtents::~gfxGlyphExtents()
         mContainedGlyphWidths.SizeOfExcludingThis(&FontCacheMallocSizeOf);
     gGlyphExtentsCount++;
 #endif
     MOZ_COUNT_DTOR(gfxGlyphExtents);
 }
 
 bool
 gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont,
+    gfxFont::Orientation aOrientation,
     gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents)
 {
     HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID);
     if (!entry) {
         if (!aContext) {
             NS_WARNING("Could not get glyph extents (no aContext)");
             return false;
         }
 
         if (aFont->SetupCairoFont(aContext)) {
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
             ++gGlyphExtentsSetupLazyTight;
 #endif
-            aFont->SetupGlyphExtents(aContext, aGlyphID, true, this);
+            aFont->SetupGlyphExtents(aContext, aOrientation, aGlyphID, true,
+                                     this);
             entry = mTightGlyphExtents.GetEntry(aGlyphID);
         }
         if (!entry) {
             NS_WARNING("Could not get glyph extents");
             return false;
         }
     }
 
--- a/gfx/thebes/gfxGlyphExtents.h
+++ b/gfx/thebes/gfxGlyphExtents.h
@@ -1,23 +1,23 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 GFX_GLYPHEXTENTS_H
 #define GFX_GLYPHEXTENTS_H
 
+#include "gfxFont.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 #include "mozilla/MemoryReporting.h"
 
 class gfxContext;
-class gfxFont;
 struct gfxRect;
 
 /**
  * This stores glyph bounds information for a particular gfxFont, at
  * a particular appunits-per-dev-pixel ratio (because the compressed glyph
  * width array is stored in appunits).
  * 
  * We store a hashtable from glyph IDs to float bounding rects. For the
@@ -57,18 +57,19 @@ public:
 
     bool IsGlyphKnownWithTightExtents(uint32_t aGlyphID) const {
         return mTightGlyphExtents.GetEntry(aGlyphID) != nullptr;
     }
 
     // Get glyph extents; a rectangle relative to the left baseline origin
     // Returns true on success. Can fail on OOM or when aContext is null
     // and extents were not (successfully) prefetched.
-    bool GetTightGlyphExtentsAppUnits(gfxFont *aFont, gfxContext *aContext,
-            uint32_t aGlyphID, gfxRect *aExtents);
+    bool GetTightGlyphExtentsAppUnits(gfxFont *aFont,
+            gfxFont::Orientation aOrientation,
+            gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents);
 
     void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) {
         mContainedGlyphWidths.Set(aGlyphID, aWidth);
     }
     void SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits);
 
     int32_t GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
 
--- a/gfx/thebes/gfxMacFont.h
+++ b/gfx/thebes/gfxMacFont.h
@@ -19,20 +19,16 @@ public:
     gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
                bool aNeedsBold);
 
     virtual ~gfxMacFont();
 
     CGFontRef GetCGFontRef() const { return mCGFont; }
 
     /* overrides for the pure virtual methods in gfxFont */
-    virtual const gfxFont::Metrics& GetMetrics() {
-        return mMetrics;
-    }
-
     virtual uint32_t GetSpaceGlyph() {
         return mSpaceGlyph;
     }
 
     virtual bool SetupCairoFont(gfxContext *aContext);
 
     /* override Measure to add padding for antialiasing */
     virtual RunMetrics Measure(gfxTextRun *aTextRun,
@@ -46,16 +42,20 @@ public:
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontCacheSizes* aSizes) const;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontCacheSizes* aSizes) const;
 
     virtual FontType GetType() const { return FONT_TYPE_MAC; }
 
 protected:
+    virtual const Metrics& GetHorizontalMetrics() {
+        return mMetrics;
+    }
+
     // override to prefer CoreText shaping with fonts that depend on AAT
     virtual bool ShapeText(gfxContext     *aContext,
                            const char16_t *aText,
                            uint32_t        aOffset,
                            uint32_t        aLength,
                            int32_t         aScript,
                            gfxShapedText  *aShapedText);
 
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -1405,17 +1405,17 @@ gfxPangoFontGroup::GetFontSet(PangoLangu
         MakeFontSet(aLang, mSizeAdjustFactor);
     mFontSets.AppendElement(FontSetByLangEntry(aLang, fontSet));
 
     return fontSet;
 }
 
 already_AddRefed<gfxFont>
 gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
-                                   int32_t aRunScript,
+                                   uint32_t aNextCh, int32_t aRunScript,
                                    gfxFont *aPrevMatchedFont,
                                    uint8_t *aMatchType)
 {
     if (aPrevMatchedFont) {
         // Don't switch fonts for control characters, regardless of
         // whether they are present in the current font, as they won't
         // actually be rendered (see bug 716229)
         uint8_t category = GetGeneralCategory(aCh);
@@ -1856,17 +1856,18 @@ gfxPangoFontGroup::GetBaseFontSet()
     nsAutoRef<FcPattern> pattern;
     nsRefPtr<gfxFcFontSet> fontSet =
         MakeFontSet(mPangoLanguage, mSizeAdjustFactor, &pattern);
 
     double size = GetPixelSize(pattern);
     if (size != 0.0 && mStyle.sizeAdjust != 0.0) {
         gfxFcFont *font = fontSet->GetFontAt(0, GetStyle());
         if (font) {
-            const gfxFont::Metrics& metrics = font->GetMetrics();
+            const gfxFont::Metrics& metrics =
+                font->GetMetrics(gfxFont::eHorizontal); // XXX vertical?
 
             // The factor of 0.1 ensures that xHeight is sane so fonts don't
             // become huge.  Strictly ">" ensures that xHeight and emHeight are
             // not both zero.
             if (metrics.xHeight > 0.1 * metrics.emHeight) {
                 mSizeAdjustFactor =
                     mStyle.sizeAdjust * metrics.emHeight / metrics.xHeight;
 
--- a/gfx/thebes/gfxPangoFonts.h
+++ b/gfx/thebes/gfxPangoFonts.h
@@ -32,18 +32,18 @@ public:
 
     virtual gfxFont* GetFirstValidFont();
 
     virtual gfxFont *GetFontAt(int32_t i);
 
     virtual void UpdateUserFonts();
 
     virtual already_AddRefed<gfxFont>
-        FindFontForChar(uint32_t aCh, uint32_t aPrevCh, int32_t aRunScript,
-                        gfxFont *aPrevMatchedFont,
+        FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
+                        int32_t aRunScript, gfxFont *aPrevMatchedFont,
                         uint8_t *aMatchType);
 
     static void Shutdown();
 
     // Used for @font-face { src: local(); }
     static gfxFontEntry *NewFontEntry(const nsAString& aFontName,
                                       uint16_t aWeight,
                                       int16_t aStretch,
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -444,17 +444,17 @@ public:
     // returns true if a pref lang is CJK
     static bool IsLangCJK(eFontPrefLang aLang);
     
     // helper method to add a pref lang to an array, if not already in array
     static void AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang);
 
     // returns a list of commonly used fonts for a given character
     // these are *possible* matches, no cmap-checking is done at this level
-    virtual void GetCommonFallbackFonts(const uint32_t /*aCh*/,
+    virtual void GetCommonFallbackFonts(uint32_t /*aCh*/, uint32_t /*aNextCh*/,
                                         int32_t /*aRunScript*/,
                                         nsTArray<const char*>& /*aFontList*/)
     {
         // platform-specific override, by default do nothing
     }
 
     static bool OffMainThreadCompositingEnabled();
 
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -531,17 +531,17 @@ struct FontFamilyListData {
 void
 gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
 {
     FontFamilyListData data(aFamilyArray);
     mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
 }
 
 gfxFontEntry*
-gfxPlatformFontList::SystemFindFontForChar(const uint32_t aCh,
+gfxPlatformFontList::SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh,
                                            int32_t aRunScript,
                                            const gfxFontStyle* aStyle)
  {
     gfxFontEntry* fontEntry = nullptr;
 
     // is codepoint with no matching font? return null immediately
     if (mCodepointsWithNoFonts.test(aCh)) {
         return nullptr;
@@ -565,17 +565,18 @@ gfxPlatformFontList::SystemFindFontForCh
         }
     }
 
     TimeStamp start = TimeStamp::Now();
 
     // search commonly available fonts
     bool common = true;
     gfxFontFamily *fallbackFamily = nullptr;
-    fontEntry = CommonFontFallback(aCh, aRunScript, aStyle, &fallbackFamily);
+    fontEntry = CommonFontFallback(aCh, aNextCh, aRunScript, aStyle,
+                                   &fallbackFamily);
  
     // if didn't find a font, do system-wide fallback (except for specials)
     uint32_t cmapCount = 0;
     if (!fontEntry) {
         common = false;
         fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount,
                                        &fallbackFamily);
     }
@@ -633,25 +634,26 @@ gfxPlatformFontList::FindFontForCharProc
     aFamilyEntry->FindFontForChar(data);
 
     return PL_DHASH_NEXT;
 }
 
 #define NUM_FALLBACK_FONTS        8
 
 gfxFontEntry*
-gfxPlatformFontList::CommonFontFallback(const uint32_t aCh,
+gfxPlatformFontList::CommonFontFallback(uint32_t aCh, uint32_t aNextCh,
                                         int32_t aRunScript,
                                         const gfxFontStyle* aMatchStyle,
                                         gfxFontFamily** aMatchedFamily)
 {
     nsAutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
     uint32_t i, numFallbacks;
 
-    gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aRunScript,
+    gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aNextCh,
+                                                       aRunScript,
                                                        defaultFallbacks);
     numFallbacks = defaultFallbacks.Length();
     for (i = 0; i < numFallbacks; i++) {
         nsAutoString familyName;
         const char *fallbackFamily = defaultFallbacks[i];
 
         familyName.AppendASCII(fallbackFamily);
         gfxFontFamily *fallback =
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -115,18 +115,18 @@ public:
                       nsTArray<nsString>& aListOfFonts);
 
     void UpdateFontList();
 
     void ClearPrefFonts() { mPrefFonts.Clear(); }
 
     virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
 
-    virtual gfxFontEntry*
-    SystemFindFontForChar(const uint32_t aCh,
+    gfxFontEntry*
+    SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh,
                           int32_t aRunScript,
                           const gfxFontStyle* aStyle);
 
     virtual gfxFontFamily* FindFamily(const nsAString& aFamily,
                                       bool aUseSystemFonts = false);
 
     gfxFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold);
 
@@ -206,17 +206,17 @@ protected:
 
     static gfxPlatformFontList *sPlatformFontList;
 
     static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
                                                nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                                void* userArg);
 
     // returns default font for a given character, null otherwise
-    gfxFontEntry* CommonFontFallback(const uint32_t aCh,
+    gfxFontEntry* CommonFontFallback(uint32_t aCh, uint32_t aNextCh,
                                      int32_t aRunScript,
                                      const gfxFontStyle* aMatchStyle,
                                      gfxFontFamily** aMatchedFamily);
 
     // search fonts system-wide for a given character, null otherwise
     virtual gfxFontEntry* GlobalFontFallback(const uint32_t aCh,
                                              int32_t aRunScript,
                                              const gfxFontStyle* aMatchStyle,
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -224,20 +224,24 @@ static const char kFontMyanmarMN[] = "My
 static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
 static const char kFontSimSunExtB[] = "SimSun-ExtB";
 static const char kFontSongtiSC[] = "Songti SC";
 static const char kFontSTHeiti[] = "STHeiti";
 static const char kFontSTIXGeneral[] = "STIXGeneral";
 static const char kFontTamilMN[] = "Tamil MN";
 
 void
-gfxPlatformMac::GetCommonFallbackFonts(const uint32_t aCh,
+gfxPlatformMac::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                        int32_t aRunScript,
                                        nsTArray<const char*>& aFontList)
 {
+    if (aNextCh == 0xfe0f) {
+        aFontList.AppendElement(kFontAppleColorEmoji);
+    }
+
     aFontList.AppendElement(kFontLucidaGrande);
 
     if (!IS_IN_BMP(aCh)) {
         uint32_t p = aCh >> 16;
         uint32_t b = aCh >> 8;
         if (p == 1) {
             if (b >= 0x1f0 && b < 0x1f7) {
                 aFontList.AppendElement(kFontAppleColorEmoji);
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -55,17 +55,17 @@ public:
 
     bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags);
 
     nsresult GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts);
     nsresult UpdateFontList();
 
-    virtual void GetCommonFallbackFonts(const uint32_t aCh,
+    virtual void GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                         int32_t aRunScript,
                                         nsTArray<const char*>& aFontList);
 
     virtual bool CanRenderContentToDataSurface() const MOZ_OVERRIDE {
       return true;
     }
 
     bool UseAcceleratedCanvas();
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1259,18 +1259,22 @@ gfxTextRun::SetSpaceGlyphIfSimple(gfxFon
                                   uint32_t aCharIndex, char16_t aSpaceChar,
                                   uint16_t aOrientation)
 {
     uint32_t spaceGlyph = aFont->GetSpaceGlyph();
     if (!spaceGlyph || !CompressedGlyph::IsSimpleGlyphID(spaceGlyph)) {
         return false;
     }
 
+    gfxFont::Orientation fontOrientation =
+        (aOrientation & gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT) ?
+            gfxFont::eVertical : gfxFont::eHorizontal;
     uint32_t spaceWidthAppUnits =
-        NS_lroundf(aFont->GetMetrics().spaceWidth * mAppUnitsPerDevUnit);
+        NS_lroundf(aFont->GetMetrics(fontOrientation).spaceWidth *
+                   mAppUnitsPerDevUnit);
     if (!CompressedGlyph::IsSimpleAdvance(spaceWidthAppUnits)) {
         return false;
     }
 
     AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false,
                 aOrientation);
     CompressedGlyph g;
     g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
@@ -1301,33 +1305,36 @@ gfxTextRun::FetchGlyphExtents(gfxContext
         uint32_t end = i + 1 < runCount ?
             mGlyphRuns[i + 1].mCharacterOffset : GetLength();
         bool fontIsSetup = false;
         uint32_t j;
         gfxGlyphExtents *extents = font->GetOrCreateGlyphExtents(mAppUnitsPerDevUnit);
   
         for (j = start; j < end; ++j) {
             const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j];
+            gfxFont::Orientation orientation =
+                IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal;
             if (glyphData->IsSimpleGlyph()) {
                 // If we're in speed mode, don't set up glyph extents here; we'll
                 // just return "optimistic" glyph bounds later
                 if (needsGlyphExtents) {
                     uint32_t glyphIndex = glyphData->GetSimpleGlyph();
                     if (!extents->IsGlyphKnown(glyphIndex)) {
                         if (!fontIsSetup) {
                             if (!font->SetupCairoFont(aRefContext)) {
                                 NS_WARNING("failed to set up font for glyph extents");
                                 break;
                             }
                             fontIsSetup = true;
                         }
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
                         ++gGlyphExtentsSetupEagerSimple;
 #endif
-                        font->SetupGlyphExtents(aRefContext, glyphIndex, false, extents);
+                        font->SetupGlyphExtents(aRefContext, orientation,
+                                                glyphIndex, false, extents);
                     }
                 }
             } else if (!glyphData->IsMissing()) {
                 uint32_t glyphCount = glyphData->GetGlyphCount();
                 if (glyphCount == 0) {
                     continue;
                 }
                 const gfxTextRun::DetailedGlyph *details = GetDetailedGlyphs(j);
@@ -1342,17 +1349,18 @@ gfxTextRun::FetchGlyphExtents(gfxContext
                                 NS_WARNING("failed to set up font for glyph extents");
                                 break;
                             }
                             fontIsSetup = true;
                         }
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
                         ++gGlyphExtentsSetupEagerTight;
 #endif
-                        font->SetupGlyphExtents(aRefContext, glyphIndex, true, extents);
+                        font->SetupGlyphExtents(aRefContext, orientation,
+                                                glyphIndex, true, extents);
                     }
                 }
             }
         }
     }
 }
 
 
@@ -1879,17 +1887,18 @@ gfxFontGroup::MakeSpaceTextRun(const Par
             // Normally, the font has a cached space glyph, so we can avoid
             // the cost of calling FindFontForChar.
             textRun->SetSpaceGlyph(font, aParams->mContext, 0, orientation);
         } else {
             // In case the primary font doesn't have <space> (bug 970891),
             // find one that does.
             uint8_t matchType;
             nsRefPtr<gfxFont> spaceFont =
-                FindFontForChar(' ', 0, MOZ_SCRIPT_LATIN, nullptr, &matchType);
+                FindFontForChar(' ', 0, 0, MOZ_SCRIPT_LATIN, nullptr,
+                                &matchType);
             if (spaceFont) {
                 textRun->SetSpaceGlyph(spaceFont, aParams->mContext, 0,
                                        orientation);
             }
         }
     }
 
     // Note that the gfxGlyphExtents glyph bounds storage for the font will
@@ -2468,33 +2477,36 @@ gfxFontGroup::GetUnderlineOffset()
         for (uint32_t i = 0; i < len; i++) {
             FamilyFace& ff = mFonts[i];
             if (!ff.IsUserFont() && ff.Family() &&
                 ff.Family()->IsBadUnderlineFamily()) {
                 nsRefPtr<gfxFont> font = GetFontAt(i);
                 if (!font) {
                     continue;
                 }
-                gfxFloat bad = font->GetMetrics().underlineOffset;
+                gfxFloat bad = font->GetMetrics(gfxFont::eHorizontal).
+                                         underlineOffset;
                 gfxFloat first =
-                    GetFirstValidFont()->GetMetrics().underlineOffset;
+                    GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal).
+                                             underlineOffset;
                 mUnderlineOffset = std::min(first, bad);
                 return mUnderlineOffset;
             }
         }
 
         // no bad underline fonts, use the first valid font's metric
-        mUnderlineOffset = GetFirstValidFont()->GetMetrics().underlineOffset;
+        mUnderlineOffset = GetFirstValidFont()->
+            GetMetrics(gfxFont::eHorizontal).underlineOffset;
     }
 
     return mUnderlineOffset;
 }
 
 already_AddRefed<gfxFont>
-gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
+gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
                               int32_t aRunScript, gfxFont *aPrevMatchedFont,
                               uint8_t *aMatchType)
 {
     // To optimize common cases, try the first font in the font-group
     // before going into the more detailed checks below
     uint32_t nextIndex = 0;
     bool isJoinControl = gfxFontUtils::IsJoinControl(aCh);
     bool wasJoinCauser = gfxFontUtils::IsJoinCauser(aPrevCh);
@@ -2644,63 +2656,84 @@ gfxFontGroup::FindFontForChar(uint32_t a
             HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR &&
         GetFirstValidFont()->SynthesizeSpaceWidth(aCh) >= 0.0)
     {
         return nullptr;
     }
 
     // -- otherwise look for other stuff
     *aMatchType = gfxTextRange::kSystemFallback;
-    font = WhichSystemFontSupportsChar(aCh, aRunScript);
+    font = WhichSystemFontSupportsChar(aCh, aNextCh, aRunScript);
     return font.forget();
 }
 
 template<typename T>
 void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
                                  const T *aString, uint32_t aLength,
                                  int32_t aRunScript, uint16_t aOrientation)
 {
     NS_ASSERTION(aRanges.Length() == 0, "aRanges must be initially empty");
     NS_ASSERTION(aLength > 0, "don't call ComputeRanges for zero-length text");
 
     uint32_t prevCh = 0;
+    uint32_t nextCh = aString[0];
+    if (sizeof(T) == sizeof(char16_t)) {
+        if (aLength > 1 && NS_IS_HIGH_SURROGATE(nextCh) &&
+                           NS_IS_LOW_SURROGATE(aString[1])) {
+            nextCh = SURROGATE_TO_UCS4(nextCh, aString[1]);
+        }
+    }
     int32_t lastRangeIndex = -1;
 
     // initialize prevFont to the group's primary font, so that this will be
     // used for string-initial control chars, etc rather than risk hitting font
     // fallback for these (bug 716229)
     gfxFont *prevFont = GetFirstValidFont();
 
     // if we use the initial value of prevFont, we treat this as a match from
     // the font group; fixes bug 978313
     uint8_t matchType = gfxTextRange::kFontGroup;
 
     for (uint32_t i = 0; i < aLength; i++) {
 
         const uint32_t origI = i; // save off in case we increase for surrogate
 
         // set up current ch
-        uint32_t ch = aString[i];
-
-        // in 16-bit case only, check for surrogate pair
+        uint32_t ch = nextCh;
+
+        // Get next char (if any) so that FindFontForChar can look ahead
+        // for a possible variation selector.
+
         if (sizeof(T) == sizeof(char16_t)) {
-            if ((i + 1 < aLength) && NS_IS_HIGH_SURROGATE(ch) &&
-                                 NS_IS_LOW_SURROGATE(aString[i + 1])) {
+            // In 16-bit case only, check for surrogate pairs.
+            if (ch > 0xffffu) {
                 i++;
-                ch = SURROGATE_TO_UCS4(ch, aString[i]);
             }
+            if (i < aLength - 1) {
+                nextCh = aString[i + 1];
+                if ((i + 2 < aLength) && NS_IS_HIGH_SURROGATE(nextCh) &&
+                                         NS_IS_LOW_SURROGATE(aString[i + 2])) {
+                    nextCh = SURROGATE_TO_UCS4(nextCh, aString[i + 2]);
+                }
+            } else {
+                nextCh = 0;
+            }
+        } else {
+            // 8-bit case is trivial.
+            nextCh = i < aLength - 1 ? aString[i + 1] : 0;
         }
 
         if (ch == 0xa0) {
             ch = ' ';
         }
 
         // find the font for this char
         nsRefPtr<gfxFont> font =
-            FindFontForChar(ch, prevCh, aRunScript, prevFont, &matchType);
+            FindFontForChar(ch, prevCh, nextCh, aRunScript, prevFont,
+                            &matchType);
 
 #ifndef RELEASE_BUILD
         if (MOZ_UNLIKELY(mTextPerf)) {
             if (matchType == gfxTextRange::kPrefsFallback) {
                 mTextPerf->current.fallbackPrefs++;
             } else if (matchType == gfxTextRange::kSystemFallback) {
                 mTextPerf->current.fallbackSystem++;
             }
@@ -2926,21 +2959,22 @@ gfxFontGroup::WhichPrefFontSupportsChar(
 
         }
     }
 
     return nullptr;
 }
 
 already_AddRefed<gfxFont>
-gfxFontGroup::WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript)
+gfxFontGroup::WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh,
+                                          int32_t aRunScript)
 {
     gfxFontEntry *fe = 
         gfxPlatformFontList::PlatformFontList()->
-            SystemFindFontForChar(aCh, aRunScript, &mStyle);
+            SystemFindFontForChar(aCh, aNextCh, aRunScript, &mStyle);
     if (fe) {
         bool wantBold = mStyle.ComputeWeight() >= 6;
         nsRefPtr<gfxFont> font =
             fe->FindOrMakeFont(&mStyle, wantBold && !fe->IsBold());
         return font.forget();
     }
 
     return nullptr;
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -813,25 +813,26 @@ public:
     // If this group has such "bad" font, each platform's gfxFontGroup
     // initialized mUnderlineOffset. The value should be lower value of
     // first font's metrics and the bad font's metrics. Otherwise, this
     // returns from first font's metrics.
     enum { UNDERLINE_OFFSET_NOT_SET = INT16_MAX };
     virtual gfxFloat GetUnderlineOffset();
 
     virtual already_AddRefed<gfxFont>
-        FindFontForChar(uint32_t ch, uint32_t prevCh, int32_t aRunScript,
-                        gfxFont *aPrevMatchedFont,
+        FindFontForChar(uint32_t ch, uint32_t prevCh, uint32_t aNextCh,
+                        int32_t aRunScript, gfxFont *aPrevMatchedFont,
                         uint8_t *aMatchType);
 
     // search through pref fonts for a character, return nullptr if no matching pref font
     virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh);
 
-    virtual already_AddRefed<gfxFont>
-        WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript);
+    already_AddRefed<gfxFont>
+        WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh,
+                                    int32_t aRunScript);
 
     template<typename T>
     void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
                        const T *aString, uint32_t aLength,
                        int32_t aRunScript, uint16_t aOrientation);
 
     gfxUserFontSet* GetUserFontSet();
 
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -589,16 +589,17 @@ gfxUtils::DrawPixelSnapped(gfxContext*  
 
     nsRefPtr<gfxDrawable> drawable = aDrawable;
 
     aFilter = ReduceResamplingFilter(aFilter,
                                      imageRect.Width(), imageRect.Height(),
                                      region.Width(), region.Height());
 
     if (aRegion.IsRestricted() &&
+        aContext->CurrentMatrix().HasNonIntegerTranslation() &&
         drawable->DrawWithSamplingRect(aContext, aRegion.Rect(), aRegion.Restriction(),
                                        doTile, aFilter, aOpacity)) {
       return;
     }
 
     // On Mobile, we don't ever want to do this; it has the potential for
     // allocating very large temporary surfaces, especially since we'll
     // do full-page snapshots often (see bug 749426).
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -720,28 +720,39 @@ static const char kFontSegoeUI[] = "Sego
 static const char kFontSegoeUIEmoji[] = "Segoe UI Emoji";
 static const char kFontSegoeUISymbol[] = "Segoe UI Symbol";
 static const char kFontSylfaen[] = "Sylfaen";
 static const char kFontTraditionalArabic[] = "Traditional Arabic";
 static const char kFontUtsaah[] = "Utsaah";
 static const char kFontYuGothic[] = "Yu Gothic";
 
 void
-gfxWindowsPlatform::GetCommonFallbackFonts(const uint32_t aCh,
+gfxWindowsPlatform::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                            int32_t aRunScript,
                                            nsTArray<const char*>& aFontList)
 {
+    if (aNextCh == 0xfe0fu) {
+        aFontList.AppendElement(kFontSegoeUIEmoji);
+    }
+
     // Arial is used as the default fallback for system fallback
     aFontList.AppendElement(kFontArial);
 
     if (!IS_IN_BMP(aCh)) {
         uint32_t p = aCh >> 16;
         if (p == 1) { // SMP plane
-            aFontList.AppendElement(kFontSegoeUIEmoji);
-            aFontList.AppendElement(kFontSegoeUISymbol);
+            if (aNextCh == 0xfe0eu) {
+                aFontList.AppendElement(kFontSegoeUISymbol);
+                aFontList.AppendElement(kFontSegoeUIEmoji);
+            } else {
+                if (aNextCh != 0xfe0fu) {
+                    aFontList.AppendElement(kFontSegoeUIEmoji);
+                }
+                aFontList.AppendElement(kFontSegoeUISymbol);
+            }
             aFontList.AppendElement(kFontEbrima);
             aFontList.AppendElement(kFontNirmalaUI);
             aFontList.AppendElement(kFontCambriaMath);
         }
     } else {
         uint32_t b = (aCh >> 8) & 0xff;
 
         switch (b) {
@@ -809,17 +820,16 @@ gfxWindowsPlatform::GetCommonFallbackFon
         case 0x25:
         case 0x26:
         case 0x27:
         case 0x29:
         case 0x2a:
         case 0x2b:
         case 0x2c:
             aFontList.AppendElement(kFontSegoeUI);
-            aFontList.AppendElement(kFontSegoeUIEmoji);
             aFontList.AppendElement(kFontSegoeUISymbol);
             aFontList.AppendElement(kFontCambria);
             aFontList.AppendElement(kFontMeiryo);
             aFontList.AppendElement(kFontArial);
             aFontList.AppendElement(kFontLucidaSansUnicode);
             aFontList.AppendElement(kFontEbrima);
             break;
         case 0x2d:
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -181,17 +181,17 @@ public:
     double GetDPIScale();
 
     nsresult GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts);
 
     nsresult UpdateFontList();
 
-    virtual void GetCommonFallbackFonts(const uint32_t aCh,
+    virtual void GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                         int32_t aRunScript,
                                         nsTArray<const char*>& aFontList);
 
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     gfxFontGroup *CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                                   const gfxFontStyle *aStyle,
                                   gfxUserFontSet *aUserFontSet);
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -525,16 +525,23 @@ bool imgFrame::Draw(gfxContext* aContext
   RefPtr<SourceSurface> surf = GetSurface();
   if (!surf && !mSinglePixel) {
     return false;
   }
 
   bool doTile = !imageRect.Contains(aRegion.Rect()) &&
                 !(aImageFlags & imgIContainer::FLAG_CLAMP);
   ImageRegion region(aRegion);
+  // SurfaceForDrawing changes the current transform, and we need it to still
+  // be changed when we call gfxUtils::DrawPixelSnapped. We still need to
+  // restore it before returning though.
+  // XXXjwatt In general having functions require someone further up the stack
+  // to undo transform changes that they make is bad practice. We should
+  // change how this code works.
+  gfxContextMatrixAutoSaveRestore autoSR(aContext);
   SurfaceWithFormat surfaceResult =
     SurfaceForDrawing(doPadding, doPartialDecode, doTile, aContext,
                       aPadding, imageRect, region, surf);
 
   if (surfaceResult.IsValid()) {
     gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable,
                                imageRect.Size(), region, surfaceResult.mFormat,
                                aFilter, aImageFlags);
--- a/image/test/reftest/downscaling/reftest.list
+++ b/image/test/reftest/downscaling/reftest.list
@@ -39,66 +39,58 @@ default-preferences pref(image.high_qual
 
 fuzzy-if(winWidget,16,20) fuzzy-if(cocoaWidget,106,31) == downscale-1.html downscale-1-ref.html
 
 fuzzy(20,999) != downscale-2a.html?203,52,left about:blank
 fuzzy(20,999) != downscale-2b.html?203,52,left about:blank
 fuzzy(20,999) != downscale-2c.html?203,52,left about:blank
 fuzzy(20,999) != downscale-2d.html?203,52,left about:blank
 fuzzy(20,999) != downscale-2e.html?203,52,left about:blank
-fuzzy(20,999) fails-if(!cocoaWidget) != downscale-2f.html?203,52,left about:blank
 
 fuzzy(20,999) != downscale-2a.html?205,53,left about:blank
 fuzzy(20,999) != downscale-2b.html?205,53,left about:blank
 fuzzy(20,999) != downscale-2c.html?205,53,left about:blank
 fuzzy(20,999) != downscale-2d.html?205,53,left about:blank
 fuzzy(20,999) != downscale-2e.html?205,53,left about:blank
-fuzzy(20,999) fails-if(!cocoaWidget) != downscale-2f.html?205,53,left about:blank
 
 fuzzy(20,999) != downscale-2a.html?203,52,right about:blank
 fuzzy(20,999) != downscale-2b.html?203,52,right about:blank
 fuzzy(20,999) != downscale-2c.html?203,52,right about:blank
 fuzzy(20,999) != downscale-2d.html?203,52,right about:blank
 fuzzy(20,999) != downscale-2e.html?203,52,right about:blank
-fuzzy(20,999) random-if(!cocoaWidget) != downscale-2f.html?203,52,right about:blank
 
 fuzzy(20,999) != downscale-2a.html?205,53,right about:blank
 fuzzy(20,999) != downscale-2b.html?205,53,right about:blank
 fuzzy(20,999) != downscale-2c.html?205,53,right about:blank
 fuzzy(20,999) != downscale-2d.html?205,53,right about:blank
 fuzzy(20,999) != downscale-2e.html?205,53,right about:blank
-fuzzy(20,999) random-if(!cocoaWidget) != downscale-2f.html?205,53,right about:blank
 
 fuzzy(20,999) != downscale-2a.html?203,52,top about:blank
 fuzzy(20,999) != downscale-2b.html?203,52,top about:blank
 fuzzy(20,999) != downscale-2c.html?203,52,top about:blank
 fuzzy(20,999) != downscale-2d.html?203,52,top about:blank
 fuzzy(20,999) != downscale-2e.html?203,52,top about:blank
-fuzzy(20,999) fails-if(!cocoaWidget) != downscale-2f.html?203,52,top about:blank
 
 fuzzy(20,999) != downscale-2a.html?205,53,top about:blank
 fuzzy(20,999) != downscale-2b.html?205,53,top about:blank
 fuzzy(20,999) != downscale-2c.html?205,53,top about:blank
 fuzzy(20,999) != downscale-2d.html?205,53,top about:blank
 fuzzy(20,999) != downscale-2e.html?205,53,top about:blank
-fuzzy(20,999) fails-if(!cocoaWidget) != downscale-2f.html?205,53,top about:blank
 
 fuzzy(20,999) != downscale-2a.html?203,52,bottom about:blank
 fuzzy(20,999) != downscale-2b.html?203,52,bottom about:blank
 fuzzy(20,999) != downscale-2c.html?203,52,bottom about:blank
 fuzzy(20,999) != downscale-2d.html?203,52,bottom about:blank
 fuzzy(20,999) != downscale-2e.html?203,52,bottom about:blank
-fuzzy(20,999) fails-if(!cocoaWidget) != downscale-2f.html?203,52,bottom about:blank
 
 fuzzy(20,999) != downscale-2a.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2b.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2c.html?205,53,bottom about:blank
 fuzzy(20,999) != downscale-2d.html?205,53,bottom about:blank
-fuzzy(20,999) != downscale-2e.html?205,53,bottom about:blank
-fuzzy(20,999) fails-if(!cocoaWidget) != downscale-2f.html?205,53,bottom about:blank
+fuzzy(20,999) fails-if(OSX==10.8) != downscale-2e.html?205,53,bottom about:blank
 
 # RUN TESTS WITH HIGH QUALITY DOWNSCALING ENABLED:
 # ================================================
 # High-quality downscaling enabled:
 default-preferences pref(image.high_quality_downscaling.enabled,true)
 
 fuzzy(31,127) fuzzy-if(d2d,31,147) == downscale-1.html downscale-1-ref.html # intermittently 147 pixels on win7 accelerated only (not win8)
 
--- a/ipc/glue/ProcessUtils_linux.cpp
+++ b/ipc/glue/ProcessUtils_linux.cpp
@@ -22,31 +22,35 @@
 #include "mozilla/ipc/PProcLoaderChild.h"
 #include "mozilla/ipc/Transport.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/IOThreadChild.h"
 #include "mozilla/dom/ContentProcess.h"
 #include "base/file_descriptor_shuffle.h"
 #include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/DebugOnly.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/unused.h"
 #include "base/process_util.h"
+#include "base/eintr_wrapper.h"
 
 #include "prenv.h"
 
 #include "nsXULAppAPI.h" // export XRE_* functions
 
 #include "nsAppRunner.h"
 
 int content_process_main(int argc, char *argv[]);
 
-extern bool gDisableAndroidLog;
+typedef mozilla::Vector<int> FdArray;
 
 #endif /* MOZ_B2G_LOADER */
 
 namespace mozilla {
+
 namespace ipc {
 
 void SetThisProcessName(const char *aName)
 {
   prctl(PR_SET_NAME, (unsigned long)aName, 0uL, 0uL, 0uL);
 }
 
 #ifdef MOZ_B2G_LOADER
@@ -93,19 +97,28 @@ using namespace mozilla::dom;
 
 static bool sProcLoaderClientOnDeinit = false;
 static DebugOnly<bool> sProcLoaderClientInitialized = false;
 static DebugOnly<bool> sProcLoaderClientGeckoInitialized = false;
 static pid_t sProcLoaderPid = 0;
 static int sProcLoaderChannelFd = -1;
 static PProcLoaderParent *sProcLoaderParent = nullptr;
 static MessageLoop *sProcLoaderLoop = nullptr;
+static mozilla::UniquePtr<FdArray> sReservedFds;
 
 static void ProcLoaderClientDeinit();
 
+/**
+ * Some file descriptors, like the child IPC channel FD, must be opened at
+ * specific numbers. To ensure this, we pre-reserve kReservedFileDescriptors FDs
+ * starting from kBeginReserveFileDescriptor so that operations like
+ * __android_log_print() won't take these magic FDs.
+ */
+static const int kReservedFileDescriptors = 5;
+static const int kBeginReserveFileDescriptor = STDERR_FILENO + 1;
 
 class ProcLoaderParent : public PProcLoaderParent
 {
 private:
   nsAutoPtr<FileDescriptor> mChannelFd; // To keep a reference.
 
 public:
   ProcLoaderParent(FileDescriptor *aFd) : mChannelFd(aFd) {}
@@ -134,16 +147,24 @@ static void
 bool
 ProcLoaderParent::RecvLoadComplete(const int32_t &aPid,
                                    const int32_t &aCookie)
 {
   ProcLoaderClientDeinit();
   return true;
 }
 
+static void
+CloseFileDescriptors(FdArray& aFds)
+{
+  for (size_t i = 0; i < aFds.length(); i++) {
+    unused << HANDLE_EINTR(close(aFds[i]));
+  }
+}
+
 void
 ProcLoaderParent::OnChannelError()
 {
   if (sProcLoaderClientOnDeinit) {
     // Get error for closing while the channel is already error.
     return;
   }
   NS_WARNING("ProcLoaderParent is in channel error");
@@ -287,30 +308,30 @@ class ProcLoaderRunnerBase;
 
 static bool sProcLoaderServing = false;
 static ProcLoaderRunnerBase *sProcLoaderDispatchedTask = nullptr;
 
 class ProcLoaderRunnerBase
 {
 public:
   virtual int DoWork() = 0;
+  virtual ~ProcLoaderRunnerBase() {}
 };
 
 
 class ProcLoaderNoopRunner : public ProcLoaderRunnerBase {
 public:
   virtual int DoWork();
 };
 
 int
 ProcLoaderNoopRunner::DoWork() {
   return 0;
 }
 
-
 /**
  * The runner to load Nuwa at the current process.
  */
 class ProcLoaderLoadRunner : public ProcLoaderRunnerBase {
 private:
   const nsTArray<nsCString> mArgv;
   const nsTArray<nsCString> mEnv;
   const nsTArray<FDRemap> mFdsRemap;
@@ -331,32 +352,51 @@ public:
   int DoWork();
 };
 
 void
 ProcLoaderLoadRunner::ShuffleFds()
 {
   unsigned int i;
 
+  MOZ_ASSERT(mFdsRemap.Length() <= kReservedFileDescriptors);
+
   InjectiveMultimap fd_shuffle1, fd_shuffle2;
   fd_shuffle1.reserve(mFdsRemap.Length());
   fd_shuffle2.reserve(mFdsRemap.Length());
+
   for (i = 0; i < mFdsRemap.Length(); i++) {
     const FDRemap *map = &mFdsRemap[i];
     int fd = map->fd().PlatformHandle();
     int tofd = map->mapto();
 
     fd_shuffle1.push_back(InjectionArc(fd, tofd, false));
     fd_shuffle2.push_back(InjectionArc(fd, tofd, false));
+
+    // Erase from sReservedFds we will use.
+    for (int* toErase = sReservedFds->begin();
+         toErase < sReservedFds->end();
+         toErase++) {
+      if (tofd == *toErase) {
+        sReservedFds->erase(toErase);
+        break;
+      }
+    }
   }
 
   DebugOnly<bool> ok = ShuffleFileDescriptors(&fd_shuffle1);
-  MOZ_ASSERT(ok, "ShuffleFileDescriptors failed");
 
-  CloseSuperfluousFds(fd_shuffle2);
+  // Close the FDs that are reserved but not used after
+  // ShuffleFileDescriptors().
+  MOZ_ASSERT(sReservedFds);
+  CloseFileDescriptors(*sReservedFds);
+  sReservedFds = nullptr;
+
+  // Note that we don'e call ::base::CloseSuperfluousFds() here, assuming that
+  // The file descriptor inherited from the parent are also necessary for us.
 }
 
 int
 ProcLoaderLoadRunner::DoWork()
 {
   unsigned int i;
 
   ShuffleFds();
@@ -477,37 +517,39 @@ public:
  *
  * \param aPeerPid is the pid of the parent.
  * \param aFd is the file descriptor of the socket for IPC.
  *
  * See the comment near the head of this file.
  */
 static int
 ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
-                     int aArgc, const char *aArgv[])
+                     int aArgc, const char *aArgv[],
+                     FdArray& aReservedFds)
 {
+  // Make a copy of aReservedFds. It will be used when we dup() the magic file
+  // descriptors when ProcLoaderChild::RecvLoad() runs.
+  sReservedFds = MakeUnique<FdArray>(mozilla::Move(aReservedFds));
+
   ScopedLogging logging;
 
   char **_argv;
   _argv = new char *[aArgc + 1];
   for (int i = 0; i < aArgc; i++) {
     _argv[i] = ::strdup(aArgv[i]);
     MOZ_ASSERT(_argv[i] != nullptr);
   }
   _argv[aArgc] = nullptr;
 
   gArgv = _argv;
   gArgc = aArgc;
 
   {
-    gDisableAndroidLog = true;
-
     nsresult rv = XRE_InitCommandLine(aArgc, _argv);
     if (NS_FAILED(rv)) {
-      gDisableAndroidLog = false;
       MOZ_CRASH();
     }
 
     FileDescriptor fd(aFd);
     close(aFd);
 
     MOZ_ASSERT(!sProcLoaderServing);
     MessageLoop loop;
@@ -525,18 +567,16 @@ ProcLoaderServiceRun(pid_t aPeerPid, int
     BackgroundHangMonitor::Prohibit();
 
     sProcLoaderServing = true;
     loop.Run();
 
     BackgroundHangMonitor::Allow();
 
     XRE_DeinitCommandLine();
-
-    gDisableAndroidLog = false;
   }
 
   MOZ_ASSERT(sProcLoaderDispatchedTask != nullptr);
   ProcLoaderRunnerBase *task = sProcLoaderDispatchedTask;
   sProcLoaderDispatchedTask = nullptr;
   int ret = task->DoWork();
   delete task;
 
@@ -550,21 +590,27 @@ ProcLoaderServiceRun(pid_t aPeerPid, int
 
 #endif /* MOZ_B2G_LOADER */
 
 } // namespace ipc
 } // namespace mozilla
 
 #ifdef MOZ_B2G_LOADER
 void
-XRE_ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd)
+XRE_ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd, FdArray& aReservedFds)
 {
+  // We already performed fork(). It's safe to free the "danger zone" of file
+  // descriptors .
+  mozilla::ipc::CloseFileDescriptors(aReservedFds);
+
   mozilla::ipc::ProcLoaderClientInit(aPeerPid, aChannelFd);
 }
 
 int
 XRE_ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
-                         int aArgc, const char *aArgv[])
+                         int aArgc, const char *aArgv[],
+                         FdArray& aReservedFds)
 {
   return mozilla::ipc::ProcLoaderServiceRun(aPeerPid, aFd,
-                                            aArgc, aArgv);
+                                            aArgc, aArgv,
+                                            aReservedFds);
 }
 #endif /* MOZ_B2G_LOADER */
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -1039,22 +1039,16 @@ obj_preventExtensions(JSContext *cx, uns
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, args, "Object.preventExtensions", &obj))
         return false;
 
     args.rval().setObject(*obj);
 
-    bool extensible;
-    if (!JSObject::isExtensible(cx, obj, &extensible))
-        return false;
-    if (!extensible)
-        return true;
-
     return JSObject::preventExtensions(cx, obj);
 }
 
 static bool
 obj_freeze(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject obj(cx);
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -452,16 +452,17 @@ frontend::CompileScript(ExclusiveContext
     if (options.forEval)
         MarkFunctionsWithinEvalScript(script);
 
     bce.tellDebuggerAboutCompiledScript(cx);
 
     if (sct && !extraSct && !sct->complete())
         return nullptr;
 
+    MOZ_ASSERT_IF(cx->isJSContext(), !cx->asJSContext()->isExceptionPending());
     return script;
 }
 
 bool
 frontend::CompileLazyFunction(JSContext *cx, Handle<LazyScript*> lazy, const char16_t *chars, size_t length)
 {
     JS_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2193,16 +2193,18 @@ Parser<FullParseHandler>::functionArgsAn
                 return false;
 
             if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric,
                                                     fun, type, kind))
             {
                 if (parser->hadAbortedSyntaxParse()) {
                     // Try again with a full parse.
                     parser->clearAbortedSyntaxParse();
+                    MOZ_ASSERT_IF(parser->context->isJSContext(),
+                                  !parser->context->asJSContext()->isExceptionPending());
                     break;
                 }
                 return false;
             }
 
             outerpc->blockidGen = funpc.blockidGen;
 
             // Advance this parser over tokens processed by the syntax parser.
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -287,24 +287,24 @@ static const PhaseInfo phases[] = {
             { PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK },
             { PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK },
             { PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK },
         { PHASE_FINALIZE_START, "Finalize Start Callback", PHASE_SWEEP },
         { PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP },
         { PHASE_SWEEP_SYMBOL_REGISTRY, "Sweep Symbol Registry", PHASE_SWEEP },
         { PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments", PHASE_SWEEP },
             { PHASE_SWEEP_DISCARD_CODE, "Sweep Discard Code", PHASE_SWEEP_COMPARTMENTS },
-            { PHASE_SWEEP_TABLES, "Sweep Tables", PHASE_SWEEP_COMPARTMENTS },
-                { PHASE_SWEEP_TABLES_INNER_VIEWS, "Sweep Inner Views", PHASE_SWEEP_TABLES },
-                { PHASE_SWEEP_TABLES_WRAPPER, "Sweep Cross Compartment Wrappers", PHASE_SWEEP_TABLES },
-                { PHASE_SWEEP_TABLES_BASE_SHAPE, "Sweep Base Shapes", PHASE_SWEEP_TABLES },
-                { PHASE_SWEEP_TABLES_INITIAL_SHAPE, "Sweep Initial Shapes", PHASE_SWEEP_TABLES },
-                { PHASE_SWEEP_TABLES_TYPE_OBJECT, "Sweep Type Objects", PHASE_SWEEP_TABLES },
-                { PHASE_SWEEP_TABLES_BREAKPOINT, "Sweep Breakpoints", PHASE_SWEEP_TABLES },
-                { PHASE_SWEEP_TABLES_REGEXP, "Sweep Regexps", PHASE_SWEEP_TABLES },
+            { PHASE_SWEEP_INNER_VIEWS, "Sweep Inner Views", PHASE_SWEEP_COMPARTMENTS },
+            { PHASE_SWEEP_CC_WRAPPER, "Sweep Cross Compartment Wrappers", PHASE_SWEEP_COMPARTMENTS },
+            { PHASE_SWEEP_BASE_SHAPE, "Sweep Base Shapes", PHASE_SWEEP_COMPARTMENTS },
+            { PHASE_SWEEP_INITIAL_SHAPE, "Sweep Initial Shapes", PHASE_SWEEP_COMPARTMENTS },
+            { PHASE_SWEEP_TYPE_OBJECT, "Sweep Type Objects", PHASE_SWEEP_COMPARTMENTS },
+            { PHASE_SWEEP_BREAKPOINT, "Sweep Breakpoints", PHASE_SWEEP_COMPARTMENTS },
+            { PHASE_SWEEP_REGEXP, "Sweep Regexps", PHASE_SWEEP_COMPARTMENTS },
+            { PHASE_SWEEP_MISC, "Sweep Miscellaneous", PHASE_SWEEP_COMPARTMENTS },
             { PHASE_DISCARD_ANALYSIS, "Discard Analysis", PHASE_SWEEP_COMPARTMENTS },
                 { PHASE_DISCARD_TI, "Discard TI", PHASE_DISCARD_ANALYSIS },
                 { PHASE_FREE_TI_ARENA, "Free TI Arena", PHASE_DISCARD_ANALYSIS },
                 { PHASE_SWEEP_TYPES, "Sweep Types", PHASE_DISCARD_ANALYSIS },
         { PHASE_SWEEP_OBJECT, "Sweep Object", PHASE_SWEEP },
         { PHASE_SWEEP_STRING, "Sweep String", PHASE_SWEEP },
         { PHASE_SWEEP_SCRIPT, "Sweep Script", PHASE_SWEEP },
         { PHASE_SWEEP_SHAPE, "Sweep Shape", PHASE_SWEEP },
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -38,24 +38,24 @@ enum Phase {
     PHASE_SWEEP_MARK_INCOMING_GRAY,
     PHASE_SWEEP_MARK_GRAY,
     PHASE_SWEEP_MARK_GRAY_WEAK,
     PHASE_FINALIZE_START,
     PHASE_SWEEP_ATOMS,
     PHASE_SWEEP_SYMBOL_REGISTRY,
     PHASE_SWEEP_COMPARTMENTS,
     PHASE_SWEEP_DISCARD_CODE,
-    PHASE_SWEEP_TABLES,
-    PHASE_SWEEP_TABLES_INNER_VIEWS,
-    PHASE_SWEEP_TABLES_WRAPPER,
-    PHASE_SWEEP_TABLES_BASE_SHAPE,
-    PHASE_SWEEP_TABLES_INITIAL_SHAPE,
-    PHASE_SWEEP_TABLES_TYPE_OBJECT,
-    PHASE_SWEEP_TABLES_BREAKPOINT,
-    PHASE_SWEEP_TABLES_REGEXP,
+    PHASE_SWEEP_INNER_VIEWS,
+    PHASE_SWEEP_CC_WRAPPER,
+    PHASE_SWEEP_BASE_SHAPE,
+    PHASE_SWEEP_INITIAL_SHAPE,
+    PHASE_SWEEP_TYPE_OBJECT,
+    PHASE_SWEEP_BREAKPOINT,
+    PHASE_SWEEP_REGEXP,
+    PHASE_SWEEP_MISC,
     PHASE_DISCARD_ANALYSIS,
     PHASE_DISCARD_TI,
     PHASE_FREE_TI_ARENA,
     PHASE_SWEEP_TYPES,
     PHASE_SWEEP_OBJECT,
     PHASE_SWEEP_STRING,
     PHASE_SWEEP_SCRIPT,
     PHASE_SWEEP_SHAPE,
@@ -229,50 +229,37 @@ struct AutoGCSlice
     Statistics &stats;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 struct AutoPhase
 {
     AutoPhase(Statistics &