Merge m-c to fx-team. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 27 Mar 2015 12:21:41 -0400
changeset 265005 16c68807669eb4c3ddd2ef01268bb4e7313ad418
parent 265004 da754eb43be35889ac0a7cc641a36c1c4841229b (current diff)
parent 264961 44e454b5e93b64cdb77a025c5d6b8d8ca5c2926e (diff)
child 265006 2a5d7568660523e12a46f4fd6cc791fce4748fb3
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team. a=merge
dom/base/ScriptSettings.cpp
testing/marionette/marionette-actions.js
testing/marionette/marionette-common.js
testing/marionette/marionette-elements.js
testing/marionette/marionette-frame-manager.js
testing/marionette/marionette-listener.js
testing/marionette/marionette-sendkeys.js
testing/marionette/marionette-server.js
testing/marionette/marionette-simpletest.js
--- a/accessible/atk/nsMaiInterfaceValue.cpp
+++ b/accessible/atk/nsMaiInterfaceValue.cpp
@@ -3,98 +3,123 @@
 /* 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 "InterfaceInitFuncs.h"
 
 #include "AccessibleWrap.h"
 #include "nsMai.h"
-
+#include "ProxyAccessible.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 extern "C" {
 
 static void
 getCurrentValueCB(AtkValue *obj, GValue *value)
 {
+  ProxyAccessible* proxy = nullptr;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
-  if (!accWrap)
-    return;
+  if (!accWrap) {
+    proxy = GetProxy(ATK_OBJECT(obj));
+    if (!proxy) {
+      return;
+    }
+  }
 
   memset (value,  0, sizeof (GValue));
-  double accValue = accWrap->CurValue();
+  double accValue = accWrap ? accWrap->CurValue() : proxy->CurValue();
   if (IsNaN(accValue))
     return;
 
   g_value_init (value, G_TYPE_DOUBLE);
   g_value_set_double (value, accValue);
 }
 
 static void
 getMaximumValueCB(AtkValue *obj, GValue *value)
 {
+  ProxyAccessible* proxy = nullptr;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
-  if (!accWrap)
-    return;
+  if (!accWrap) {
+    proxy = GetProxy(ATK_OBJECT(obj));
+    if (!proxy) {
+      return;
+    }
+  }
 
   memset(value,  0, sizeof (GValue));
-  double accValue = accWrap->MaxValue();
+  double accValue = accWrap ? accWrap->MaxValue() : proxy->MaxValue();
   if (IsNaN(accValue))
     return;
 
   g_value_init(value, G_TYPE_DOUBLE);
   g_value_set_double(value, accValue);
 }
 
 static void
 getMinimumValueCB(AtkValue *obj, GValue *value)
 {
+  ProxyAccessible* proxy = nullptr;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
-  if (!accWrap)
-    return;
+  if (!accWrap) {
+    proxy = GetProxy(ATK_OBJECT(obj));
+    if (!proxy) {
+      return;
+    }
+  }
 
   memset(value,  0, sizeof (GValue));
-  double accValue = accWrap->MinValue();
+  double accValue = accWrap ? accWrap->MinValue() : proxy->MinValue();
   if (IsNaN(accValue))
     return;
 
   g_value_init(value, G_TYPE_DOUBLE);
   g_value_set_double(value, accValue);
 }
 
 static void
 getMinimumIncrementCB(AtkValue *obj, GValue *minimumIncrement)
 {
+  ProxyAccessible* proxy = nullptr;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
-  if (!accWrap)
-    return;
+  if (!accWrap) {
+    proxy = GetProxy(ATK_OBJECT(obj));
+    if (!proxy) {
+      return;
+    }
+  }
 
   memset(minimumIncrement,  0, sizeof (GValue));
-  double accValue = accWrap->Step();
+  double accValue = accWrap ? accWrap->Step() : proxy->Step();
   if (IsNaN(accValue))
     accValue = 0; // zero if the minimum increment is undefined
 
   g_value_init(minimumIncrement, G_TYPE_DOUBLE);
   g_value_set_double(minimumIncrement, accValue);
 }
 
 static gboolean
 setCurrentValueCB(AtkValue *obj, const GValue *value)
 {
+  ProxyAccessible* proxy = nullptr;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
-  if (!accWrap)
-    return FALSE;
+  if (!accWrap) {
+    proxy = GetProxy(ATK_OBJECT(obj));
+    if (!proxy) {
+      return FALSE;
+    }
+  }
 
   double accValue =g_value_get_double(value);
-  return accWrap->SetCurValue(accValue);
+  return accWrap ? accWrap->SetCurValue(accValue) : proxy->SetCurValue(accValue);
 }
 }
 
 void
 valueInterfaceInitCB(AtkValueIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid aIface");
   if (MOZ_UNLIKELY(!aIface))
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -528,18 +528,19 @@ nsAccessibilityService::ContentRemoved(n
   DocAccessible* document = GetDocAccessible(aPresShell);
   if (document) {
     // Flatten hierarchy may be broken at this point so we cannot get a true
     // container by traversing up the DOM tree. Find a parent of first accessible
     // from the subtree of the given DOM node, that'll be a container. If no
     // accessibles in subtree then we don't care about the change.
     Accessible* child = document->GetAccessible(aChildNode);
     if (!child) {
-      a11y::TreeWalker walker(document->GetContainerAccessible(aChildNode),
-                              aChildNode, a11y::TreeWalker::eWalkCache);
+      Accessible* container = document->GetContainerAccessible(aChildNode);
+      a11y::TreeWalker walker(container ? container : document, aChildNode,
+                              a11y::TreeWalker::eWalkCache);
       child = walker.NextChild();
     }
 
     if (child) {
       document->ContentRemoved(child->Parent(), aChildNode);
 #ifdef A11Y_LOG
       if (logging::IsEnabled(logging::eTree))
         logging::AccessibleNNode("real container", child->Parent());
--- a/accessible/ipc/DocAccessibleChild.cpp
+++ b/accessible/ipc/DocAccessibleChild.cpp
@@ -10,16 +10,17 @@
 #include "ProxyAccessible.h"
 #include "Relation.h"
 #include "HyperTextAccessible-inl.h"
 #include "ImageAccessible.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "nsIPersistentProperties2.h"
 #include "nsISimpleEnumerator.h"
+#include "nsAccUtils.h"
 
 namespace mozilla {
 namespace a11y {
 
 static uint32_t
 InterfacesFor(Accessible* aAcc)
 {
   uint32_t interfaces = 0;
@@ -1425,10 +1426,210 @@ DocAccessibleChild::RecvUnselectAll(cons
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
     *aSuccess = acc->UnselectAll();
   }
 
   return true;
 }
 
+bool
+DocAccessibleChild::RecvDoAction(const uint64_t& aID,
+                                 const uint8_t& aIndex,
+                                 bool* aSuccess)
+{
+  *aSuccess = false;
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    *aSuccess = acc->DoAction(aIndex);
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvActionCount(const uint64_t& aID,
+                                    uint8_t* aCount)
+{
+  *aCount = 0;
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    *aCount = acc->ActionCount();
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvActionDescriptionAt(const uint64_t& aID,
+                                            const uint8_t& aIndex,
+                                            nsString* aDescription)
+{
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    acc->ActionDescriptionAt(aIndex, *aDescription);
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvActionNameAt(const uint64_t& aID,
+                                     const uint8_t& aIndex,
+                                     nsString* aName)
+{
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    acc->ActionNameAt(aIndex, *aName);
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvAccessKey(const uint64_t& aID,
+                                  uint32_t* aKey,
+                                  uint32_t* aModifierMask)
+{
+  *aKey = 0;
+  *aModifierMask = 0;
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    KeyBinding kb = acc->AccessKey();
+    *aKey = kb.Key();
+    *aModifierMask = kb.ModifierMask();
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvKeyboardShortcut(const uint64_t& aID,
+                                         uint32_t* aKey,
+                                         uint32_t* aModifierMask)
+{
+  *aKey = 0;
+  *aModifierMask = 0;
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    KeyBinding kb = acc->KeyboardShortcut();
+    *aKey = kb.Key();
+    *aModifierMask = kb.ModifierMask();
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvCurValue(const uint64_t& aID,
+                                 double* aValue)
+{
+  *aValue = UnspecifiedNaN<double>();
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    *aValue = acc->CurValue();
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvSetCurValue(const uint64_t& aID,
+                                    const double& aValue,
+                                    bool* aRetVal)
+{
+  *aRetVal = false;
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    *aRetVal = acc->SetCurValue(aValue);
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvMinValue(const uint64_t& aID,
+                                 double* aValue)
+{
+  *aValue = UnspecifiedNaN<double>();
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    *aValue = acc->MinValue();
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvMaxValue(const uint64_t& aID,
+                                 double* aValue)
+{
+  *aValue = UnspecifiedNaN<double>();
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    *aValue = acc->MaxValue();
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvStep(const uint64_t& aID,
+                             double* aStep)
+{
+  *aStep = UnspecifiedNaN<double>();
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    *aStep = acc->Step();
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvTakeFocus(const uint64_t& aID)
+{
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    acc->TakeFocus();
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvChildAtPoint(const uint64_t& aID,
+                                     const int32_t& aX,
+                                     const int32_t& aY,
+                                     const uint32_t& aWhich,
+                                     uint64_t* aChild,
+                                     bool* aOk)
+{
+  *aChild = 0;
+  *aOk = false;
+  Accessible* acc = IdToAccessible(aID);
+  if (acc && !acc->IsDefunct() && !nsAccUtils::MustPrune(acc)) {
+    Accessible* child =
+      acc->ChildAtPoint(aX, aY,
+                        static_cast<Accessible::EWhichChildAtPoint>(aWhich));
+    if (child) {
+      *aChild = reinterpret_cast<uint64_t>(child->UniqueID());
+      *aOk = true;
+    }
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvBounds(const uint64_t& aID,
+                               nsIntRect* aRect)
+{
+  Accessible* acc = IdToAccessible(aID);
+  if (acc && !acc->IsDefunct()) {
+    *aRect = acc->Bounds();
+  }
+
+  return false;
+}
+
 }
 }
--- a/accessible/ipc/DocAccessibleChild.h
+++ b/accessible/ipc/DocAccessibleChild.h
@@ -346,16 +346,66 @@ public:
                                            const uint32_t& aIndex,
                                            bool* aSuccess) override;
 
   virtual bool RecvSelectAll(const uint64_t& aID,
                              bool* aSuccess) override;
 
   virtual bool RecvUnselectAll(const uint64_t& aID,
                                bool* aSuccess) override;
+
+  virtual bool RecvDoAction(const uint64_t& aID,
+                            const uint8_t& aIndex,
+                            bool* aSuccess) override;
+
+  virtual bool RecvActionCount(const uint64_t& aID,
+                               uint8_t* aCount) override;
+
+  virtual bool RecvActionDescriptionAt(const uint64_t& aID,
+                                       const uint8_t& aIndex,
+                                       nsString* aDescription) override;
+
+  virtual bool RecvActionNameAt(const uint64_t& aID,
+                                const uint8_t& aIndex,
+                                nsString* aName) override;
+
+  virtual bool RecvAccessKey(const uint64_t& aID,
+                             uint32_t* aKey,
+                             uint32_t* aModifierMask) override;
+
+  virtual bool RecvKeyboardShortcut(const uint64_t& aID,
+                                    uint32_t* aKey,
+                                    uint32_t* aModifierMask) override;
+
+  virtual bool RecvCurValue(const uint64_t& aID,
+                            double* aValue);
+
+  virtual bool RecvSetCurValue(const uint64_t& aID,
+                               const double& aValue,
+                               bool* aRetVal);
+
+  virtual bool RecvMinValue(const uint64_t& aID,
+                            double* aValue);
+
+  virtual bool RecvMaxValue(const uint64_t& aID,
+                            double* aValue);
+
+  virtual bool RecvStep(const uint64_t& aID,
+                        double* aStep);
+
+  virtual bool RecvTakeFocus(const uint64_t& aID) override;
+
+  virtual bool RecvChildAtPoint(const uint64_t& aID,
+                                const int32_t& aX,
+                                const int32_t& aY,
+                                const uint32_t& aWhich,
+                                uint64_t* aChild,
+                                bool* aOk) override;
+
+  virtual bool RecvBounds(const uint64_t& aID, nsIntRect* aRect) override;
 private:
 
   Accessible* IdToAccessible(const uint64_t& aID) const;
   Accessible* IdToAccessibleLink(const uint64_t& aID) const;
   Accessible* IdToAccessibleSelect(const uint64_t& aID) const;
   HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID) const;
   ImageAccessible* IdToImageAccessible(const uint64_t& aID) const;
   TableCellAccessible* IdToTableCellAccessible(const uint64_t& aID) const;
--- a/accessible/ipc/PDocAccessible.ipdl
+++ b/accessible/ipc/PDocAccessible.ipdl
@@ -186,13 +186,30 @@ child:
   prio(high) sync SelectedItems(uint64_t aID) returns(uint64_t[] aSelectedItemIDs);
   prio(high) sync SelectedItemCount(uint64_t aID) returns(uint32_t aCount);
   prio(high) sync GetSelectedItem(uint64_t aID, uint32_t aIndex) returns(uint64_t aSelected, bool aOk);
   prio(high) sync IsItemSelected(uint64_t aID, uint32_t aIndex) returns(bool aSelected);
   prio(high) sync AddItemToSelection(uint64_t aID, uint32_t aIndex) returns(bool aSuccess);
   prio(high) sync RemoveItemFromSelection(uint64_t aID, uint32_t aIndex) returns(bool aSuccess);
   prio(high) sync SelectAll(uint64_t aID) returns(bool aSuccess);
   prio(high) sync UnselectAll(uint64_t aID) returns(bool aSuccess);
-  
+
+  prio(high) sync DoAction(uint64_t aID, uint8_t aIndex) returns(bool aSuccess);
+  prio(high) sync ActionCount(uint64_t aID) returns(uint8_t aCount);
+  prio(high) sync ActionDescriptionAt(uint64_t aID, uint8_t aIndex) returns(nsString aDescription);
+  prio(high) sync ActionNameAt(uint64_t aID, uint8_t aIndex) returns(nsString aName);
+  prio(high) sync AccessKey(uint64_t aID) returns(uint32_t aKey, uint32_t aModifierMask);
+  prio(high) sync KeyboardShortcut(uint64_t aID) returns(uint32_t aKey, uint32_t aModifierMask);
+
+  prio(high) sync CurValue(uint64_t aID) returns(double aValue);
+  prio(high) sync SetCurValue(uint64_t aID, double aValue) returns(bool aRetVal);
+  prio(high) sync MinValue(uint64_t aID) returns(double aValue);
+  prio(high) sync MaxValue(uint64_t aID) returns(double aValue);
+  prio(high) sync Step(uint64_t aID) returns(double aStep);
+
+  prio(high) sync TakeFocus(uint64_t aID);
+  prio(high) sync ChildAtPoint(uint64_t aID, int32_t aX, int32_t aY, uint32_t aWhich)
+    returns(uint64_t aChild, bool aOk);
+  prio(high) sync Bounds(uint64_t aID) returns(nsIntRect aRect);
 };
 
 }
 }
--- a/accessible/ipc/ProxyAccessible.cpp
+++ b/accessible/ipc/ProxyAccessible.cpp
@@ -794,10 +794,122 @@ ProxyAccessible::SelectAll()
 bool
 ProxyAccessible::UnselectAll()
 {
   bool success = false;
   unused << mDoc->SendUnselectAll(mID, &success);
   return success;
 }
 
+bool
+ProxyAccessible::DoAction(uint8_t aIndex)
+{
+  bool success = false;
+  unused << mDoc->SendDoAction(mID, aIndex, &success);
+  return success;
+}
+
+uint8_t
+ProxyAccessible::ActionCount()
+{
+  uint8_t count = 0;
+  unused << mDoc->SendActionCount(mID, &count);
+  return count;
+}
+
+void
+ProxyAccessible::ActionDescriptionAt(uint8_t aIndex, nsString& aDescription)
+{
+  unused << mDoc->SendActionDescriptionAt(mID, aIndex, &aDescription);
+}
+
+void
+ProxyAccessible::ActionNameAt(uint8_t aIndex, nsString& aName)
+{
+  unused << mDoc->SendActionNameAt(mID, aIndex, &aName);
+}
+
+KeyBinding
+ProxyAccessible::AccessKey()
+{
+  uint32_t key = 0;
+  uint32_t modifierMask = 0;
+  unused << mDoc->SendAccessKey(mID, &key, &modifierMask);
+  return KeyBinding(key, modifierMask);
+}
+
+KeyBinding
+ProxyAccessible::KeyboardShortcut()
+{
+  uint32_t key = 0;
+  uint32_t modifierMask = 0;
+  unused << mDoc->SendKeyboardShortcut(mID, &key, &modifierMask);
+  return KeyBinding(key, modifierMask);
+}
+
+double
+ProxyAccessible::CurValue()
+{
+  double val = UnspecifiedNaN<double>();
+  unused << mDoc->SendCurValue(mID, &val);
+  return val;
+}
+
+bool
+ProxyAccessible::SetCurValue(double aValue)
+{
+  bool success = false;
+  unused << mDoc->SendSetCurValue(mID, aValue, &success);
+  return success;
+}
+
+double
+ProxyAccessible::MinValue()
+{
+  double val = UnspecifiedNaN<double>();
+  unused << mDoc->SendMinValue(mID, &val);
+  return val;
+}
+
+double
+ProxyAccessible::MaxValue()
+{
+  double val = UnspecifiedNaN<double>();
+  unused << mDoc->SendMaxValue(mID, &val);
+  return val;
+}
+
+double
+ProxyAccessible::Step()
+{
+  double step = UnspecifiedNaN<double>();
+  unused << mDoc->SendStep(mID, &step);
+  return step;
+}
+
+void
+ProxyAccessible::TakeFocus()
+{
+  unused << mDoc->SendTakeFocus(mID);
+}
+
+ProxyAccessible*
+ProxyAccessible::ChildAtPoint(int32_t aX, int32_t aY,
+                              Accessible::EWhichChildAtPoint aWhichChild)
+{
+  uint64_t childID = 0;
+  bool ok = false;
+  unused << mDoc->SendChildAtPoint(mID, aX, aY,
+                                   static_cast<uint32_t>(aWhichChild),
+                                   &childID, &ok);
+  return ok ? mDoc->GetAccessible(childID) : nullptr;
+}
+
+nsIntRect
+ProxyAccessible::Bounds()
+{
+  nsIntRect rect;
+  unused << mDoc->SendBounds(mID, &rect);
+  return rect;
+}
+
 }
 }
--- a/accessible/ipc/ProxyAccessible.h
+++ b/accessible/ipc/ProxyAccessible.h
@@ -4,19 +4,21 @@
  * 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 "nsIAccessibleText.h"
+#include "Accessible.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsRect.h"
+#include "Accessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class Attribute;
 class DocAccessibleParent;
 enum class RelationType;
 
@@ -251,16 +253,34 @@ public:
   uint32_t SelectedItemCount();
   ProxyAccessible* GetSelectedItem(uint32_t aIndex);
   bool IsItemSelected(uint32_t aIndex);
   bool AddItemToSelection(uint32_t aIndex);
   bool RemoveItemFromSelection(uint32_t aIndex);
   bool SelectAll();
   bool UnselectAll();
 
+  bool DoAction(uint8_t aIndex);
+  uint8_t ActionCount();
+  void ActionDescriptionAt(uint8_t aIndex, nsString& aDescription);
+  void ActionNameAt(uint8_t aIndex, nsString& aName);
+  KeyBinding AccessKey();
+  KeyBinding KeyboardShortcut();
+
+  double CurValue();
+  bool SetCurValue(double aValue);
+  double MinValue();
+  double MaxValue();
+  double Step();
+
+  void TakeFocus();
+  ProxyAccessible* ChildAtPoint(int32_t aX, int32_t aY,
+                                Accessible::EWhichChildAtPoint aWhichChild);
+  nsIntRect Bounds();
+
   /**
    * 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.
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -964,22 +964,17 @@ pref("gecko.handlerService.schemes.ircs.
 
 // By default, we don't want protocol/content handlers to be registered from a different host, see bug 402287
 pref("gecko.handlerService.allowRegisterFromDifferentHost", false);
 
 #ifdef MOZ_SAFE_BROWSING
 pref("browser.safebrowsing.enabled", true);
 pref("browser.safebrowsing.malware.enabled", true);
 pref("browser.safebrowsing.downloads.enabled", true);
-// Remote lookups are only enabled for Windows in Nightly and Aurora
-#if defined(XP_WIN)
 pref("browser.safebrowsing.downloads.remote.enabled", true);
-#else
-pref("browser.safebrowsing.downloads.remote.enabled", false);
-#endif
 pref("browser.safebrowsing.debug", false);
 
 pref("browser.safebrowsing.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
 pref("browser.safebrowsing.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
 pref("browser.safebrowsing.reportURL", "https://safebrowsing.google.com/safebrowsing/report?");
 pref("browser.safebrowsing.reportGenericURL", "http://%LOCALE%.phish-generic.mozilla.com/?hl=%LOCALE%");
 pref("browser.safebrowsing.reportErrorURL", "http://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%");
 pref("browser.safebrowsing.reportPhishURL", "http://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%");
@@ -1010,17 +1005,17 @@ pref("urlclassifier.gethash.timeout_ms",
 // a gethash request will be forced to check that the result is still in
 // the database.
 pref("urlclassifier.max-complete-age", 2700);
 // Tables for application reputation.
 pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
 #ifdef XP_WIN
 // Only download the whitelist on Windows, since the whitelist is
 // only useful for suppressing remote lookups for signed binaries which we can
-// only verify on Windows (Bug 974579).
+// only verify on Windows (Bug 974579). Other platforms always do remote lookups.
 pref("urlclassifier.downloadAllowTable", "goog-downloadwhite-digest256");
 #endif
 #endif
 
 pref("browser.geolocation.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/geolocation/");
 
 pref("browser.EULA.version", 3);
 pref("browser.rights.version", 3);
@@ -1445,16 +1440,19 @@ pref("devtools.performance.ui.flatten-tr
 pref("devtools.performance.ui.show-platform-data", false);
 pref("devtools.performance.ui.show-idle-blocks", true);
 pref("devtools.performance.ui.enable-memory", false);
 pref("devtools.performance.ui.enable-framerate", true);
 
 // The default cache UI setting
 pref("devtools.cache.disabled", false);
 
+// The default service workers UI setting
+pref("devtools.serviceWorkers.testing.enabled", false);
+
 // Enable the Network Monitor
 pref("devtools.netmonitor.enabled", true);
 
 // The default Network Monitor UI settings
 pref("devtools.netmonitor.panes-network-details-width", 550);
 pref("devtools.netmonitor.panes-network-details-height", 450);
 pref("devtools.netmonitor.statistics", true);
 pref("devtools.netmonitor.filters", "[\"all\"]");
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3241,18 +3241,17 @@
                                           documentURIObject: documentURIObject,
                                           docLocation: aMessage.data.docLocation,
                                           charSet: aMessage.data.charSet,
                                           referrer: aMessage.data.referrer,
                                           referrerPolicy: aMessage.data.referrerPolicy,
                                         };
               let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
               let event = gContextMenuContentData.event;
-              let pos = browser.mapScreenCoordinatesFromContent(event.screenX, event.screenY);
-              popup.openPopupAtScreen(pos.x, pos.y, true);
+              popup.openPopupAtScreen(event.screenX, event.screenY, true);
               break;
             }
             case "DOMWebNotificationClicked": {
               let tab = this.getTabForBrowser(browser);
               if (!tab)
                 return;
               this.selectedTab = tab;
               window.focus();
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -45,16 +45,19 @@ support-files =
   file_bug902156_2.html
   file_bug902156_3.html
   file_bug906190_1.html
   file_bug906190_2.html
   file_bug906190_3_4.html
   file_bug906190_redirected.html
   file_bug906190.js
   file_bug906190.sjs
+  file_mixedContentFromOnunload.html
+  file_mixedContentFromOnunload_test1.html
+  file_mixedContentFromOnunload_test2.html
   file_bug970276_popup1.html
   file_bug970276_popup2.html
   file_bug970276_favicon1.ico
   file_bug970276_favicon2.ico
   file_dom_notifications.html
   file_double_close_tab.html
   file_favicon_change.html
   file_favicon_change_not_in_document.html
@@ -278,16 +281,17 @@ skip-if = e10s
 [browser_bug832435.js]
 [browser_bug839103.js]
 [browser_bug880101.js]
 skip-if = e10s # Bug 1126316 - New e10s windows erroneously fire initial about:blank location through nsIWebProgressListener
 [browser_bug882977.js]
 [browser_bug902156.js]
 [browser_bug906190.js]
 skip-if = buildapp == "mulet" || e10s # Bug 1093642 - test manipulates content and relies on content focus
+[browser_mixedContentFromOnunload.js]
 [browser_bug970746.js]
 skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and gets in a mess when in e10s mode
 [browser_bug1015721.js]
 skip-if = os == 'win' || e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
 [browser_bug1064280_changeUrlInPinnedTab.js]
 [browser_bug1070778.js]
 [browser_canonizeURL.js]
 skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
--- a/browser/base/content/test/general/browser_bug435325.js
+++ b/browser/base/content/test/general/browser_bug435325.js
@@ -54,16 +54,17 @@ function checkPage() {
 
   // Re-enable the proxy so example.com is resolved to localhost, rather than
   // the actual example.com.
   Services.prefs.setIntPref("network.proxy.type", proxyPrefValue);
 
   Services.obs.addObserver(function observer(aSubject, aTopic) {
     ok(!Services.io.offline, "After clicking the Try Again button, we're back " +
                              "online.");
+    Services.obs.removeObserver(observer, "network:offline-status-changed", false);
     finish();
   }, "network:offline-status-changed", false);
   gBrowser.contentDocument.getElementById("errorTryAgain").click();
 }
 
 registerCleanupFunction(function() {
   Services.prefs.setBoolPref("browser.cache.disk.enable", true);
   Services.prefs.setBoolPref("browser.cache.memory.enable", true);
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_mixedContentFromOnunload.js
@@ -0,0 +1,107 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Tests for Bug 947079 - Fix bug in nsSecureBrowserUIImpl that sets the wrong
+ * security state on a page because of a subresource load that is not on the
+ * same page.
+ */
+
+// We use different domains for each test and for navigation within each test
+const gHttpTestRoot1 = "http://example.com/browser/browser/base/content/test/general/";
+const gHttpsTestRoot1 = "https://test1.example.com/browser/browser/base/content/test/general/";
+const gHttpTestRoot2 = "http://example.net/browser/browser/base/content/test/general/";
+const gHttpsTestRoot2 = "https://test2.example.com/browser/browser/base/content/test/general/";
+
+let gTestBrowser = null;
+
+function SecStateTestsCompleted() {
+  gBrowser.removeCurrentTab();
+  window.focus();
+  finish();
+}
+
+function test() {
+  waitForExplicitFinish();
+  SpecialPowers.pushPrefEnv({"set": [["security.mixed_content.block_active_content", true],
+                            ["security.mixed_content.block_display_content", false]]}, SecStateTests);
+}
+
+function SecStateTests() {
+  gBrowser.selectedTab = gBrowser.addTab();
+  gTestBrowser = gBrowser.selectedBrowser;
+
+  whenLoaded(gTestBrowser, SecStateTest1A);
+  let url = gHttpTestRoot1 + "file_mixedContentFromOnunload.html";
+  gTestBrowser.contentWindow.location = url;
+}
+
+// Navigation from an http page to a https page with no mixed content
+// The http page loads an http image on unload
+function SecStateTest1A() {
+  whenLoaded(gTestBrowser, SecStateTest1B);
+  let url = gHttpsTestRoot1 + "file_mixedContentFromOnunload_test1.html";
+  gTestBrowser.contentWindow.location = url;
+}
+
+function SecStateTest1B() {
+  // check security state.  Since current url is https and doesn't have any
+  // mixed content resources, we expect it to be secure.
+  isSecurityState("secure");
+
+  whenLoaded(gTestBrowser, SecStateTest2A);
+
+  // change locations and proceed with the second test
+  let url = gHttpTestRoot2 + "file_mixedContentFromOnunload.html";
+  gTestBrowser.contentWindow.location = url;
+}
+
+// Navigation from an http page to a https page that has mixed display content
+// The http page loads an http image on unload
+function SecStateTest2A() {
+  whenLoaded(gTestBrowser, SecStateTest2B);
+  let url = gHttpsTestRoot2 + "file_mixedContentFromOnunload_test2.html";
+  gTestBrowser.contentWindow.location = url;
+}
+
+function SecStateTest2B() {
+  isSecurityState("broken");
+
+  SecStateTestsCompleted();
+}
+
+// Compares the security state of the page with what is expected
+function isSecurityState(expectedState) {
+  let ui = gTestBrowser.securityUI;
+  if (!ui) {
+    ok(false, "No security UI to get the security state");
+    return;
+  }
+
+  const wpl = Components.interfaces.nsIWebProgressListener;
+
+  // determine the security state
+  let isSecure = ui.state & wpl.STATE_IS_SECURE;
+  let isBroken = ui.state & wpl.STATE_IS_BROKEN;
+  let isInsecure = ui.state & wpl.STATE_IS_INSECURE;
+
+  let actualState;
+  if (isSecure && !(isBroken || isInsecure)) {
+    actualState = "secure";
+  } else if (isBroken && !(isSecure || isInsecure)) {
+    actualState = "broken";
+  } else if (isInsecure && !(isSecure || isBroken)) {
+    actualState = "insecure";
+  } else {
+    actualState = "unknown";
+  }
+
+  is(expectedState, actualState, "Expected state " + expectedState + " and the actual state is " + actualState + ".");
+}
+
+function whenLoaded(aElement, aCallback) {
+  aElement.addEventListener("load", function onLoad() {
+    aElement.removeEventListener("load", onLoad, true);
+    executeSoon(aCallback);
+  }, true);
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/file_mixedContentFromOnunload.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test for https://bugzilla.mozilla.org/show_bug.cgi?id=947079
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 947079</title>
+</head>
+<body>
+  <p>Test for Bug 947079</p>
+  <script>
+    window.addEventListener('unload', function() {
+        new Image().src = 'http://mochi.test:8888/tests/image/test/mochitest/blue.png';
+    });
+  </script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/file_mixedContentFromOnunload_test1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test 1 for https://bugzilla.mozilla.org/show_bug.cgi?id=947079
+Page with no insecure subresources
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test 1 for Bug 947079</title>
+</head>
+<body>
+  <p>There are no insecure resource loads on this page</p>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/file_mixedContentFromOnunload_test2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test 2 for https://bugzilla.mozilla.org/show_bug.cgi?id=947079
+Page with an insecure image load
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test 2 for Bug 947079</title>
+</head>
+<body>
+  <p>Page with http image load</p>
+  <img src="http://test2.example.com/tests/image/test/mochitest/blue.png">
+</body>
+</html>
--- a/browser/components/preferences/applications.js
+++ b/browser/components/preferences/applications.js
@@ -8,16 +8,17 @@
 //****************************************************************************//
 // Constants & Enumeration Values
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cr = Components.results;
 
 Components.utils.import('resource://gre/modules/Services.jsm');
+Components.utils.import('resource://gre/modules/AppConstants.jsm');
 
 const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
 const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
 const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
 const TYPE_PDF = "application/pdf";
 
 const PREF_PDFJS_DISABLED = "pdfjs.disabled";
 const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged";
@@ -68,27 +69,19 @@ const PREF_AUDIO_FEED_SELECTED_ACTION = 
 const PREF_AUDIO_FEED_SELECTED_READER = "browser.audioFeeds.handler.default";
 
 // The nsHandlerInfoAction enumeration values in nsIHandlerInfo identify
 // the actions the application can take with content of various types.
 // But since nsIHandlerInfo doesn't support plugins, there's no value
 // identifying the "use plugin" action, so we use this constant instead.
 const kActionUsePlugin = 5;
 
-/*
-#ifdef MOZ_WIDGET_GTK
-*/
-const ICON_URL_APP      = "moz-icon://dummy.exe?size=16";
-/*
-#else
-*/
-const ICON_URL_APP      = "chrome://browser/skin/preferences/application.png";
-/*
-#endif
-*/
+const ICON_URL_APP = AppConstants.platform == "linux" ?
+                     "moz-icon://dummy.exe?size=16" :
+                     "chrome://browser/skin/preferences/application.png";
 
 // For CSS. Can be one of "ask", "save", "plugin" or "feed". If absent, the icon URL
 // was set by us to a custom handler icon and CSS should not try to override it.
 const APP_ICON_ATTR_NAME = "appHandlerIcon";
 
 //****************************************************************************//
 // Utilities
 
--- a/browser/components/preferences/in-content/applications.js
+++ b/browser/components/preferences/in-content/applications.js
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 //****************************************************************************//
 // Constants & Enumeration Values
 
 Components.utils.import('resource://gre/modules/Services.jsm');
+Components.utils.import('resource://gre/modules/AppConstants.jsm');
 const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
 const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
 const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
 const TYPE_PDF = "application/pdf";
 
 const PREF_PDFJS_DISABLED = "pdfjs.disabled";
 const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged";
 
@@ -62,27 +63,19 @@ const PREF_AUDIO_FEED_SELECTED_ACTION = 
 const PREF_AUDIO_FEED_SELECTED_READER = "browser.audioFeeds.handler.default";
 
 // The nsHandlerInfoAction enumeration values in nsIHandlerInfo identify
 // the actions the application can take with content of various types.
 // But since nsIHandlerInfo doesn't support plugins, there's no value
 // identifying the "use plugin" action, so we use this constant instead.
 const kActionUsePlugin = 5;
 
-/*
-#if MOZ_WIDGET_GTK == 2
-*/
-const ICON_URL_APP      = "moz-icon://dummy.exe?size=16";
-/*
-#else
-*/
-const ICON_URL_APP      = "chrome://browser/skin/preferences/application.png";
-/*
-#endif
-*/
+const ICON_URL_APP = AppConstants.platform == "linux" ?
+                     "moz-icon://dummy.exe?size=16" :
+                     "chrome://browser/skin/preferences/application.png";
 
 // For CSS. Can be one of "ask", "save", "plugin" or "feed". If absent, the icon URL
 // was set by us to a custom handler icon and CSS should not try to override it.
 const APP_ICON_ATTR_NAME = "appHandlerIcon";
 
 //****************************************************************************//
 // Utilities
 
--- a/browser/components/preferences/in-content/sync.js
+++ b/browser/components/preferences/in-content/sync.js
@@ -90,17 +90,19 @@ let gSyncPane = {
   },
 
   _init: function () {
     let topics = ["weave:service:login:error",
                   "weave:service:login:finish",
                   "weave:service:start-over:finish",
                   "weave:service:setup-complete",
                   "weave:service:logout:finish",
-                  FxAccountsCommon.ONVERIFIED_NOTIFICATION];
+                  FxAccountsCommon.ONVERIFIED_NOTIFICATION,
+                  FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION,
+                  ];
     let migrateTopic = "fxa-migration:state-changed";
 
     // Add the observers now and remove them on unload
     //XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
     //        of `this`. Fix in a followup. (bug 583347)
     topics.forEach(function (topic) {
       Weave.Svc.Obs.add(topic, this.updateWeavePrefs, this);
     }, this);
@@ -118,16 +120,18 @@ let gSyncPane = {
       return Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");
     }),
 
     XPCOMUtils.defineLazyGetter(this, '_accountsStringBundle', () => {
       return Services.strings.createBundle("chrome://browser/locale/accounts.properties");
     }),
 
     this.updateWeavePrefs();
+
+    this._initProfileImageUI();
   },
 
   _setupEventListeners: function() {
     function setEventListener(aId, aEventType, aCallback)
     {
       document.getElementById(aId)
               .addEventListener(aEventType, aCallback.bind(gSyncPane));
     }
@@ -219,16 +223,24 @@ let gSyncPane = {
       fxaMigrator.forgetFxAccount();
     });
     setEventListener("sync-migrate-resend", "click", function () {
       let win = Services.wm.getMostRecentWindow("navigator:browser");
       fxaMigrator.resendVerificationMail(win);
     });
   },
 
+  _initProfileImageUI: function () {
+    try {
+      if (Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled")) {
+        document.getElementById("fxaProfileImage").hidden = false;
+      }
+    } catch (e) { }
+  },
+
   updateWeavePrefs: function () {
     // ask the migration module to broadcast its current state (and nothing will
     // happen if it's not loaded - which is good, as that means no migration
     // is pending/necessary) - we don't want to suck that module in just to
     // find there's nothing to do.
     Services.obs.notifyObservers(null, "fxa-migration:state-request", null);
 
     let service = Components.classes["@mozilla.org/weave/service;1"]
@@ -239,20 +251,21 @@ let gSyncPane = {
     if (service.fxAccountsEnabled) {
       // unhide the reading-list engine if readinglist is enabled (note we do
       // it here as it must remain disabled for legacy sync users)
       if (Services.prefs.getBoolPref("browser.readinglist.enabled")) {
         document.getElementById("readinglist-engine").removeAttribute("hidden");
       }
       // determine the fxa status...
       this.page = PAGE_PLEASE_WAIT;
+
       fxAccounts.getSignedInUser().then(data => {
         if (!data) {
           this.page = FXA_PAGE_LOGGED_OUT;
-          return;
+          return false;
         }
         this.page = FXA_PAGE_LOGGED_IN;
         // We are logged in locally, but maybe we are in a state where the
         // server rejected our credentials (eg, password changed on the server)
         let fxaLoginStatus = document.getElementById("fxaLoginStatus");
         let enginesListDisabled;
         // Not Verfied implies login error state, so check that first.
         if (!data.verified) {
@@ -276,17 +289,46 @@ let gSyncPane = {
         document.getElementById("fxaEmailAddress1").textContent = data.email;
         document.getElementById("fxaEmailAddress2").textContent = data.email;
         document.getElementById("fxaEmailAddress3").textContent = data.email;
         document.getElementById("fxaSyncComputerName").value = Weave.Service.clientsEngine.localName;
         let engines = document.getElementById("fxaSyncEngines")
         for (let checkbox of engines.querySelectorAll("checkbox")) {
           checkbox.disabled = enginesListDisabled;
         }
+
+        // Clear the profile image (if any) of the previously logged in account.
+        document.getElementById("fxaProfileImage").style.removeProperty("background-image");
+
+        // If the account is verified the next promise in the chain will
+        // fetch profile data.
+        return data.verified;
+      }).then(shouldGetProfile => {
+        if (shouldGetProfile) {
+          return fxAccounts.getSignedInUserProfile();
+        }
+      }).then(data => {
+        if (data && data.avatar) {
+          // Make sure the image is available before displaying it,
+          // as we don't want to overwrite the default profile image
+          // with a broken/unavailable image
+          let img = new Image();
+          img.onload = () => {
+            let bgImage = "url('" + data.avatar + "')";
+            document.getElementById("fxaProfileImage").style.backgroundImage = bgImage;
+          };
+          img.src = data.avatar;
+        }
+      }, err => {
+        FxAccountsCommon.log.error(err);
+      }).catch(err => {
+        // If we get here something's really busted
+        Cu.reportError(String(err));
       });
+
     // If fxAccountEnabled is false and we are in a "not configured" state,
     // then fxAccounts is probably fully disabled rather than just unconfigured,
     // so handle this case.  This block can be removed once we remove support
     // for fxAccounts being disabled.
     } else if (Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED ||
                Weave.Svc.Prefs.get("firstSync", "") == "notReady") {
       this.page = PAGE_NO_ACCOUNT;
     // else: sync was previously configured for the legacy provider, so we
@@ -516,16 +558,25 @@ let gSyncPane = {
   },
 
   reSignIn: function() {
     this.openContentInBrowser("about:accounts?action=reauth&entrypoint=preferences", {
       replaceQueryString: true
     });
   },
 
+  openChangeProfileImage: function() {
+    fxAccounts.promiseAccountsChangeProfileURI("avatar")
+      .then(url => {
+        this.openContentInBrowser(url, {
+          replaceQueryString: true
+        });
+      });
+  },
+
   manageFirefoxAccount: function() {
     let url = Services.prefs.getCharPref("identity.fxaccounts.settings.uri");
     this.openContentInBrowser(url);
   },
 
   verifyFirefoxAccount: function() {
     fxAccounts.resendVerificationEmail().then(() => {
       fxAccounts.getSignedInUser().then(data => {
--- a/browser/components/preferences/in-content/sync.xul
+++ b/browser/components/preferences/in-content/sync.xul
@@ -228,17 +228,21 @@
     <groupbox id="fxaGroup">
       <caption><label>&syncBrand.fxAccount.label;</label></caption>
 
       <deck id="fxaLoginStatus">
 
         <!-- logged in and verified and all is good -->
         <hbox id="fxaLoginVerified"
               align="center">
-          <label id="fxaEmailAddress1"/>
+          <hbox align="center">
+            <image id="fxaProfileImage"
+              onclick="gSyncPane.openChangeProfileImage();" hidden="true"/>
+            <label id="fxaEmailAddress1"/>
+          </hbox>
           <spacer flex="1"/>
           <button id="verifiedManage"
                   label="&manage.label;"/>
           <button id="fxaUnlinkButton"
                   label="&disconnect.label;"/>
         </hbox>
 
         <!-- logged in to an unverified account -->
--- a/browser/devtools/framework/test/browser.ini
+++ b/browser/devtools/framework/test/browser.ini
@@ -3,16 +3,18 @@ subsuite = devtools
 support-files =
   browser_toolbox_options_disable_js.html
   browser_toolbox_options_disable_js_iframe.html
   browser_toolbox_options_disable_cache.sjs
   browser_toolbox_sidebar_tool.xul
   head.js
   helper_disable_cache.js
   doc_theme.css
+  browser_toolbox_options_enable_serviceworkers_testing.html
+  serviceworker.js
 
 [browser_devtools_api.js]
 [browser_devtools_api_destroy.js]
 [browser_dynamic_tool_enabling.js]
 [browser_keybindings.js]
 [browser_new_activation_workflow.js]
 [browser_target_events.js]
 [browser_target_remote.js]
@@ -46,12 +48,14 @@ skip-if = e10s # Bug 1069044 - destroyIn
 [browser_toolbox_transport_events.js]
 [browser_toolbox_window_reload_target.js]
 [browser_toolbox_window_shortcuts.js]
 skip-if = os == "mac" && os_version == "10.8" || os == "win" && os_version == "5.1" # Bug 851129 - Re-enable browser_toolbox_window_shortcuts.js test after leaks are fixed
 [browser_toolbox_window_title_changes.js]
 [browser_toolbox_zoom.js]
 [browser_toolbox_custom_host.js]
 [browser_toolbox_theme_registration.js]
+[browser_toolbox_options_enable_serviceworkers_testing.js]
+skip-if = e10s # Bug 1030318
 
 # We want this test to run for mochitest-dt as well, so we include it here:
 [../../../base/content/test/general/browser_parsable_css.js]
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_toolbox_options_enable_serviceworkers_testing.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>browser_toolbox_options_enable_serviceworkers_testing.html</title>
+    <meta charset="UTF-8">
+    <style>
+      div {
+        width: 260px;
+        height: 24px;
+        border: 1px solid #000;
+        margin-top: 10px;
+      }
+
+      h1 {
+        font-size: 20px
+      }
+    </style>
+    <script type="application/javascript;version=1.8">
+      function log(msg) {
+        var output = document.getElementById("output");
+
+        output.innerHTML = msg;
+      }
+
+      navigator.serviceWorker.register("serviceworker.js").then(
+        swr => {
+          var msg = "";
+          var button = document.getElementById("button");
+          if (swr.installing) {
+            msg += "Installing worker/";
+          }
+          if (swr.waiting) {
+            msg += "Waiting worker/";
+          }
+          if (swr.active) {
+            msg += "Active worker/";
+          }
+          log(msg);
+          button.click();
+        },
+        error => {
+          var button = document.getElementById("button");
+          if (error.name === "SecurityError") {
+            log("SecurityError");
+          }
+          button.click();
+      });
+    </script>
+  </head>
+  <body>
+    <h1>Test in page</h1>
+    <input id="button"
+           type="button"
+           value="Worker clicks here"/>
+    <br>
+    <div id="output">No output</div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_toolbox_options_enable_serviceworkers_testing.js
@@ -0,0 +1,124 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that enabling Service Workers testing option enables the
+// mServiceWorkersTestingEnabled attribute added to nsPIDOMWindow.
+
+const TEST_URI = URL_ROOT +
+                 "browser_toolbox_options_enable_serviceworkers_testing.html";
+
+const ELEMENT_ID = "devtools-enable-serviceWorkersTesting";
+
+let toolbox;
+let doc;
+
+function test() {
+  // Note: Pref dom.serviceWorkers.testing.enabled is false since we are testing
+  // the same capabilities are enabled with the devtool pref.
+  SpecialPowers.pushPrefEnv({"set": [
+    ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+    ["dom.serviceWorkers.enabled", true],
+    ["dom.serviceWorkers.testing.enabled", false]
+  ]}, start);
+}
+
+function start() {
+  gBrowser.selectedTab = gBrowser.addTab();
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    doc = content.document;
+    gDevTools.showToolbox(target).then(testSelectTool);
+  }, true);
+
+  content.location = TEST_URI;
+}
+
+function testSelectTool(aToolbox) {
+  toolbox = aToolbox;
+  toolbox.once("options-selected", testRegisterFails);
+  toolbox.selectTool("options");
+}
+
+function testRegisterFails() {
+  let output = doc.getElementById("output");
+  let button = doc.getElementById("button");
+
+  function doTheCheck() {
+    info("Testing it doesn't registers correctly until enable testing");
+    is(output.textContent,
+       "SecurityError",
+       "SecurityError expected");
+    testRegisterInstallingWorker();
+  }
+
+  if (output.textContent !== "No output") {
+    doTheCheck();
+  }
+
+  button.addEventListener('click', function onClick() {
+    button.removeEventListener('click', onClick);
+    doTheCheck();
+  });
+}
+
+function testRegisterInstallingWorker() {
+  toggleServiceWorkersTestingCheckbox().then(() => {
+    let output = doc.getElementById("output");
+    let button = doc.getElementById("button");
+
+    function doTheCheck() {
+      info("Testing it registers correctly and there is an installing worker");
+      is(output.textContent,
+         "Installing worker/",
+         "Installing worker expected");
+      toggleServiceWorkersTestingCheckbox().then(finishUp);
+    }
+
+    if (output.textContent !== "No output") {
+      doTheCheck();
+    }
+
+    button.addEventListener('click', function onClick() {
+      button.removeEventListener('click', onClick);
+      doTheCheck();
+    });
+  });
+}
+
+function toggleServiceWorkersTestingCheckbox() {
+  let deferred = promise.defer();
+
+  let panel = toolbox.getCurrentPanel();
+  let cbx = panel.panelDoc.getElementById(ELEMENT_ID);
+
+  cbx.scrollIntoView();
+
+  if (cbx.checked) {
+    info("Clearing checkbox to disable service workers testing");
+  } else {
+    info("Checking checkbox to enable service workers testing");
+  }
+
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    doc = content.document;
+    deferred.resolve();
+  }, true);
+
+  cbx.click();
+
+  let mm = getFrameScript();
+  mm.sendAsyncMessage("devtools:test:reload");
+
+  return deferred.promise;
+}
+
+function finishUp() {
+  toolbox.destroy().then(function() {
+    gBrowser.removeCurrentTab();
+    toolbox = doc = null;
+    finish();
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/serviceworker.js
@@ -0,0 +1,1 @@
+// empty service worker, always succeed!
--- a/browser/devtools/framework/toolbox-options.js
+++ b/browser/devtools/framework/toolbox-options.js
@@ -312,17 +312,17 @@ OptionsPanel.prototype = {
       menulist.addEventListener("command", function() {
         setPrefAndEmit(this.getAttribute("data-pref"), this.value);
       }.bind(menulist));
     }
 
     if (this.target.activeTab) {
       this.target.client.attachTab(this.target.activeTab._actor, (response) => {
         this._origJavascriptEnabled = response.javascriptEnabled;
-        this.disableJSNode.checked = !this._origJavascriptEnabled
+        this.disableJSNode.checked = !this._origJavascriptEnabled;
         this.disableJSNode.addEventListener("click", this._disableJSClicked, false);
       });
     } else {
       this.disableJSNode.hidden = true;
     }
   },
 
   updateDefaultTheme: function() {
--- a/browser/devtools/framework/toolbox-options.xul
+++ b/browser/devtools/framework/toolbox-options.xul
@@ -140,16 +140,20 @@
         <vbox id="context-options" class="options-groupbox">
           <checkbox id="devtools-disable-cache"
                     label="&options.disableCache.label2;"
                     tooltiptext="&options.disableCache.tooltip2;"
                     data-pref="devtools.cache.disabled"/>
           <checkbox id="devtools-disable-javascript"
                     label="&options.disableJavaScript.label;"
                     tooltiptext="&options.disableJavaScript.tooltip;"/>
+          <checkbox id="devtools-enable-serviceWorkersTesting"
+                    label="&options.enableServiceWorkersTesting.label;"
+                    tooltiptext="&options.enableServiceWorkersTesting.tooltip;"
+                    data-pref="devtools.serviceWorkers.testing.enabled"/>
           <hbox class="hidden-labels-box">
             <checkbox label="&options.enableChrome.label5;"
                       tooltiptext="&options.enableChrome.tooltip3;"
                       data-pref="devtools.chrome.enabled"/>
           </hbox>
           <hbox class="hidden-labels-box">
             <checkbox label="&options.enableRemote.label3;"
                       tooltiptext="&options.enableRemote.tooltip;"
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -327,16 +327,17 @@ Toolbox.prototype = {
 
         let framesMenu = this.doc.getElementById("command-button-frames");
         framesMenu.addEventListener("command", this.selectFrame, true);
 
         this._buildDockButtons();
         this._buildOptions();
         this._buildTabs();
         this._applyCacheSettings();
+        this._applyServiceWorkersTestingSettings();
         this._addKeysToWindow();
         this._addReloadKeys();
         this._addHostListeners();
         if (this._hostOptions && this._hostOptions.zoom === false) {
           this._disableZoomKeys();
         } else {
           this._addZoomKeys();
           this._loadInitialZoom();
@@ -402,18 +403,23 @@ Toolbox.prototype = {
    * @param  {Object} data
    *         {
    *           newValue: The new value
    *           oldValue:  The old value
    *           pref: The name of the preference that has changed
    *         }
    */
   _prefChanged: function(event, data) {
-    if (data.pref === "devtools.cache.disabled") {
+    switch(data.pref) {
+    case "devtools.cache.disabled":
       this._applyCacheSettings();
+      break;
+    case "devtools.serviceWorkers.testing.enabled":
+      this._applyServiceWorkersTestingSettings();
+      break;
     }
   },
 
   _buildOptions: function() {
     let key = this.doc.getElementById("toolbox-options-key");
     key.addEventListener("command", () => {
       this.selectTool("options");
     }, true);
@@ -743,16 +749,32 @@ Toolbox.prototype = {
     let cacheDisabled = Services.prefs.getBoolPref(pref);
 
     if (this.target.activeTab) {
       this.target.activeTab.reconfigure({"cacheDisabled": cacheDisabled});
     }
   },
 
   /**
+   * Apply the current service workers testing setting from
+   * devtools.serviceWorkers.testing.enabled to this toolbox's tab.
+   */
+  _applyServiceWorkersTestingSettings: function() {
+    let pref = "devtools.serviceWorkers.testing.enabled";
+    let serviceWorkersTestingEnabled =
+      Services.prefs.getBoolPref(pref) || false;
+
+    if (this.target.activeTab) {
+      this.target.activeTab.reconfigure({
+        "serviceWorkersTestingEnabled": serviceWorkersTestingEnabled
+      });
+    }
+  },
+
+  /**
    * Setter for the checked state of the picker button in the toolbar
    * @param {Boolean} isChecked
    */
   set pickerButtonChecked(isChecked) {
     if (isChecked) {
       this._pickerButton.setAttribute("checked", "true");
     } else {
       this._pickerButton.removeAttribute("checked");
@@ -1689,20 +1711,23 @@ Toolbox.prototype = {
 
         outstanding.push(panel.destroy());
       } catch (e) {
         // We don't want to stop here if any panel fail to close.
         console.error("Panel " + id + ":", e);
       }
     }
 
-    // Now that we are closing the toolbox we can re-enable JavaScript for the
-    // current tab.
+    // Now that we are closing the toolbox we can re-enable the cache settings
+    // and disable the service workers testing settings for the current tab.
     if (this.target.activeTab) {
-      this.target.activeTab.reconfigure({"cacheDisabled": false});
+      this.target.activeTab.reconfigure({
+        "cacheDisabled": false,
+        "serviceWorkersTestingEnabled": false
+      });
     }
 
     // Destroying the walker and inspector fronts
     outstanding.push(this.destroyInspector().then(() => {
       // Removing buttons
       if (this._pickerButton) {
         this._pickerButton.removeEventListener("command", this._togglePicker, false);
         this._pickerButton = null;
--- a/browser/devtools/profiler/test/browser_profiler_shared-connection-01.js
+++ b/browser/devtools/profiler/test/browser_profiler_shared-connection-01.js
@@ -8,36 +8,47 @@
 let gProfilerConnections = 0;
 Services.obs.addObserver(profilerConnectionObserver, "profiler-connection-created", false);
 
 let test = Task.async(function*() {
   let firstTab = yield addTab(SIMPLE_URL);
   let firstTarget = TargetFactory.forTab(firstTab);
   yield firstTarget.makeRemote();
 
-  yield gDevTools.showToolbox(firstTarget, "webconsole");
+  let toolboxFirstTab;
+  yield gDevTools.showToolbox(firstTarget, "webconsole").then((aToolbox) => {
+    toolboxFirstTab = aToolbox;
+  });
+
   is(gProfilerConnections, 1,
     "A shared profiler connection should have been created.");
 
   yield gDevTools.showToolbox(firstTarget, "jsprofiler");
   is(gProfilerConnections, 1,
     "No new profiler connections should have been created.");
 
   let secondTab = yield addTab(SIMPLE_URL);
   let secondTarget = TargetFactory.forTab(secondTab);
   yield secondTarget.makeRemote();
 
-  yield gDevTools.showToolbox(secondTarget, "jsprofiler");
+  let toolboxSecondTab;
+  yield gDevTools.showToolbox(secondTarget, "jsprofiler").then((aToolbox) => {
+    toolboxSecondTab = aToolbox;
+  });
+
   is(gProfilerConnections, 2,
     "Only one new profiler connection should have been created.");
 
-  yield removeTab(firstTab);
-  yield removeTab(secondTab);
-
-  finish();
+  yield toolboxFirstTab.destroy().then(() => {
+    removeTab(firstTab);
+  });
+  yield toolboxSecondTab.destroy().then(() => {
+    removeTab(secondTab);
+    finish();
+  });
 });
 
 function profilerConnectionObserver(subject, topic, data) {
   is(topic, "profiler-connection-created", "The correct topic was observed.");
   gProfilerConnections++;
 }
 
 registerCleanupFunction(() => {
--- a/browser/locales/en-US/chrome/browser/devtools/toolbox.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/toolbox.dtd
@@ -92,16 +92,22 @@
 <!ENTITY options.disableJavaScript.tooltip   "Turning this option on will disable JavaScript for the current tab. If the tab or the toolbox is closed then this setting will be forgotten.">
 
 <!-- LOCALIZATION NOTE (options.disableCache.label2,
   -  options.disableCache.tooltip2): This is the options panel label and
   -  tooltip for the checkbox that toggles the cache on or off. -->
 <!ENTITY options.disableCache.label2     "Disable Cache (when toolbox is open)">
 <!ENTITY options.disableCache.tooltip2   "Turning this option on will disable the cache for all tabs that have the toolbox open.">
 
+<!-- LOCALIZATION NOTE (options.enableServiceWorkersTesting.label,
+  -  options.enableServiceWorkersTesting.tooltip): This is the options panel label and
+  -  tooltip for the checkbox that toggles the service workers testing features on or off. -->
+<!ENTITY options.enableServiceWorkersTesting.label     "Enable Service Workers testing features (when toolbox is open)">
+<!ENTITY options.enableServiceWorkersTesting.tooltip   "Turning this option on will enable the service workers testing features for all tabs that have the toolbox open.">
+
 <!-- LOCALIZATION NOTE (options.selectDefaultTools.label): This is the label for
   -  the heading of group of checkboxes corresponding to the default developer
   -  tools. -->
 <!ENTITY options.selectDefaultTools.label     "Default Firefox Developer Tools">
 
 <!-- LOCALIZATION NOTE (options.selectAdditionalTools.label): This is the label for
   -  the heading of group of checkboxes corresponding to the developer tools
   -  added by add-ons. This heading is hidden when there is no developer tool
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -174,16 +174,17 @@ browser.jar:
   skin/classic/browser/preferences/Options-sync.png   (preferences/Options-sync.png)
 #endif
 * skin/classic/browser/preferences/preferences.css    (preferences/preferences.css)
 * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
 * skin/classic/browser/preferences/in-content/dialog.css      (preferences/in-content/dialog.css)
   skin/classic/browser/preferences/in-content/favicon.ico     (../shared/incontentprefs/favicon.ico)
   skin/classic/browser/preferences/in-content/icons.svg       (../shared/incontentprefs/icons.svg)
   skin/classic/browser/preferences/in-content/search.css      (../shared/incontentprefs/search.css)
+  skin/classic/browser/preferences/in-content/default-profile-image.svg   (../shared/incontentprefs/default-profile-image.svg)
   skin/classic/browser/preferences/applications.css   (preferences/applications.css)
   skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
   skin/classic/browser/preferences/search.css         (preferences/search.css)
   skin/classic/browser/social/services-16.png         (social/services-16.png)
   skin/classic/browser/social/services-64.png         (social/services-64.png)
   skin/classic/browser/social/share-button.png        (social/share-button.png)
   skin/classic/browser/social/share-button-active.png (social/share-button-active.png)
   skin/classic/browser/social/chat-icons.svg          (../shared/social/chat-icons.svg)
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -279,16 +279,17 @@ browser.jar:
 #endif
   skin/classic/browser/preferences/saveFile.png             (preferences/saveFile.png)
 * skin/classic/browser/preferences/preferences.css          (preferences/preferences.css)
 * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
 * skin/classic/browser/preferences/in-content/dialog.css      (preferences/in-content/dialog.css)
   skin/classic/browser/preferences/in-content/favicon.ico     (../shared/incontentprefs/favicon.ico)
   skin/classic/browser/preferences/in-content/icons.svg       (../shared/incontentprefs/icons.svg)
   skin/classic/browser/preferences/in-content/search.css      (../shared/incontentprefs/search.css)
+  skin/classic/browser/preferences/in-content/default-profile-image.svg   (../shared/incontentprefs/default-profile-image.svg)
   skin/classic/browser/preferences/applications.css         (preferences/applications.css)
   skin/classic/browser/preferences/aboutPermissions.css     (preferences/aboutPermissions.css)
   skin/classic/browser/preferences/search.css               (preferences/search.css)
   skin/classic/browser/preferences/checkbox.png             (preferences/checkbox.png)
   skin/classic/browser/preferences/checkbox@2x.png          (preferences/checkbox@2x.png)
   skin/classic/browser/yosemite/preferences/checkbox.png    (preferences/checkbox-yosemite.png)
   skin/classic/browser/yosemite/preferences/checkbox@2x.png (preferences/checkbox-yosemite@2x.png)
   skin/classic/browser/social/services-16.png               (social/services-16.png)
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/incontentprefs/default-profile-image.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
+<path fill="#C3CFD8" d="M500-0.3c276.1,0,500,223.9,500,500s-223.9,500-500,500S0,775.8,0,499.7C0,223.5,223.9-0.3,500-0.3z"/>
+<circle fill="#FFFFFF" cx="500" cy="317" r="139.1"/>
+<path fill="#FFFFFF" d="M751.8,643.6L751.8,643.6c0.1-2.3,0.2-4.6,0.2-6.9c0-68-55.3-127-136.2-156.3L505.9,590.4h0
+	c-0.4,29.8-1.4,58.8-2.8,86.6c-1,0.1-2,0.3-3.1,0.3s-2-0.2-3.1-0.3c-1.4-27.9-2.4-56.9-2.8-86.7h0L384.3,480.4
+	C303.3,509.7,248,568.7,248,636.7c0,2.3,0.1,4.6,0.2,6.9l7.4,49.7c57.1,72,145.4,118.2,244.4,118.2c99,0,187.3-46.2,244.4-118.2
+	L751.8,643.6z"/>
+</svg>
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -211,16 +211,32 @@ treecol {
 }
 
 /* XXX This style is for bug 740213 and should be removed once that
    bug has a solution. */
 description > html|a {
   cursor: pointer;
 }
 
+#fxaProfileImage {
+  width: 60px;
+  height: 60px;
+  border-radius: 50%;
+  border-width: 5px;
+  border-color: red;
+  background-image: url(chrome://browser/skin/preferences/in-content/default-profile-image.svg);
+  background-size: contain;
+  cursor: pointer;
+  -moz-margin-end: 15px;
+}
+
+#fxaProfileImage:hover {
+  border-color: blue;
+}
+
 #noFxaAccount {
   /* Overriding the margins from the base preferences.css theme file.
      These overrides can be simplified by fixing bug 1027174 */
   margin: 0;
 }
 
 #weavePrefsDeck > vbox > label,
 #weavePrefsDeck > vbox > groupbox,
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -202,16 +202,17 @@ browser.jar:
 #endif
         skin/classic/browser/preferences/saveFile.png                (preferences/saveFile.png)
 *       skin/classic/browser/preferences/preferences.css             (preferences/preferences.css)
 *       skin/classic/browser/preferences/in-content/preferences.css  (preferences/in-content/preferences.css)
 *       skin/classic/browser/preferences/in-content/dialog.css       (preferences/in-content/dialog.css)
         skin/classic/browser/preferences/in-content/favicon.ico      (../shared/incontentprefs/favicon.ico)
         skin/classic/browser/preferences/in-content/icons.svg        (../shared/incontentprefs/icons.svg)
         skin/classic/browser/preferences/in-content/search.css       (../shared/incontentprefs/search.css)
+        skin/classic/browser/preferences/in-content/default-profile-image.svg   (../shared/incontentprefs/default-profile-image.svg)
         skin/classic/browser/preferences/applications.css            (preferences/applications.css)
         skin/classic/browser/preferences/aboutPermissions.css        (preferences/aboutPermissions.css)
         skin/classic/browser/preferences/search.css                  (preferences/search.css)
         skin/classic/browser/preferences/checkbox.png                (preferences/checkbox-xp.png)
         skin/classic/browser/preferences/checkbox-classic.png        (preferences/checkbox-classic.png)
         skin/classic/browser/social/services-16.png                  (social/services-16.png)
         skin/classic/browser/social/services-64.png                  (social/services-64.png)
         skin/classic/browser/social/chat-icons.svg                   (../shared/social/chat-icons.svg)
--- a/config/external/nss/Makefile.in
+++ b/config/external/nss/Makefile.in
@@ -125,16 +125,17 @@ DEFAULT_GMAKE_FLAGS += NSS_ENABLE_ECC=1
 ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_1)
 DEFAULT_GMAKE_FLAGS += OS_DLLFLAGS='-static-libgcc' NSPR31_LIB_PREFIX=lib
 endif
 ifndef MOZ_NATIVE_SQLITE
 ifdef MOZ_FOLD_LIBS
 DEFAULT_GMAKE_FLAGS += SQLITE_LIB_NAME=nss3
 else
 DEFAULT_GMAKE_FLAGS += SQLITE_LIB_NAME=mozsqlite3
+DEFAULT_GMAKE_FLAGS += SQLITE_LIB_DIR=$(ABS_DIST)/../config/external/sqlite
 endif # MOZ_FOLD_LIBS
 DEFAULT_GMAKE_FLAGS += SQLITE_INCLUDE_DIR=$(ABS_DIST)/include
 endif
 ifdef NSS_DISABLE_DBM 
 DEFAULT_GMAKE_FLAGS += NSS_DISABLE_DBM=1
 endif
 # Hack to force NSS build system to use "normal" object directories
 DEFAULT_GMAKE_FLAGS += topsrcdir='$(topsrcdir)'
@@ -352,16 +353,21 @@ nss3.def: $(nss_def_file) $(sqlite_def_f
 	  $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) -o $@ $^)
 
 GARBAGE += \
   nss3.def \
   $(NULL)
 endif # GCC_USE_GNU_LD
 endif # WINNT
 
+IMPORT_LIB_FILES = $(IMPORT_LIBRARY)
+IMPORT_LIB_DEST ?= $(DIST)/lib
+IMPORT_LIB_TARGET = target
+INSTALL_TARGETS += IMPORT_LIB
+
 endif # MOZ_FOLD_LIBS
 
 include $(topsrcdir)/config/rules.mk
 
 # Can't pass this in DEFAULT_GMAKE_FLAGS because that overrides
 # definitions in NSS, so just export it into the sub-make's environment.
 ifeq (WINNT_1,$(OS_TARGET)_$(MOZ_MEMORY))
 ifdef MOZ_CRT
--- a/config/makefiles/target_binaries.mk
+++ b/config/makefiles/target_binaries.mk
@@ -26,59 +26,32 @@ PROGRAMS_DEST ?= $(FINAL_TARGET)
 PROGRAMS_TARGET := target
 INSTALL_TARGETS += PROGRAMS
 endif
 
 ifdef LIBRARY
 ifdef DIST_INSTALL
 ifdef IS_COMPONENT
 $(error Shipping static component libs makes no sense.)
-else
-DIST_LIBRARY_FILES = $(LIBRARY)
-DIST_LIBRARY_DEST ?= $(DIST)/lib
-DIST_LIBRARY_TARGET = target
-INSTALL_TARGETS += DIST_LIBRARY
 endif
 endif # DIST_INSTALL
 endif # LIBRARY
 
 
 ifdef SHARED_LIBRARY
 ifndef IS_COMPONENT
 SHARED_LIBRARY_FILES = $(SHARED_LIBRARY)
 SHARED_LIBRARY_DEST ?= $(FINAL_TARGET)
 SHARED_LIBRARY_TARGET = target
 INSTALL_TARGETS += SHARED_LIBRARY
-
-ifneq (,$(filter WINNT,$(OS_ARCH)))
-ifndef NO_INSTALL_IMPORT_LIBRARY
-IMPORT_LIB_FILES = $(IMPORT_LIBRARY)
-endif # NO_INSTALL_IMPORT_LIBRARY
-else
-IMPORT_LIB_FILES = $(SHARED_LIBRARY)
-endif
-
-IMPORT_LIB_DEST ?= $(DIST)/lib
-IMPORT_LIB_TARGET = target
-ifdef IMPORT_LIB_FILES
-INSTALL_TARGETS += IMPORT_LIB
-endif
-
 endif # ! IS_COMPONENT
 endif # SHARED_LIBRARY
 
 ifneq (,$(strip $(HOST_SIMPLE_PROGRAMS)$(HOST_PROGRAM)))
 HOST_PROGRAMS_EXECUTABLES = $(HOST_SIMPLE_PROGRAMS) $(HOST_PROGRAM)
 HOST_PROGRAMS_DEST ?= $(DIST)/host/bin
 HOST_PROGRAMS_TARGET = host
 INSTALL_TARGETS += HOST_PROGRAMS
 endif
 
-ifdef HOST_LIBRARY
-HOST_LIBRARY_FILES = $(HOST_LIBRARY)
-HOST_LIBRARY_DEST ?= $(DIST)/host/lib
-HOST_LIBRARY_TARGET = host
-INSTALL_TARGETS += HOST_LIBRARY
-endif
-
 endif # !NO_DIST_INSTALL
 
 # EOF
--- a/configure.in
+++ b/configure.in
@@ -2722,16 +2722,17 @@ dnl These are all the places some varian
 MOZ_CHECK_HEADERS(sys/statvfs.h sys/statfs.h sys/vfs.h sys/mount.h)
 
 dnl Quota support
 MOZ_CHECK_HEADERS(sys/quota.h sys/sysmacros.h)
 MOZ_CHECK_HEADERS([linux/quota.h],,,[#include <sys/socket.h>])
 
 dnl SCTP support - needs various network include headers
 MOZ_CHECK_HEADERS([linux/if_addr.h linux/rtnetlink.h],,,[#include <sys/socket.h>])
+MOZ_CHECK_HEADERS(sys/queue.h)
 
 MOZ_CHECK_HEADERS(sys/types.h netinet/in.h byteswap.h)
 
 dnl Check for sin_len and sin6_len - used by SCTP; only appears in Mac/*BSD generally
 AC_CACHE_CHECK(for sockaddr_in.sin_len,
                    ac_cv_sockaddr_in_sin_len,
                    [AC_TRY_COMPILE([#ifdef HAVE_SYS_TYPES_H
                                     #include <sys/types.h>
--- a/docshell/test/navigation/mochitest.ini
+++ b/docshell/test/navigation/mochitest.ini
@@ -40,14 +40,14 @@ skip-if = (buildapp == 'b2g' && (toolkit
 [test_grandchild.html]
 [test_not-opener.html]
 skip-if = buildapp == 'b2g' || (toolkit == 'android' && processor == 'x86') #x86 only
 [test_opener.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_popup-navigates-children.html]
 skip-if = buildapp == 'b2g' # b2g(Needs multiple window.open support, also uses docshelltreenode) b2g-debug(Needs multiple window.open support, also uses docshelltreenode) b2g-desktop(Needs multiple window.open support, also uses docshelltreenode)
 [test_reserved.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || android_version == '10' #too slow on Android 2.3 aws only; bug 1030403
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || android_version == '10' || android_version == '18' #too slow on Android 2.3 and 4.3 aws only; bug 1030403
 [test_sessionhistory.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #RANDOM # b2g-debug(Perma-orange on debug emulator builds) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_sibling-matching-parent.html]
 [test_sibling-off-domain.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
--- a/dom/animation/AnimationPlayer.cpp
+++ b/dom/animation/AnimationPlayer.cpp
@@ -56,17 +56,17 @@ AnimationPlayer::SetStartTime(const Null
   if (!aNewStartTime.IsNull()) {
     if (mPlaybackRate != 0.0) {
       mHoldTime.SetNull();
     }
   } else {
     mHoldTime = previousCurrentTime;
   }
 
-  CancelPendingPlay();
+  CancelPendingTasks();
   if (mReady) {
     // We may have already resolved mReady, but in that case calling
     // MaybeResolve is a no-op, so that's okay.
     mReady->MaybeResolve(this);
   }
 
   UpdateSourceContent();
   PostUpdate();
@@ -118,17 +118,22 @@ AnimationPlayer::SilentlySetCurrentTime(
 }
 
 // Implements http://w3c.github.io/web-animations/#set-the-current-time
 void
 AnimationPlayer::SetCurrentTime(const TimeDuration& aSeekTime)
 {
   SilentlySetCurrentTime(aSeekTime);
 
-  // Once pending pause tasks are supported, cancel that here.
+  if (mPendingState == PendingState::PausePending) {
+    CancelPendingTasks();
+    if (mReady) {
+      mReady->MaybeResolve(this);
+    }
+  }
 
   UpdateSourceContent();
   PostUpdate();
 
   // FIXME: Once bug 1074630 is fixed, run the procedure to update a player's
   // finished state for player:
   // http://w3c.github.io/web-animations/#update-a-players-finished-state
 }
@@ -155,17 +160,17 @@ AnimationPlayer::SilentlySetPlaybackRate
     SilentlySetCurrentTime(previousTime.Value());
     MOZ_ASSERT(!rv.Failed(), "Should not assert for non-null time");
   }
 }
 
 AnimationPlayState
 AnimationPlayer::PlayState() const
 {
-  if (mIsPending) {
+  if (mPendingState != PendingState::NotPending) {
     return AnimationPlayState::Pending;
   }
 
   Nullable<TimeDuration> currentTime = GetCurrentTime();
   if (currentTime.IsNull()) {
     return AnimationPlayState::Idle;
   }
 
@@ -262,50 +267,49 @@ AnimationPlayer::SetSource(Animation* aS
 
 void
 AnimationPlayer::Tick()
 {
   // Since we are not guaranteed to get only one call per refresh driver tick,
   // it's possible that mPendingReadyTime is set to a time in the future.
   // In that case, we should wait until the next refresh driver tick before
   // resuming.
-  if (mIsPending &&
+  if (mPendingState != PendingState::NotPending &&
       !mPendingReadyTime.IsNull() &&
       mPendingReadyTime.Value() <= mTimeline->GetCurrentTime().Value()) {
     ResumeAt(mPendingReadyTime.Value());
     mPendingReadyTime.SetNull();
   }
 
   if (IsPossiblyOrphanedPendingPlayer()) {
     MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(),
                "Orphaned pending players should have an active timeline");
     ResumeAt(mTimeline->GetCurrentTime().Value());
   }
 
   UpdateSourceContent();
 }
 
 void
-AnimationPlayer::StartOnNextTick(const Nullable<TimeDuration>& aReadyTime)
+AnimationPlayer::TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime)
 {
   // Normally we expect the play state to be pending but it's possible that,
-  // due to the handling of possibly orphaned players in Tick() [coming
-  // in a later patch in this series], this player got started whilst still
-  // being in another document's pending player map.
+  // due to the handling of possibly orphaned players in Tick(), this player got
+  // started whilst still being in another document's pending player map.
   if (PlayState() != AnimationPlayState::Pending) {
     return;
   }
 
   // If aReadyTime.IsNull() we'll detect this in Tick() where we check for
   // orphaned players and trigger this animation anyway
   mPendingReadyTime = aReadyTime;
 }
 
 void
-AnimationPlayer::StartNow()
+AnimationPlayer::TriggerNow()
 {
   MOZ_ASSERT(PlayState() == AnimationPlayState::Pending,
              "Expected to start a pending player");
   MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(),
              "Expected an active timeline");
 
   ResumeAt(mTimeline->GetCurrentTime().Value());
 }
@@ -329,33 +333,35 @@ AnimationPlayer::GetCurrentOrPendingStar
   // need to incorporate the playbackRate when implemented (bug 1127380).
   result.SetValue(mPendingReadyTime.Value() - mHoldTime.Value());
   return result;
 }
 
 void
 AnimationPlayer::Cancel()
 {
-  if (mIsPending) {
-    CancelPendingPlay();
+  if (mPendingState != PendingState::NotPending) {
+    CancelPendingTasks();
     if (mReady) {
       mReady->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     }
   }
 
   mHoldTime.SetNull();
   mStartTime.SetNull();
 
   UpdateSourceContent();
 }
 
 bool
 AnimationPlayer::IsRunning() const
 {
-  if (IsPaused() || !GetSource() || GetSource()->IsFinishedTransition()) {
+  if (IsPausedOrPausing() ||
+      !GetSource() ||
+      GetSource()->IsFinishedTransition()) {
     return false;
   }
 
   ComputedTiming computedTiming = GetSource()->GetComputedTiming();
   return computedTiming.mPhase == ComputedTiming::AnimationPhase_Active;
 }
 
 void
@@ -419,58 +425,66 @@ AnimationPlayer::ComposeStyle(nsRefPtr<c
 
 void
 AnimationPlayer::DoPlay()
 {
   // FIXME: When we implement finishing behavior (bug 1074630) we will
   // need to pass a flag so that when we start playing due to a change in
   // animation-play-state we *don't* trigger finishing behavior.
 
+  bool reuseReadyPromise = false;
+  if (mPendingState != PendingState::NotPending) {
+    CancelPendingTasks();
+    reuseReadyPromise = true;
+  }
+
   Nullable<TimeDuration> currentTime = GetCurrentTime();
   if (mPlaybackRate > 0.0 &&
       (currentTime.IsNull())) {
     mHoldTime.SetValue(TimeDuration(0));
   } else if (mPlaybackRate < 0.0 &&
              (currentTime.IsNull())) {
     mHoldTime.SetValue(TimeDuration(SourceContentEnd()));
   } else if (mPlaybackRate == 0.0 && currentTime.IsNull()) {
     mHoldTime.SetValue(TimeDuration(0));
   }
 
   if (mHoldTime.IsNull()) {
     return;
   }
 
-  // Clear ready promise. We'll create a new one lazily.
-  mReady = nullptr;
-
   // Clear the start time until we resolve a new one
   mStartTime.SetNull();
 
-  mIsPending = true;
+  if (!reuseReadyPromise) {
+    // Clear ready promise. We'll create a new one lazily.
+    mReady = nullptr;
+  }
+
+  mPendingState = PendingState::PlayPending;
 
   nsIDocument* doc = GetRenderedDocument();
   if (!doc) {
-    StartOnNextTick(Nullable<TimeDuration>());
+    TriggerOnNextTick(Nullable<TimeDuration>());
     return;
   }
 
   PendingPlayerTracker* tracker = doc->GetOrCreatePendingPlayerTracker();
   tracker->AddPlayPending(*this);
 
   // We may have updated the current time when we set the hold time above
   // so notify source content.
   UpdateSourceContent();
 }
 
 void
 AnimationPlayer::DoPause()
 {
-  if (mIsPending) {
-    CancelPendingPlay();
+  if (mPendingState == PendingState::PlayPending) {
+    CancelPendingTasks();
     // Resolve the ready promise since we currently only use it for
     // players that are waiting to play. Later (in bug 1109390), we will
     // use this for players waiting to pause as well and then we won't
     // want to resolve it just yet.
     if (mReady) {
       mReady->MaybeResolve(this);
     }
   }
@@ -486,28 +500,29 @@ AnimationPlayer::DoPause()
 }
 
 void
 AnimationPlayer::ResumeAt(const TimeDuration& aResumeTime)
 {
   // This method is only expected to be called for a player that is
   // waiting to play. We can easily adapt it to handle other states
   // but it's currently not necessary.
-  MOZ_ASSERT(PlayState() == AnimationPlayState::Pending,
-             "Expected to resume a pending player");
+  MOZ_ASSERT(mPendingState == PendingState::PlayPending,
+             "Expected to resume a play-pending player");
   MOZ_ASSERT(!mHoldTime.IsNull(),
-             "A player in the pending state should have a resolved hold time");
+             "A player in the play-pending state should have a resolved"
+             " hold time");
 
   if (mPlaybackRate != 0) {
     mStartTime.SetValue(aResumeTime - (mHoldTime.Value() / mPlaybackRate));
     mHoldTime.SetNull();
   } else {
     mStartTime.SetValue(aResumeTime);
   }
-  mIsPending = false;
+  mPendingState = PendingState::NotPending;
 
   UpdateSourceContent();
 
   if (mReady) {
     mReady->MaybeResolve(this);
   }
 }
 
@@ -534,31 +549,35 @@ AnimationPlayer::PostUpdate()
 {
   AnimationPlayerCollection* collection = GetCollection();
   if (collection) {
     collection->NotifyPlayerUpdated();
   }
 }
 
 void
-AnimationPlayer::CancelPendingPlay()
+AnimationPlayer::CancelPendingTasks()
 {
-  if (!mIsPending) {
+  if (mPendingState == PendingState::NotPending) {
     return;
   }
 
   nsIDocument* doc = GetRenderedDocument();
   if (doc) {
     PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker();
     if (tracker) {
-      tracker->RemovePlayPending(*this);
+      if (mPendingState == PendingState::PlayPending) {
+        tracker->RemovePlayPending(*this);
+      } else {
+        tracker->RemovePausePending(*this);
+      }
     }
   }
 
-  mIsPending = false;
+  mPendingState = PendingState::NotPending;
   mPendingReadyTime.SetNull();
 }
 
 bool
 AnimationPlayer::IsPossiblyOrphanedPendingPlayer() const
 {
   // Check if we are pending but might never start because we are not being
   // tracked.
@@ -569,21 +588,21 @@ AnimationPlayer::IsPossiblyOrphanedPendi
   //   or bound to a different document.
   //   (note that for the case of our source content changing we should handle
   //   that in SetSource)
   // * We started playing but our timeline became inactive.
   //   In this case the pending player tracker will drop us from its hashmap
   //   when we have been painted.
   // * When we started playing we couldn't find a PendingPlayerTracker to
   //   register with (perhaps the source content had no document) so we simply
-  //   set mIsPending in DoPlay and relied on this method to catch us on the
+  //   set mPendingState in DoPlay and relied on this method to catch us on the
   //   next tick.
 
   // If we're not pending we're ok.
-  if (!mIsPending) {
+  if (mPendingState == PendingState::NotPending) {
     return false;
   }
 
   // If we have a pending ready time then we will be started on the next
   // tick.
   if (!mPendingReadyTime.IsNull()) {
     return false;
   }
@@ -593,22 +612,27 @@ AnimationPlayer::IsPossiblyOrphanedPendi
   if (!mTimeline || mTimeline->GetCurrentTime().IsNull()) {
     return false;
   }
 
   // If we have no rendered document, or we're not in our rendered document's
   // PendingPlayerTracker then there's a good chance no one is tracking us.
   //
   // If we're wrong and another document is tracking us then, at worst, we'll
-  // simply start the animation one tick too soon. That's better than never
-  // starting the animation and is unlikely.
+  // simply start/pause the animation one tick too soon. That's better than
+  // never starting/pausing the animation and is unlikely.
   nsIDocument* doc = GetRenderedDocument();
-  return !doc ||
-         !doc->GetPendingPlayerTracker() ||
-         !doc->GetPendingPlayerTracker()->IsWaitingToPlay(*this);
+  if (!doc) {
+    return false;
+  }
+
+  PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker();
+  return !tracker ||
+         (!tracker->IsWaitingToPlay(*this) &&
+          !tracker->IsWaitingToPause(*this));
 }
 
 StickyTimeDuration
 AnimationPlayer::SourceContentEnd() const
 {
   if (!mSource) {
     return StickyTimeDuration(0);
   }
--- a/dom/animation/AnimationPlayer.h
+++ b/dom/animation/AnimationPlayer.h
@@ -49,17 +49,17 @@ class AnimationPlayer : public nsISuppor
 {
 protected:
   virtual ~AnimationPlayer() {}
 
 public:
   explicit AnimationPlayer(AnimationTimeline* aTimeline)
     : mTimeline(aTimeline)
     , mPlaybackRate(1.0)
-    , mIsPending(false)
+    , mPendingState(PendingState::NotPending)
     , mIsRunningOnCompositor(false)
     , mIsPreviousStateFinished(false)
     , mIsRelevant(false)
   {
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationPlayer)
@@ -102,31 +102,33 @@ public:
   // in future we will likely have to flush style in
   // CSSAnimationPlayer::PauseFromJS so we leave it for now.
   void PauseFromJS() { Pause(); }
 
   void SetSource(Animation* aSource);
   void Tick();
 
   /**
+   * Set the time to use for starting or pausing a pending player.
+   *
    * Typically, when a player is played, it does not start immediately but is
    * added to a table of pending players on the document of its source content.
    * In the meantime it sets its hold time to the time from which playback
    * should begin.
    *
    * When the document finishes painting, any pending players in its table
    * are marked as being ready to start by calling StartOnNextTick.
    * The moment when the paint completed is also recorded, converted to a
    * timeline time, and passed to StartOnTick. This is so that when these
    * players do start, they can be timed from the point when painting
    * completed.
    *
-   * After calling StartOnNextTick, players remain in the pending state until
+   * After calling TriggerOnNextTick, players remain in the pending state until
    * the next refresh driver tick. At that time they transition out of the
-   * pending state using the time passed to StartOnNextTick as the effective
+   * pending state using the time passed to TriggerOnNextTick as the effective
    * time at which they resumed.
    *
    * This approach means that any setup time required for performing the
    * initial paint of an animation such as layerization is not deducted from
    * the running time of the animation. Without this we can easily drop the
    * first few frames of an animation, or, on slower devices, the whole
    * animation.
    *
@@ -140,30 +142,37 @@ public:
    *   time of the player but then we'd also have to update the timing and style
    *   of all animations connected to that timeline or else be stuck in an
    *   inconsistent state until the next refresh driver tick.
    *
    * - If we simply use the refresh driver time on its next tick, the lag
    *   between triggering an animation and its effective start is unacceptably
    *   long.
    *
+   * For pausing, we apply the same asynchronous approach. This is so that we
+   * synchronize with animations that are running on the compositor. Otherwise
+   * if the main thread lags behind the compositor there will be a noticeable
+   * jump backwards when the main thread takes over. Even though main thread
+   * animations could be paused immediately, we do it asynchronously for
+   * consistency and so that animations paused together end up in step.
+   *
    * Note that the caller of this method is responsible for removing the player
    * from any PendingPlayerTracker it may have been added to.
    */
-  void StartOnNextTick(const Nullable<TimeDuration>& aReadyTime);
+  void TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime);
 
-  // Testing only: Start a pending player using the current timeline time.
-  // This is used to support existing tests that expect animations to begin
-  // immediately. Ideally we would rewrite the those tests and get rid of this
-  // method, but there are a lot of them.
+  // Testing only: Start or pause a pending player using the current timeline
+  // time. This is used to support existing tests that expect animations to
+  // begin immediately. Ideally we would rewrite the those tests and get rid of
+  // this method, but there are a lot of them.
   //
-  // As with StartOnNextTick, the caller of this method is responsible for
+  // As with TriggerOnNextTick, the caller of this method is responsible for
   // removing the player from any PendingPlayerTracker it may have been added
   // to.
-  void StartNow();
+  void TriggerNow();
 
   /**
    * When StartOnNextTick is called, we store the ready time but we don't apply
    * it until the next tick. In the meantime, GetStartTime() will return null.
    *
    * However, if we build layer animations again before the next tick, we
    * should initialize them with the start time that GetStartTime() will return
    * on the next tick.
@@ -177,27 +186,34 @@ public:
    * This method returns the start time, if resolved. Otherwise, if we have
    * a pending ready time, it returns the corresponding start time. If neither
    * of those are available, it returns null.
    */
   Nullable<TimeDuration> GetCurrentOrPendingStartTime() const;
 
   void Cancel();
 
-  const nsString& Name() const {
+  const nsString& Name() const
+  {
     return mSource ? mSource->Name() : EmptyString();
   }
 
-  bool IsPaused() const { return PlayState() == AnimationPlayState::Paused; }
+  bool IsPausedOrPausing() const
+  {
+    return PlayState() == AnimationPlayState::Paused ||
+           mPendingState == PendingState::PausePending;
+  }
   bool IsRunning() const;
 
-  bool HasCurrentSource() const {
+  bool HasCurrentSource() const
+  {
     return GetSource() && GetSource()->IsCurrent();
   }
-  bool HasInEffectSource() const {
+  bool HasInEffectSource() const
+  {
     return GetSource() && GetSource()->IsInEffect();
   }
 
   bool IsRelevant() const { return mIsRelevant; }
   void UpdateRelevance();
 
   void SetIsRunningOnCompositor() { mIsRunningOnCompositor = true; }
   void ClearIsRunningOnCompositor() { mIsRunningOnCompositor = false; }
@@ -221,20 +237,22 @@ public:
 protected:
   void DoPlay();
   void DoPause();
   void ResumeAt(const TimeDuration& aResumeTime);
 
   void UpdateSourceContent();
   void FlushStyle() const;
   void PostUpdate();
-  // Remove this player from the pending player tracker and resets mIsPending
-  // as necessary. The caller is responsible for resolving or aborting the
-  // mReady promise as necessary.
-  void CancelPendingPlay();
+  /**
+   * Remove this player from the pending player tracker and reset
+   * mPendingState as necessary. The caller is responsible for resolving or
+   * aborting the mReady promise as necessary.
+   */
+  void CancelPendingTasks();
 
   bool IsPossiblyOrphanedPendingPlayer() const;
   StickyTimeDuration SourceContentEnd() const;
 
   nsIDocument* GetRenderedDocument() const;
   nsPresContext* GetPresContext() const;
   virtual css::CommonAnimationManager* GetAnimationManager() const = 0;
   AnimationPlayerCollection* GetCollection() const;
@@ -247,22 +265,25 @@ protected:
   Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
   double mPlaybackRate;
 
   // A Promise that is replaced on each call to Play() (and in future Pause())
   // and fulfilled when Play() is successfully completed.
   // This object is lazily created by GetReady.
   nsRefPtr<Promise> mReady;
 
-  // Indicates if the player is in the pending state. We use this rather
-  // than checking if this player is tracked by a PendingPlayerTracker.
-  // This is because the PendingPlayerTracker is associated with the source
-  // content's document but we need to know if we're pending even if the
-  // source content loses association with its document.
-  bool mIsPending;
+  // Indicates if the player is in the pending state (and what state it is
+  // waiting to enter when it finished pending). We use this rather than
+  // checking if this player is tracked by a PendingPlayerTracker because the
+  // player will continue to be pending even after it has been removed from the
+  // PendingPlayerTracker while it is waiting for the next tick
+  // (see TriggerOnNextTick for details).
+  enum class PendingState { NotPending, PlayPending, PausePending };
+  PendingState mPendingState;
+
   bool mIsRunningOnCompositor;
   // Indicates whether we were in the finished state during our
   // most recent unthrottled sample (our last ComposeStyle call).
   // FIXME: When we implement the finished promise (bug 1074630) we can
   // probably remove this and check if the promise has been settled yet
   // or not instead.
   bool mIsPreviousStateFinished; // Spec calls this "previous finished state"
   // Indicates that the player should be exposed in an element's
--- a/dom/animation/PendingPlayerTracker.cpp
+++ b/dom/animation/PendingPlayerTracker.cpp
@@ -8,86 +8,97 @@
 #include "mozilla/dom/AnimationTimeline.h"
 #include "nsIFrame.h"
 #include "nsIPresShell.h"
 
 using namespace mozilla;
 
 namespace mozilla {
 
-NS_IMPL_CYCLE_COLLECTION(PendingPlayerTracker, mPlayPendingSet, mDocument)
+NS_IMPL_CYCLE_COLLECTION(PendingPlayerTracker,
+                         mPlayPendingSet,
+                         mPausePendingSet,
+                         mDocument)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PendingPlayerTracker, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PendingPlayerTracker, Release)
 
 void
-PendingPlayerTracker::AddPlayPending(dom::AnimationPlayer& aPlayer)
+PendingPlayerTracker::AddPending(dom::AnimationPlayer& aPlayer,
+                                 AnimationPlayerSet& aSet)
 {
-  mPlayPendingSet.PutEntry(&aPlayer);
+  aSet.PutEntry(&aPlayer);
 
   // Schedule a paint. Otherwise animations that don't trigger a paint by
   // themselves (e.g. CSS animations with an empty keyframes rule) won't
   // start until something else paints.
   EnsurePaintIsScheduled();
 }
 
 void
-PendingPlayerTracker::RemovePlayPending(dom::AnimationPlayer& aPlayer)
+PendingPlayerTracker::RemovePending(dom::AnimationPlayer& aPlayer,
+                                    AnimationPlayerSet& aSet)
 {
-  mPlayPendingSet.RemoveEntry(&aPlayer);
+  aSet.RemoveEntry(&aPlayer);
 }
 
 bool
-PendingPlayerTracker::IsWaitingToPlay(dom::AnimationPlayer const& aPlayer) const
+PendingPlayerTracker::IsWaiting(const dom::AnimationPlayer& aPlayer,
+                                const AnimationPlayerSet& aSet) const
 {
-  return mPlayPendingSet.Contains(const_cast<dom::AnimationPlayer*>(&aPlayer));
+  return aSet.Contains(const_cast<dom::AnimationPlayer*>(&aPlayer));
 }
 
 PLDHashOperator
-StartPlayerAtTime(nsRefPtrHashKey<dom::AnimationPlayer>* aKey,
-                  void* aReadyTime)
+TriggerPlayerAtTime(nsRefPtrHashKey<dom::AnimationPlayer>* aKey,
+                    void* aReadyTime)
 {
   dom::AnimationPlayer* player = aKey->GetKey();
   dom::AnimationTimeline* timeline = player->Timeline();
 
   // When the timeline's refresh driver is under test control, its values
   // have no correspondance to wallclock times so we shouldn't try to convert
   // aReadyTime (which is a wallclock time) to a timeline value. Instead, the
-  // animation player will be started when the refresh driver is next
-  // advanced since this will trigger a call to StartPendingPlayersNow.
+  // animation player will be started/paused when the refresh driver is next
+  // advanced since this will trigger a call to TriggerPendingPlayersNow.
   if (timeline->IsUnderTestControl()) {
     return PL_DHASH_NEXT;
   }
 
   Nullable<TimeDuration> readyTime =
     timeline->ToTimelineTime(*static_cast<const TimeStamp*>(aReadyTime));
-  player->StartOnNextTick(readyTime);
+  player->TriggerOnNextTick(readyTime);
 
   return PL_DHASH_REMOVE;
 }
 
 void
-PendingPlayerTracker::StartPendingPlayersOnNextTick(const TimeStamp& aReadyTime)
+PendingPlayerTracker::TriggerPendingPlayersOnNextTick(const TimeStamp&
+                                                        aReadyTime)
 {
-  mPlayPendingSet.EnumerateEntries(StartPlayerAtTime,
+  mPlayPendingSet.EnumerateEntries(TriggerPlayerAtTime,
                                    const_cast<TimeStamp*>(&aReadyTime));
+  mPausePendingSet.EnumerateEntries(TriggerPlayerAtTime,
+                                    const_cast<TimeStamp*>(&aReadyTime));
 }
 
 PLDHashOperator
-StartPlayerNow(nsRefPtrHashKey<dom::AnimationPlayer>* aKey, void*)
+TriggerPlayerNow(nsRefPtrHashKey<dom::AnimationPlayer>* aKey, void*)
 {
-  aKey->GetKey()->StartNow();
+  aKey->GetKey()->TriggerNow();
   return PL_DHASH_NEXT;
 }
 
 void
-PendingPlayerTracker::StartPendingPlayersNow()
+PendingPlayerTracker::TriggerPendingPlayersNow()
 {
-  mPlayPendingSet.EnumerateEntries(StartPlayerNow, nullptr);
+  mPlayPendingSet.EnumerateEntries(TriggerPlayerNow, nullptr);
   mPlayPendingSet.Clear();
+  mPausePendingSet.EnumerateEntries(TriggerPlayerNow, nullptr);
+  mPausePendingSet.Clear();
 }
 
 void
 PendingPlayerTracker::EnsurePaintIsScheduled()
 {
   if (!mDocument) {
     return;
   }
--- a/dom/animation/PendingPlayerTracker.h
+++ b/dom/animation/PendingPlayerTracker.h
@@ -20,31 +20,67 @@ class PendingPlayerTracker final
 public:
   explicit PendingPlayerTracker(nsIDocument* aDocument)
     : mDocument(aDocument)
   { }
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PendingPlayerTracker)
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(PendingPlayerTracker)
 
-  void AddPlayPending(dom::AnimationPlayer& aPlayer);
-  void RemovePlayPending(dom::AnimationPlayer& aPlayer);
-  bool IsWaitingToPlay(dom::AnimationPlayer const& aPlayer) const;
+  void AddPlayPending(dom::AnimationPlayer& aPlayer)
+  {
+    MOZ_ASSERT(!IsWaitingToPause(aPlayer),
+               "Player is already waiting to pause");
+    AddPending(aPlayer, mPlayPendingSet);
+  }
+  void RemovePlayPending(dom::AnimationPlayer& aPlayer)
+  {
+    RemovePending(aPlayer, mPlayPendingSet);
+  }
+  bool IsWaitingToPlay(const dom::AnimationPlayer& aPlayer) const
+  {
+    return IsWaiting(aPlayer, mPlayPendingSet);
+  }
 
-  void StartPendingPlayersOnNextTick(const TimeStamp& aReadyTime);
-  void StartPendingPlayersNow();
-  bool HasPendingPlayers() const { return mPlayPendingSet.Count() > 0; }
+  void AddPausePending(dom::AnimationPlayer& aPlayer)
+  {
+    MOZ_ASSERT(!IsWaitingToPlay(aPlayer),
+               "Player is already waiting to play");
+    AddPending(aPlayer, mPausePendingSet);
+  }
+  void RemovePausePending(dom::AnimationPlayer& aPlayer)
+  {
+    RemovePending(aPlayer, mPausePendingSet);
+  }
+  bool IsWaitingToPause(const dom::AnimationPlayer& aPlayer) const
+  {
+    return IsWaiting(aPlayer, mPausePendingSet);
+  }
+
+  void TriggerPendingPlayersOnNextTick(const TimeStamp& aReadyTime);
+  void TriggerPendingPlayersNow();
+  bool HasPendingPlayers() const {
+    return mPlayPendingSet.Count() > 0 || mPausePendingSet.Count() > 0;
+  }
 
 private:
   ~PendingPlayerTracker() { }
 
   void EnsurePaintIsScheduled();
 
   typedef nsTHashtable<nsRefPtrHashKey<dom::AnimationPlayer>>
     AnimationPlayerSet;
 
+  void AddPending(dom::AnimationPlayer& aPlayer,
+                  AnimationPlayerSet& aSet);
+  void RemovePending(dom::AnimationPlayer& aPlayer,
+                     AnimationPlayerSet& aSet);
+  bool IsWaiting(const dom::AnimationPlayer& aPlayer,
+                 const AnimationPlayerSet& aSet) const;
+
   AnimationPlayerSet mPlayPendingSet;
+  AnimationPlayerSet mPausePendingSet;
   nsCOMPtr<nsIDocument> mDocument;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_dom_PendingPlayerTracker_h
--- a/dom/animation/test/css-animations/test_animation-pausing.html
+++ b/dom/animation/test/css-animations/test_animation-pausing.html
@@ -26,20 +26,21 @@ async_test(function(t) {
 
   assert_equals(getMarginLeft(cs), 0,
                 'Initial value of margin-left is zero');
   var previousAnimVal = getMarginLeft(cs);
 
   player.ready.then(waitForFrame).then(t.step_func(function() {
     assert_true(getMarginLeft(cs) > previousAnimVal,
                 'margin-left is initially increasing');
+    player.pause();
+    return player.ready;
+  })).then(t.step_func(function() {
     previousAnimVal = getMarginLeft(cs);
-
-    player.pause();
-    return player.ready.then(waitForFrame);
+    return waitForFrame();
   })).then(t.step_func(function() {
     assert_equals(getMarginLeft(cs), previousAnimVal,
                   'margin-left does not increase after calling pause()');
     t.done();
   }));
 }, 'pause() a running animation');
 
 async_test(function(t) {
@@ -97,23 +98,24 @@ async_test(function(t) {
 
   player.ready.then(function() {
     div.style.animationPlayState = 'running';
     cs.animationPlayState; // Trigger style resolution
     return waitForFrame();
   }).then(t.step_func(function() {
     assert_equals(cs.animationPlayState, 'running',
                   'animation-play-state is running');
-    previousAnimVal = getMarginLeft(cs);
     div.style.animationPlayState = 'paused';
-    cs.animationPlayState; // Trigger style resolution
-    return waitForFrame();
+    return player.ready;
   })).then(t.step_func(function() {
     assert_equals(cs.animationPlayState, 'paused',
                   'animation-play-state is paused');
+    previousAnimVal = getMarginLeft(cs);
+    return waitForFrame();
+  })).then(t.step_func(function() {
     assert_equals(getMarginLeft(cs), previousAnimVal,
                   'Animated value of margin-left does not change when'
                   + ' paused by style');
     t.done();
   }));
 }, 'play() is overridden by later setting "animation-play-state: paused"');
 
 async_test(function(t) {
@@ -147,31 +149,31 @@ async_test(function(t) {
   div.style.animation = 'anim 1000s paused';
 
   var player = div.getAnimationPlayers()[0];
   assert_equals(getMarginLeft(cs), 0,
                 'Initial value of margin-left is zero');
 
   // Unlike the previous test for play(), since calling pause() is sticky,
   // we'll apply it even if the underlying style also says we're paused.
-  // 
+  //
   // We would like to test that implementations flush styles before running
   // pause() but actually there's no style we can currently set that will
   // change the behavior of pause(). That may change in the future
   // (e.g. if we introduce animation-timeline or animation-playback-rate etc.).
   //
   // For now this just serves as a sanity check that we do the same thing
   // even if we set style before calling the API.
   div.style.animationPlayState = 'running';
   player.pause();
   var previousAnimVal = getMarginLeft(cs);
 
-  waitForFrame().then(t.step_func(function() {
+  player.ready.then(waitForFrame).then(t.step_func(function() {
     assert_equals(cs.animationPlayState, 'running',
-                  'animation-play-state is paused');
+                  'animation-play-state is running');
     assert_equals(getMarginLeft(cs), previousAnimVal,
                   'Paused value of margin-left does not change');
     t.done();
   }));
 }, 'pause() applies pending changes to animation-play-state first');
 // (Note that we can't actually test for this; see comment above, in test-body.)
 
 </script>
--- a/dom/animation/test/css-animations/test_animation-player-currenttime.html
+++ b/dom/animation/test/css-animations/test_animation-player-currenttime.html
@@ -583,34 +583,31 @@ async_test(function(t) {
 }, 'Setting currentTime to null');
 
 
 async_test(function(t) {
   var div = addDiv(t, {'class': 'animated-div'});
   div.style.animation = 'anim 100s';
 
   var player = div.getAnimationPlayers()[0];
+  var pauseTime;
 
   player.ready.then(t.step_func(function() {
-    var savedCurrentTime = player.currentTime;
-
     assert_not_equals(player.currentTime, null,
       'AnimationPlayer.currentTime not null on ready Promise resolve');
-
-    var prePauseCurrentTime = player.currentTime;
-
     player.pause();
-    // After bug 1109390 we will need to wait here for the ready promise again
-
-    assert_equals(player.currentTime, prePauseCurrentTime,
-      'AnimationPlayer.currentTime is unchanged after AnimationPlayer.pause()');
-    assert_equals(player.playState, 'paused',
-      'AnimationPlayer.playState is "paused" after pause() call');
+    return player.ready;
+  })).then(t.step_func(function() {
+    pauseTime = player.currentTime;
+    return waitForFrame();
+  })).then(t.step_func(function() {
+    assert_equals(player.currentTime, pauseTime,
+      'AnimationPlayer.currentTime is unchanged after pausing');
   })).catch(t.step_func(function(reason) {
     assert_unreached(reason);
   })).then(function() {
     t.done();
   });
-}, 'AnimationPlayer.currentTime after paused');
+}, 'AnimationPlayer.currentTime after pausing');
 
     </script>
   </body>
 </html>
--- a/dom/animation/test/css-animations/test_animation-player-playstate.html
+++ b/dom/animation/test/css-animations/test_animation-player-playstate.html
@@ -19,33 +19,47 @@ async_test(function(t) {
   assert_equals(player.playState, 'pending');
 
   player.ready.then(t.step_func(function() {
     assert_equals(player.playState, 'running');
     t.done();
   }));
 }, 'Player returns correct playState when running');
 
-test(function(t) {
+async_test(function(t) {
   var div = addDiv(t);
   var cs = window.getComputedStyle(div);
   div.style.animation = 'anim 1000s paused';
 
   var player = div.getAnimationPlayers()[0];
-  assert_equals(player.playState, 'paused');
+  // FIXME: When we turn on async pausing later in this patch series, enable
+  // this
+  //   assert_equals(player.playState, 'pending');
+
+  player.ready.then(t.step_func(function() {
+    assert_equals(player.playState, 'paused');
+    t.done();
+  }));
 }, 'Player returns correct playState when paused');
 
-test(function(t) {
+async_test(function(t) {
   var div = addDiv(t);
   var cs = window.getComputedStyle(div);
   div.style.animation = 'anim 1000s';
 
   var player = div.getAnimationPlayers()[0];
   player.pause();
-  assert_equals(player.playState, 'paused');
+  // FIXME: When we turn on async pausing later in this patch series, enable
+  // this
+  //   assert_equals(player.playState, 'pending');
+
+  player.ready.then(t.step_func(function() {
+    assert_equals(player.playState, 'paused');
+    t.done();
+  }));
 }, 'Player.playState updates when paused by script');
 
 test(function(t) {
   var div = addDiv(t);
   var cs = window.getComputedStyle(div);
   div.style.animation = 'anim 1000s paused';
 
   var player = div.getAnimationPlayers()[0];
--- a/dom/animation/test/css-animations/test_animation-player-starttime.html
+++ b/dom/animation/test/css-animations/test_animation-player-starttime.html
@@ -613,18 +613,18 @@ async_test(function(t) {
 
   player.ready.then(t.step_func(function() {
     var savedStartTime = player.startTime;
 
     assert_not_equals(player.startTime, null,
       'AnimationPlayer.startTime not null on ready Promise resolve');
 
     player.pause();
-    // After bug 1109390 we will need to wait here for the ready promise again
-
+    return player.ready;
+  })).then(t.step_func(function() {
     assert_equals(player.startTime, null,
       'AnimationPlayer.startTime is null after paused');
     assert_equals(player.playState, 'paused',
       'AnimationPlayer.playState is "paused" after pause() call');
   })).catch(t.step_func(function(reason) {
     assert_unreached(reason);
   })).then(function() {
     t.done();
--- a/dom/animation/test/css-transitions/test_animation-player-starttime.html
+++ b/dom/animation/test/css-transitions/test_animation-player-starttime.html
@@ -379,18 +379,18 @@ async_test(function(t) {
 
   player.ready.then(t.step_func(function() {
     var savedStartTime = player.startTime;
 
     assert_not_equals(player.startTime, null,
       'AnimationPlayer.startTime not null on ready Promise resolve');
 
     player.pause();
-    // After bug 1109390 we will need to wait here for the ready promise again
-
+    return player.ready;
+  })).then(t.step_func(function() {
     assert_equals(player.startTime, null,
       'AnimationPlayer.startTime is null after paused');
     assert_equals(player.playState, 'paused',
       'AnimationPlayer.playState is "paused" after pause() call');
   })).catch(t.step_func(function(reason) {
     assert_unreached(reason);
   })).then(function() {
     t.done();
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -484,17 +484,17 @@ AutoJSAPI::InitWithLegacyErrorReporting(
 //
 // Eventually, SpiderMonkey will have a special-purpose callback for warnings
 // only.
 void
 WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aRep)
 {
   MOZ_ASSERT(JSREPORT_IS_WARNING(aRep->flags));
   nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
-  nsPIDOMWindow* win = xpc::WindowGlobalOrNull(JS::CurrentGlobalOrNull(aCx));
+  nsPIDOMWindow* win = xpc::CurrentWindowOrNull(aCx);
   xpcReport->Init(aRep, aMessage, nsContentUtils::IsCallerChrome(),
                   win ? win->WindowID() : 0);
   xpcReport->LogToConsole();
 }
 
 void
 AutoJSAPI::TakeOwnershipOfErrorReporting()
 {
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2590,17 +2590,17 @@ nsDOMWindowUtils::AdvanceTimeAndRefresh(
   // player's 'ready' promise before continuing. Then we could remove the
   // special handling here and the code path followed when testing would
   // more closely match the code path during regular operation. Filed as
   // bug 1112957.
   nsCOMPtr<nsIDocument> doc = GetDocument();
   if (doc) {
     PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker();
     if (tracker) {
-      tracker->StartPendingPlayersNow();
+      tracker->TriggerPendingPlayersNow();
     }
   }
 
   nsRefreshDriver* driver = GetPresContext()->RefreshDriver();
   driver->AdvanceTimeAndRefresh(aMilliseconds);
 
   RefPtr<LayerTransactionChild> transaction = GetLayerTransaction();
   if (transaction && transaction->IPCOpen()) {
@@ -3980,16 +3980,42 @@ nsDOMWindowUtils::GetFramesReflowed(uint
   if (!presContext) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   *aResult = presContext->FramesReflowedCount();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDOMWindowUtils::SetServiceWorkersTestingEnabled(bool aEnabled)
+{
+  MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+  NS_ENSURE_STATE(window);
+
+  window->SetServiceWorkersTestingEnabled(aEnabled);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::GetServiceWorkersTestingEnabled(bool *aEnabled)
+{
+  MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+  NS_ENSURE_STATE(window);
+
+  *aEnabled = window->GetServiceWorkersTestingEnabled();
+
+  return NS_OK;
+}
+
 NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsTranslationNodeList)
 NS_IMPL_RELEASE(nsTranslationNodeList)
 
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -879,18 +879,17 @@ nsFrameLoader::ShowRemoteFrame(const Scr
                           "remote-browser-shown", nullptr);
     }
   } else {
     nsIntRect dimensions;
     NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
 
     // Don't show remote iframe if we are waiting for the completion of reflow.
     if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
-      nsIntPoint chromeDisp = aFrame->GetChromeDisplacement();
-      mRemoteBrowser->UpdateDimensions(dimensions, size, chromeDisp);
+      mRemoteBrowser->UpdateDimensions(dimensions, size);
     }
   }
 
   return true;
 }
 
 void
 nsFrameLoader::Hide()
@@ -1378,16 +1377,22 @@ nsFrameLoader::StartDestroy()
   // references are dropped in DestroyComplete.
   if (mChildMessageManager || mRemoteBrowser) {
     mOwnerContentStrong = mOwnerContent;
     if (mRemoteBrowser) {
       mRemoteBrowser->CacheFrameLoader(this);
     }
   }
 
+  // If the TabParent has installed any event listeners on the window, this is
+  // its last chance to remove them while we're still in the document.
+  if (mRemoteBrowser) {
+    mRemoteBrowser->RemoveWindowListeners();
+  }
+
   nsCOMPtr<nsIDocument> doc;
   bool dynamicSubframeRemoval = false;
   if (mOwnerContent) {
     doc = mOwnerContent->OwnerDoc();
     dynamicSubframeRemoval = !mIsTopLevelContent && !doc->InUnlinkOrDeletion();
     doc->SetSubDocumentFor(mOwnerContent, nullptr);
 
     SetOwnerContent(nullptr);
@@ -2053,18 +2058,17 @@ nsFrameLoader::GetWindowDimensions(nsInt
 NS_IMETHODIMP
 nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame)
 {
   if (mRemoteFrame) {
     if (mRemoteBrowser) {
       ScreenIntSize size = aIFrame->GetSubdocumentSize();
       nsIntRect dimensions;
       NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
-      nsIntPoint chromeDisp = aIFrame->GetChromeDisplacement();
-      mRemoteBrowser->UpdateDimensions(dimensions, size, chromeDisp);
+      mRemoteBrowser->UpdateDimensions(dimensions, size);
     }
     return NS_OK;
   }
   UpdateBaseWindowPositionAndSize(aIFrame);
   return NS_OK;
 }
 
 void
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -224,16 +224,19 @@ public:
    */
   void ApplySandboxFlags(uint32_t sandboxFlags);
 
   void GetURL(nsString& aURL);
 
   void ActivateUpdateHitRegion();
   void DeactivateUpdateHitRegion();
 
+  // Properly retrieves documentSize of any subdocument type.
+  nsresult GetWindowDimensions(nsIntRect& aRect);
+
 private:
 
   void SetOwnerContent(mozilla::dom::Element* aContent);
 
   bool ShouldUseRemoteProcess();
 
   /**
    * Is this a frameloader for a bona fide <iframe mozbrowser> or
@@ -279,19 +282,16 @@ private:
 
   /**
    * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
    * initialize mDocShell.
    */
   nsresult MaybeCreateDocShell();
   nsresult EnsureMessageManager();
 
-  // Properly retrieves documentSize of any subdocument type.
-  nsresult GetWindowDimensions(nsIntRect& aRect);
-
   // Updates the subdocument position and size. This gets called only
   // when we have our own in-process DocShell.
   void UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame);
   nsresult CheckURILoad(nsIURI* aURI);
   void FireErrorEvent();
   nsresult ReallyStartLoadingInternal();
 
   // Return true if remote browser created; nothing else to do
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -579,17 +579,17 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWind
   mMayHavePointerEnterLeaveEventListener(false),
   mIsModalContentWindow(false),
   mIsActive(false), mIsBackground(false),
   mAudioMuted(false), mAudioVolume(1.0),
   mDesktopModeViewport(false), mInnerWindow(nullptr),
   mOuterWindow(aOuterWindow),
   // Make sure no actual window ends up with mWindowID == 0
   mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false),
-  mMarkedCCGeneration(0)
+  mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false)
  {}
 
 nsPIDOMWindow::~nsPIDOMWindow() {}
 
 // DialogValueHolder CC goop.
 NS_IMPL_CYCLE_COLLECTION(DialogValueHolder, mValue)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DialogValueHolder)
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -86,16 +86,23 @@
 
 #ifdef XP_WIN
 // Thanks so much, Microsoft! :(
 #ifdef CreateEvent
 #undef CreateEvent
 #endif
 #endif // XP_WIN
 
+#ifdef XP_MACOSX
+// HandlePluginCrashed() and HandlePluginInstantiated() needed from here to
+// fix bug 1147521.  Should later be replaced by proper interface methods,
+// maybe on nsIObjectLoadingContext.
+#include "mozilla/dom/HTMLObjectElement.h"
+#endif
+
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 static const char *kPrefJavaMIME = "plugin.java.mime";
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #ifdef PR_LOGGING
@@ -862,16 +869,20 @@ nsObjectLoadingContent::InstantiatePlugi
   }
 
   nsCOMPtr<nsIRunnable> ev = \
     new nsSimplePluginEvent(thisContent,
                             doc,
                             NS_LITERAL_STRING("PluginInstantiated"));
   NS_DispatchToCurrentThread(ev);
 
+#ifdef XP_MACOSX
+  HTMLObjectElement::HandlePluginInstantiated(thisContent->AsElement());
+#endif
+
   return NS_OK;
 }
 
 void
 nsObjectLoadingContent::GetPluginAttributes(nsTArray<MozPluginParameter>& aAttributes)
 {
   aAttributes = mCachedAttributes;
 }
@@ -2718,24 +2729,29 @@ NS_IMETHODIMP
 nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag,
                                       const nsAString& pluginDumpID,
                                       const nsAString& browserDumpID,
                                       bool submittedCrashReport)
 {
   LOG(("OBJLC [%p]: Plugin Crashed, queuing crash event", this));
   NS_ASSERTION(mType == eType_Plugin, "PluginCrashed at non-plugin type");
 
+  nsCOMPtr<nsIContent> thisContent =
+    do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+
+#ifdef XP_MACOSX
+  HTMLObjectElement::HandlePluginCrashed(thisContent->AsElement());
+#endif
+
   PluginDestroyed();
 
   // Switch to fallback/crashed state, notify
   LoadFallback(eFallbackCrashed, true);
 
   // send nsPluginCrashedEvent
-  nsCOMPtr<nsIContent> thisContent =
-    do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
   // Note that aPluginTag in invalidated after we're called, so copy 
   // out any data we need now.
   nsAutoCString pluginName;
   aPluginTag->GetName(pluginName);
   nsAutoCString pluginFilename;
   aPluginTag->GetFilename(pluginFilename);
 
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -181,16 +181,28 @@ public:
   bool GetAudioMuted() const;
   void SetAudioMuted(bool aMuted);
 
   float GetAudioVolume() const;
   nsresult SetAudioVolume(float aVolume);
 
   float GetAudioGlobalVolume();
 
+  virtual void SetServiceWorkersTestingEnabled(bool aEnabled)
+  {
+    MOZ_ASSERT(IsOuterWindow());
+    mServiceWorkersTestingEnabled = aEnabled;
+  }
+
+  bool GetServiceWorkersTestingEnabled()
+  {
+    MOZ_ASSERT(IsOuterWindow());
+    return mServiceWorkersTestingEnabled;
+  }
+
 protected:
   // Lazily instantiate an about:blank document if necessary, and if
   // we have what it takes to do so.
   void MaybeCreateDoc();
 
   float GetAudioGlobalVolumeInternal(float aVolume);
   void RefreshMediaElements();
 
@@ -793,16 +805,20 @@ protected:
   // this window.
   uint64_t mWindowID;
 
   // This is only used by the inner window. Set to true once we've sent
   // the (chrome|content)-document-global-created notification.
   bool mHasNotifiedGlobalCreated;
 
   uint32_t mMarkedCCGeneration;
+
+  // Let the service workers plumbing know that some feature are enabled while
+  // testing.
+  bool mServiceWorkersTestingEnabled;
 };
 
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMWindow, NS_PIDOMWINDOW_IID)
 
 #ifdef MOZILLA_INTERNAL_API
 PopupControlState
 PushPopupControlState(PopupControlState aState, bool aForce);
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/file_csp_path_matching_incl_query.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1147026 - CSP should ignore query string when checking a resource load</title>
+  </head>
+  <body>
+  <div id="testdiv">blocked</div>
+  <script src="http://test1.example.com/tests/dom/base/test/csp/file_csp_path_matching.js?val=foo"></script>
+</body>
+</html>
--- a/dom/base/test/csp/mochitest.ini
+++ b/dom/base/test/csp/mochitest.ini
@@ -81,16 +81,17 @@ support-files =
   file_CSP_bug941404_xhr.html
   file_CSP_bug941404_xhr.html^headers^
   file_hash_source.html
   file_dual_header_testserver.sjs
   file_hash_source.html^headers^
   file_self_none_as_hostname_confusion.html
   file_self_none_as_hostname_confusion.html^headers^
   file_csp_path_matching.html
+  file_csp_path_matching_incl_query.html
   file_csp_path_matching.js
   file_csp_path_matching_redirect.html
   file_csp_path_matching_redirect_server.sjs
   file_csp_testserver.sjs
   file_report_uri_missing_in_report_only_header.html
   file_report_uri_missing_in_report_only_header.html^headers^
   file_csp_report.html
   file_redirect_content.sjs
--- a/dom/base/test/csp/test_csp_path_matching.html
+++ b/dom/base/test/csp/test_csp_path_matching.html
@@ -74,19 +74,24 @@ var counter = 0;
 var policy;
 
 function loadNextTest() {
   if (counter == policies.length) {
     SimpleTest.finish();
   }
   else {
     policy = policies[counter++];
-    var src = "file_csp_testserver.sjs";
+    var src = "file_csp_testserver.sjs?file=";
     // append the file that should be served
-    src += "?file=" + escape("tests/dom/base/test/csp/file_csp_path_matching.html");
+    src += (counter % 2 == 0)
+               // load url including ref: example.com#foo
+             ? escape("tests/dom/base/test/csp/file_csp_path_matching.html")
+               // load url including query: example.com?val=foo (bug 1147026)
+             : escape("tests/dom/base/test/csp/file_csp_path_matching_incl_query.html");
+
     // append the CSP that should be used to serve the file
     src += "&csp=" + escape("default-src 'none'; script-src " + policy[1]);
 
     document.getElementById("testframe").addEventListener("load", test, false);
     document.getElementById("testframe").src = src;
   }
 }
 
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1520,17 +1520,17 @@ DOMInterfaces = {
         'terminate',
     ],
 },
 
 'WorkerDebuggerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'nativeType': 'mozilla::dom::workers::WorkerDebuggerGlobalScope',
     'implicitJSContext': [
-        'dump', 'global',
+        'dump', 'global', 'reportError',
     ],
 },
 
 'WorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'workers': True,
     'concrete': False,
     'implicitJSContext': [
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -238,26 +238,24 @@ public:
 protected:
   virtual ~StackFrame();
 
   virtual bool IsJSFrame() const
   {
     return false;
   }
 
-  virtual nsresult GetLineno(int32_t* aLineNo)
+  virtual int32_t GetLineno()
   {
-    *aLineNo = mLineno;
-    return NS_OK;
+    return mLineno;
   }
 
-  virtual nsresult GetColNo(int32_t* aColNo)
+  virtual int32_t GetColNo()
   {
-    *aColNo = mColNo;
-    return NS_OK;
+    return mColNo;
   }
 
   nsCOMPtr<nsIStackFrame> mCaller;
   nsCOMPtr<nsIStackFrame> mAsyncCaller;
   nsString mFilename;
   nsString mFunname;
   nsString mAsyncCause;
   int32_t mLineno;
@@ -313,18 +311,18 @@ public:
   NS_IMETHOD GetFormattedStack(nsAString& aStack) override;
   NS_IMETHOD GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame) override;
 
 protected:
   virtual bool IsJSFrame() const override {
     return true;
   }
 
-  virtual nsresult GetLineno(int32_t* aLineNo) override;
-  virtual nsresult GetColNo(int32_t* aColNo) override;
+  virtual int32_t GetLineno() override;
+  virtual int32_t GetColNo() override;
 
 private:
   virtual ~JSStackFrame();
 
   JS::Heap<JSObject*> mStack;
   nsString mFormattedStack;
 
   bool mFilenameInitialized;
@@ -432,29 +430,35 @@ GetValueIfNotCached(JSContext* aCx, JSOb
   JS::ExposeObjectToActiveJS(stack);
 
   aPropGetter(aCx, stack, aValue);
 }
 
 /* readonly attribute AString filename; */
 NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename)
 {
-  NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
+  if (!mStack) {
+    aFilename.Truncate();
+    return NS_OK;
+  }
+
   ThreadsafeAutoJSContext cx;
   JS::Rooted<JSString*> filename(cx);
   bool canCache = false, useCachedValue = false;
   GetValueIfNotCached(cx, mStack, JS::GetSavedFrameSource, mFilenameInitialized,
                       &canCache, &useCachedValue, &filename);
   if (useCachedValue) {
     return StackFrame::GetFilename(aFilename);
   }
 
   nsAutoJSString str;
   if (!str.init(cx, filename)) {
-    return NS_ERROR_OUT_OF_MEMORY;
+    JS_ClearPendingException(cx);
+    aFilename.Truncate();
+    return NS_OK;
   }
   aFilename = str;
 
   if (canCache) {
     mFilename = str;
     mFilenameInitialized = true;
   }
 
@@ -471,32 +475,38 @@ NS_IMETHODIMP StackFrame::GetFilename(ns
   }
 
   return NS_OK;
 }
 
 /* readonly attribute AString name; */
 NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction)
 {
-  NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
+  if (!mStack) {
+    aFunction.Truncate();
+    return NS_OK;
+  }
+
   ThreadsafeAutoJSContext cx;
   JS::Rooted<JSString*> name(cx);
   bool canCache = false, useCachedValue = false;
   GetValueIfNotCached(cx, mStack, JS::GetSavedFrameFunctionDisplayName,
                       mFunnameInitialized, &canCache, &useCachedValue,
                       &name);
 
   if (useCachedValue) {
     return StackFrame::GetName(aFunction);
   }
 
   if (name) {
     nsAutoJSString str;
     if (!str.init(cx, name)) {
-      return NS_ERROR_OUT_OF_MEMORY;
+      JS_ClearPendingException(cx);
+      aFunction.Truncate();
+      return NS_OK;
     }
     aFunction = str;
   } else {
     aFunction.SetIsVoid(true);
   }
 
   if (canCache) {
     mFunname = aFunction;
@@ -514,103 +524,113 @@ NS_IMETHODIMP StackFrame::GetName(nsAStr
   } else {
     aFunction.Assign(mFunname);
   }
 
   return NS_OK;
 }
 
 // virtual
-nsresult
-JSStackFrame::GetLineno(int32_t* aLineNo)
+int32_t
+JSStackFrame::GetLineno()
 {
-  NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
+  if (!mStack) {
+    return 0;
+  }
+
   ThreadsafeAutoJSContext cx;
   uint32_t line;
   bool canCache = false, useCachedValue = false;
   GetValueIfNotCached(cx, mStack, JS::GetSavedFrameLine, mLinenoInitialized,
                       &canCache, &useCachedValue, &line);
 
   if (useCachedValue) {
-    return StackFrame::GetLineno(aLineNo);
+    return StackFrame::GetLineno();
   }
 
-  *aLineNo = line;
-
   if (canCache) {
     mLineno = line;
     mLinenoInitialized = true;
   }
 
-  return NS_OK;
+  return line;
 }
 
 /* readonly attribute int32_t lineNumber; */
 NS_IMETHODIMP StackFrame::GetLineNumber(int32_t* aLineNumber)
 {
-  return GetLineno(aLineNumber);
+  *aLineNumber = GetLineno();
+  return NS_OK;
 }
 
 // virtual
-nsresult
-JSStackFrame::GetColNo(int32_t* aColNo)
+int32_t
+JSStackFrame::GetColNo()
 {
-  NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
+  if (!mStack) {
+    return 0;
+  }
+
   ThreadsafeAutoJSContext cx;
   uint32_t col;
   bool canCache = false, useCachedValue = false;
   GetValueIfNotCached(cx, mStack, JS::GetSavedFrameColumn, mColNoInitialized,
                       &canCache, &useCachedValue, &col);
 
   if (useCachedValue) {
-    return StackFrame::GetColNo(aColNo);
+    return StackFrame::GetColNo();
   }
 
-  *aColNo = col;
-
   if (canCache) {
     mColNo = col;
     mColNoInitialized = true;
   }
 
-  return NS_OK;
+  return col;
 }
 
 /* readonly attribute int32_t columnNumber; */
 NS_IMETHODIMP StackFrame::GetColumnNumber(int32_t* aColumnNumber)
 {
-  return GetColNo(aColumnNumber);
+  *aColumnNumber = GetColNo();
+  return NS_OK;
 }
 
 /* readonly attribute AUTF8String sourceLine; */
 NS_IMETHODIMP StackFrame::GetSourceLine(nsACString& aSourceLine)
 {
   aSourceLine.Truncate();
   return NS_OK;
 }
 
 /* readonly attribute AString asyncCause; */
 NS_IMETHODIMP JSStackFrame::GetAsyncCause(nsAString& aAsyncCause)
 {
-  NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
+  if (!mStack) {
+    aAsyncCause.Truncate();
+    return NS_OK;
+  }
+
   ThreadsafeAutoJSContext cx;
   JS::Rooted<JSString*> asyncCause(cx);
   bool canCache = false, useCachedValue = false;
   GetValueIfNotCached(cx, mStack, JS::GetSavedFrameAsyncCause,
                       mAsyncCauseInitialized, &canCache, &useCachedValue,
                       &asyncCause);
 
   if (useCachedValue) {
     return StackFrame::GetAsyncCause(aAsyncCause);
   }
 
   if (asyncCause) {
     nsAutoJSString str;
     if (!str.init(cx, asyncCause)) {
-      return NS_ERROR_OUT_OF_MEMORY;
+      JS_ClearPendingException(cx);
+      aAsyncCause.Truncate();
+      return NS_OK;
     }
     aAsyncCause = str;
   } else {
     aAsyncCause.SetIsVoid(true);
   }
 
   if (canCache) {
     mAsyncCause = aAsyncCause;
@@ -630,17 +650,21 @@ NS_IMETHODIMP StackFrame::GetAsyncCause(
   }
 
   return NS_OK;
 }
 
 /* readonly attribute nsIStackFrame asyncCaller; */
 NS_IMETHODIMP JSStackFrame::GetAsyncCaller(nsIStackFrame** aAsyncCaller)
 {
-  NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
+  if (!mStack) {
+    *aAsyncCaller = nullptr;
+    return NS_OK;
+  }
+
   ThreadsafeAutoJSContext cx;
   JS::Rooted<JSObject*> asyncCallerObj(cx);
   bool canCache = false, useCachedValue = false;
   GetValueIfNotCached(cx, mStack, JS::GetSavedFrameAsyncParent,
                       mAsyncCallerInitialized, &canCache, &useCachedValue,
                       &asyncCallerObj);
 
   if (useCachedValue) {
@@ -663,17 +687,21 @@ NS_IMETHODIMP StackFrame::GetAsyncCaller
 {
   NS_IF_ADDREF(*aAsyncCaller = mAsyncCaller);
   return NS_OK;
 }
 
 /* readonly attribute nsIStackFrame caller; */
 NS_IMETHODIMP JSStackFrame::GetCaller(nsIStackFrame** aCaller)
 {
-  NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
+  if (!mStack) {
+    *aCaller = nullptr;
+    return NS_OK;
+  }
+
   ThreadsafeAutoJSContext cx;
   JS::Rooted<JSObject*> callerObj(cx);
   bool canCache = false, useCachedValue = false;
   GetValueIfNotCached(cx, mStack, JS::GetSavedFrameParent, mCallerInitialized,
                       &canCache, &useCachedValue, &callerObj);
 
   if (useCachedValue) {
     return StackFrame::GetCaller(aCaller);
@@ -701,17 +729,21 @@ NS_IMETHODIMP JSStackFrame::GetCaller(ns
 NS_IMETHODIMP StackFrame::GetCaller(nsIStackFrame** aCaller)
 {
   NS_IF_ADDREF(*aCaller = mCaller);
   return NS_OK;
 }
 
 NS_IMETHODIMP JSStackFrame::GetFormattedStack(nsAString& aStack)
 {
-  NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
+  if (!mStack) {
+    aStack.Truncate();
+    return NS_OK;
+  }
+
   // Sadly we can't use GetValueIfNotCached here, because our getter
   // returns bool, not JS::SavedFrameResult.  Maybe it's possible to
   // make the templates more complicated to deal, but in the meantime
   // let's just inline GetValueIfNotCached here.
   ThreadsafeAutoJSContext cx;
 
   // Allow caching if cx and stack are same-compartment.  Otherwise take the
   // slow path.
@@ -722,22 +754,26 @@ NS_IMETHODIMP JSStackFrame::GetFormatted
     return NS_OK;
   }
 
   JS::ExposeObjectToActiveJS(mStack);
   JS::Rooted<JSObject*> stack(cx, mStack);
 
   JS::Rooted<JSString*> formattedStack(cx);
   if (!JS::StringifySavedFrameStack(cx, stack, &formattedStack)) {
-    return NS_ERROR_UNEXPECTED;
+    JS_ClearPendingException(cx);
+    aStack.Truncate();
+    return NS_OK;
   }
 
   nsAutoJSString str;
   if (!str.init(cx, formattedStack)) {
-    return NS_ERROR_OUT_OF_MEMORY;
+    JS_ClearPendingException(cx);
+    aStack.Truncate();
+    return NS_OK;
   }
 
   aStack = str;
 
   if (canCache) {
     mFormattedStack = str;
     mFormattedStackInitialized = true;
   }
@@ -782,19 +818,17 @@ NS_IMETHODIMP StackFrame::ToString(nsACS
   nsString funname;
   rv = GetName(funname);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (funname.IsEmpty()) {
     funname.AssignLiteral("<TOP_LEVEL>");
   }
 
-  int32_t lineno;
-  rv = GetLineno(&lineno);
-  NS_ENSURE_SUCCESS(rv, rv);
+  int32_t lineno = GetLineno();
 
   static const char format[] = "%s frame :: %s :: %s :: line %d";
   _retval.AppendPrintf(format, frametype,
                        NS_ConvertUTF16toUTF8(filename).get(),
                        NS_ConvertUTF16toUTF8(funname).get(),
                        lineno);
   return NS_OK;
 }
--- a/dom/canvas/test/webgl-mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest.ini
@@ -12,17 +12,17 @@ fail-if = (os == 'b2g')
 [webgl-mochitest/test_draw.html]
 [webgl-mochitest/test_fb_param.html]
 [webgl-mochitest/test_fb_param_crash.html]
 [webgl-mochitest/test_hidden_alpha.html]
 skip-if = (os == 'b2g') || buildapp == 'mulet' # Mulet - bug 1093639 (crashes in libLLVM-3.0.so)
 [webgl-mochitest/test_implicit_color_buffer_float.html]
 [webgl-mochitest/test_highp_fs.html]
 [webgl-mochitest/test_no_arr_points.html]
-skip-if = android_version == '10' #Android 2.3 aws only; bug 1030942
+skip-if = android_version == '10' || android_version == '18' #Android 2.3 and 4.3 aws only; bug 1030942
 [webgl-mochitest/test_noprog_draw.html]
 [webgl-mochitest/test_privileged_exts.html]
 [webgl-mochitest/test_texsubimage_float.html]
 [webgl-mochitest/test_webgl_available.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 #[webgl-mochitest/test_webgl_color_buffer_float.html]
 # We haven't cleaned up the Try results yet, but let's get this on the books first.
 [webgl-mochitest/test_webgl_conformance.html]
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -1171,17 +1171,17 @@ ContentEventHandler::OnQueryCharacterAtP
     // there is no character at the point.
     aEvent->mReply.mOffset = WidgetQueryContentEvent::NOT_FOUND;
     aEvent->mSucceeded = true;
     return NS_OK;
   }
   nsPoint ptInTarget = ptInRoot + rootFrame->GetOffsetToCrossDoc(targetFrame);
   int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
   int32_t targetAPD = targetFrame->PresContext()->AppUnitsPerDevPixel();
-  ptInTarget = ptInTarget.ConvertAppUnits(rootAPD, targetAPD);
+  ptInTarget = ptInTarget.ScaleToOtherAppUnits(rootAPD, targetAPD);
 
   nsTextFrame* textframe = static_cast<nsTextFrame*>(targetFrame);
   nsIFrame::ContentOffsets contentOffsets =
     textframe->GetCharacterOffsetAtFramePoint(ptInTarget);
   NS_ENSURE_TRUE(contentOffsets.content, NS_ERROR_FAILURE);
   uint32_t offset;
   rv = GetFlatTextOffsetOfRange(mRootContent, contentOffsets.content,
                                 contentOffsets.offset, &offset,
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -18,16 +18,17 @@
 #include "nsFormSubmission.h"
 #include "nsIObjectFrame.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsIWidget.h"
 #include "nsContentUtils.h"
 #ifdef XP_MACOSX
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/Event.h"
+#include "nsFocusManager.h"
 #endif
 
 namespace mozilla {
 namespace dom {
 
 HTMLObjectElement::HTMLObjectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
                                      FromParser aFromParser)
   : nsGenericHTMLFormElement(aNodeInfo),
@@ -146,29 +147,68 @@ public:
 private:
   nsCOMPtr<nsIWidget> mWidget;
   nsCOMPtr<Element> mElement;
 };
 
 void
 HTMLObjectElement::OnFocusBlurPlugin(Element* aElement, bool aFocus)
 {
+  // In general we don't want to call nsIWidget::SetPluginFocused() for any
+  // Element that doesn't have a plugin running.  But if SetPluginFocused(true)
+  // was just called for aElement while it had a plugin running, we want to
+  // make sure nsIWidget::SetPluginFocused(false) gets called for it now, even
+  // if aFocus is true.
+  if (aFocus) {
+    nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(aElement);
+    bool hasRunningPlugin = false;
+    if (olc) {
+      olc->GetHasRunningPlugin(&hasRunningPlugin);
+    }
+    if (!hasRunningPlugin) {
+      aFocus = false;
+    }
+  }
+
   if (aFocus || aElement == sLastFocused) {
     if (!aFocus) {
       sLastFocused = nullptr;
     }
     nsIWidget* widget = GetWidget(aElement);
     if (widget) {
       nsContentUtils::AddScriptRunner(
         new PluginFocusSetter(widget, aFocus ? aElement : nullptr));
     }
   }
 }
 
 void
+HTMLObjectElement::HandlePluginCrashed(Element* aElement)
+{
+  OnFocusBlurPlugin(aElement, false);
+}
+
+void
+HTMLObjectElement::HandlePluginInstantiated(Element* aElement)
+{
+  // If aElement is already focused when a plugin is instantiated, we need
+  // to initiate a call to nsIWidget::SetPluginFocused(true).  Otherwise
+  // keyboard input won't work in a click-to-play plugin until aElement
+  // loses focus and regains it.
+  nsIContent* focusedContent = nullptr;
+  nsFocusManager *fm = nsFocusManager::GetFocusManager();
+  if (fm) {
+    focusedContent = fm->GetFocusedContent();
+  }
+  if (SameCOMIdentity(focusedContent, aElement)) {
+    OnFocusBlurPlugin(aElement, true);
+  }
+}
+
+void
 HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
                                          WidgetEvent* aEvent)
 {
   if (!aEvent->mFlags.mIsTrusted) {
     return;
   }
   switch (aEvent->message) {
     case NS_FOCUS_CONTENT: {
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -31,16 +31,18 @@ public:
   virtual int32_t TabIndexDefault() override;
 
 #ifdef XP_MACOSX
   // nsIDOMEventTarget
   NS_IMETHOD PostHandleEvent(EventChainPostVisitor& aVisitor) override;
   // Helper methods
   static void OnFocusBlurPlugin(Element* aElement, bool aFocus);
   static void HandleFocusBlurPlugin(Element* aElement, WidgetEvent* aEvent);
+  static void HandlePluginCrashed(Element* aElement);
+  static void HandlePluginInstantiated(Element* aElement);
   // Weak pointer. Null if last action was blur.
   static Element* sLastFocused;
 #endif
 
   // Element
   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
 
   // nsIDOMHTMLObjectElement
--- a/dom/html/test/forms/mochitest.ini
+++ b/dom/html/test/forms/mochitest.ini
@@ -23,23 +23,23 @@ skip-if = buildapp == 'mulet'
 skip-if = buildapp == 'mulet'
 [test_input_attributes_reflection.html]
 [test_input_autocomplete.html]
 [test_input_color_input_change_events.html]
 skip-if = buildapp == 'mulet'
 [test_input_color_picker_initial.html]
 skip-if = buildapp == 'mulet'
 [test_input_color_picker_popup.html]
-skip-if = buildapp == 'mulet'
+skip-if = buildapp == 'mulet' || android_version == '18' # Android, bug 1147974
 [test_input_color_picker_update.html]
-skip-if = buildapp == 'mulet'
+skip-if = buildapp == 'mulet' || android_version == '18' # Android, bug 1147974
 [test_input_defaultValue.html]
 [test_input_email.html]
 [test_input_event.html]
-skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop and mulet specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') || android_version == '18' #Bug 931116, b2g desktop and mulet specific, initial triage; on Android, bug 1147974
 [test_input_file_picker.html]
 skip-if = buildapp == 'b2g' # b2g(5 failures out of 139 and timing out, bug 901581) b2g-debug(5 failures out of 139 and timing out, bug 901581) b2g-desktop(5 failures out of 139 and timing out, bug 901581)
 [test_input_list_attribute.html]
 [test_input_number_l10n.html]
 # We don't build ICU for Firefox for Android or Firefox OS:
 skip-if = buildapp == 'mulet' || os == "android" || appname == "b2g"
 [test_input_number_key_events.html]
 [test_input_number_mouse_events.html]
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -45,17 +45,17 @@ interface nsIFile;
 interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsITranslationNodeList;
 interface nsIJSRAIIHelper;
 interface nsIContentPermissionRequest;
 
-[scriptable, uuid(400db885-c2b8-4bf1-bc12-1dadcb08ad12)]
+[scriptable, uuid(7f2f44ab-2857-4cc2-8c9d-3d9816f5a4d6)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1752,16 +1752,21 @@ interface nsIDOMWindowUtils : nsISupport
    * Controls the amount of chrome that should be visible on each side of
    * the window. Works like the chromemargin xul:window attribute.
    * This should only be used with non-XUL windows.
    */
   void setChromeMargin(in int32_t aTop,
                        in int32_t aRight,
                        in int32_t aBottom,
                        in int32_t aLeft);
+
+  /**
+   * Enable some service workers testing features.
+   */
+  attribute boolean serviceWorkersTestingEnabled;
 };
 
 [scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)]
 interface nsITranslationNodeList : nsISupports {
   readonly attribute unsigned long length;
   nsIDOMNode item(in unsigned long index);
 
   // A translation root is a block element, or an inline element
--- a/dom/ipc/FilePickerParent.cpp
+++ b/dom/ipc/FilePickerParent.cpp
@@ -50,20 +50,20 @@ FilePickerParent::~FilePickerParent()
 // process. This runnable stat()s the file off the main thread.
 //
 // We run code in three places:
 // 1. The main thread calls Dispatch() to start the runnable.
 // 2. The stream transport thread stat()s the file in Run() and then dispatches
 // the same runnable on the main thread.
 // 3. The main thread sends the results over IPC.
 FilePickerParent::FileSizeAndDateRunnable::FileSizeAndDateRunnable(FilePickerParent *aFPParent,
-                                                                   nsCOMArray<nsIDOMFile>& aDomfiles)
+                                                                   nsTArray<nsRefPtr<FileImpl>>& aFiles)
  : mFilePickerParent(aFPParent)
 {
-  mDomfiles.SwapElements(aDomfiles);
+  mFiles.SwapElements(aFiles);
 }
 
 bool
 FilePickerParent::FileSizeAndDateRunnable::Dispatch()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mEventTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
@@ -77,26 +77,26 @@ FilePickerParent::FileSizeAndDateRunnabl
 
 NS_IMETHODIMP
 FilePickerParent::FileSizeAndDateRunnable::Run()
 {
   // If we're on the main thread, then that means we're done. Just send the
   // results.
   if (NS_IsMainThread()) {
     if (mFilePickerParent) {
-      mFilePickerParent->SendFiles(mDomfiles);
+      mFilePickerParent->SendFiles(mFiles);
     }
     return NS_OK;
   }
 
   // We're not on the main thread, so do the stat().
-  for (unsigned i = 0; i < mDomfiles.Length(); i++) {
-    uint64_t size, lastModified;
-    mDomfiles[i]->GetSize(&size);
-    mDomfiles[i]->GetMozLastModifiedDate(&lastModified);
+  for (unsigned i = 0; i < mFiles.Length(); i++) {
+    ErrorResult rv;
+    mFiles[i]->GetSize(rv);
+    mFiles[i]->GetLastModified(rv);
   }
 
   // Dispatch ourselves back on the main thread.
   if (NS_FAILED(NS_DispatchToMainThread(this))) {
     // It's hard to see how we can recover gracefully in this case. The child
     // process is waiting for an IPC, but that can only happen on the main
     // thread.
     MOZ_CRASH();
@@ -106,24 +106,24 @@ FilePickerParent::FileSizeAndDateRunnabl
 
 void
 FilePickerParent::FileSizeAndDateRunnable::Destroy()
 {
   mFilePickerParent = nullptr;
 }
 
 void
-FilePickerParent::SendFiles(const nsCOMArray<nsIDOMFile>& aDomfiles)
+FilePickerParent::SendFiles(const nsTArray<nsRefPtr<FileImpl>>& aFiles)
 {
   nsIContentParent* parent = TabParent::GetFrom(Manager())->Manager();
   InfallibleTArray<PBlobParent*> files;
 
-  for (unsigned i = 0; i < aDomfiles.Length(); i++) {
-    BlobParent* blob = parent->GetOrCreateActorForBlob(
-      static_cast<File*>(aDomfiles[i]));
+  for (unsigned i = 0; i < aFiles.Length(); i++) {
+    nsRefPtr<File> file = new File(nullptr, aFiles[i]);
+    BlobParent* blob = parent->GetOrCreateActorForBlob(file);
     if (blob) {
       files.AppendElement(blob);
     }
   }
 
   InputFiles infiles;
   infiles.filesParent().SwapElements(files);
   unused << Send__delete__(this, infiles, mResult);
@@ -134,47 +134,43 @@ FilePickerParent::Done(int16_t aResult)
 {
   mResult = aResult;
 
   if (mResult != nsIFilePicker::returnOK) {
     unused << Send__delete__(this, void_t(), mResult);
     return;
   }
 
-  nsCOMArray<nsIDOMFile> domfiles;
+  nsTArray<nsRefPtr<FileImpl>> files;
   if (mMode == nsIFilePicker::modeOpenMultiple) {
     nsCOMPtr<nsISimpleEnumerator> iter;
     NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
 
     nsCOMPtr<nsISupports> supports;
     bool loop = true;
     while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
       iter->GetNext(getter_AddRefs(supports));
       if (supports) {
         nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
 
-        // A null parent is fine because File are not used in this process
-        // but only in the child.
-        nsCOMPtr<nsIDOMFile> domfile = File::CreateFromFile(nullptr, file);
-        domfiles.AppendElement(domfile);
+        nsRefPtr<FileImpl> fileimpl = new FileImplFile(file);
+        files.AppendElement(fileimpl);
       }
     }
   } else {
     nsCOMPtr<nsIFile> file;
     mFilePicker->GetFile(getter_AddRefs(file));
     if (file) {
-      // A null parent is fine because File are not used in this process
-      // but only in the child.
-      nsCOMPtr<nsIDOMFile> domfile = File::CreateFromFile(nullptr, file);
-      domfiles.AppendElement(domfile);
+      nsRefPtr<FileImpl> fileimpl = new FileImplFile(file);
+      files.AppendElement(fileimpl);
     }
   }
 
   MOZ_ASSERT(!mRunnable);
-  mRunnable = new FileSizeAndDateRunnable(this, domfiles);
+  mRunnable = new FileSizeAndDateRunnable(this, files);
   if (!mRunnable->Dispatch()) {
     unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
   }
 }
 
 bool
 FilePickerParent::CreateFilePicker()
 {
--- a/dom/ipc/FilePickerParent.h
+++ b/dom/ipc/FilePickerParent.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_FilePickerParent_h
 #define mozilla_dom_FilePickerParent_h
 
 #include "nsIDOMFile.h"
 #include "nsIEventTarget.h"
 #include "nsIFilePicker.h"
 #include "nsCOMArray.h"
 #include "nsThreadUtils.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/PFilePickerParent.h"
 
 namespace mozilla {
 namespace dom {
 
 class FilePickerParent : public PFilePickerParent
 {
  public:
@@ -24,17 +25,17 @@ class FilePickerParent : public PFilePic
                    const int16_t& aMode)
   : mTitle(aTitle)
   , mMode(aMode)
   {}
 
   virtual ~FilePickerParent();
 
   void Done(int16_t aResult);
-  void SendFiles(const nsCOMArray<nsIDOMFile>& aDomfiles);
+  void SendFiles(const nsTArray<nsRefPtr<FileImpl>>& aDomfiles);
 
   virtual bool RecvOpen(const int16_t& aSelectedType,
                         const bool& aAddToRecentDocs,
                         const nsString& aDefaultFile,
                         const nsString& aDefaultExtension,
                         InfallibleTArray<nsString>&& aFilters,
                         InfallibleTArray<nsString>&& aFilterNames,
                         const nsString& aDisplayDirectory) override;
@@ -59,21 +60,21 @@ class FilePickerParent : public PFilePic
   };
 
  private:
   bool CreateFilePicker();
 
   class FileSizeAndDateRunnable : public nsRunnable
   {
     FilePickerParent* mFilePickerParent;
-    nsCOMArray<nsIDOMFile> mDomfiles;
+    nsTArray<nsRefPtr<FileImpl>> mFiles;
     nsCOMPtr<nsIEventTarget> mEventTarget;
 
   public:
-    FileSizeAndDateRunnable(FilePickerParent *aFPParent, nsCOMArray<nsIDOMFile>& aDomfiles);
+    FileSizeAndDateRunnable(FilePickerParent *aFPParent, nsTArray<nsRefPtr<FileImpl>>& aFiles);
     bool Dispatch();
     NS_IMETHOD Run();
     void Destroy();
   };
 
   nsRefPtr<FileSizeAndDateRunnable> mRunnable;
   nsRefPtr<FilePickerShownCallback> mCallback;
   nsCOMPtr<nsIFilePicker> mFilePicker;
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -50,17 +50,17 @@ using class mozilla::WidgetTouchEvent fr
 using struct mozilla::dom::RemoteDOMEvent from "mozilla/dom/TabMessageUtils.h";
 using mozilla::dom::ScreenOrientation from "mozilla/dom/ScreenOrientation.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using mozilla::CSSPoint from "Units.h";
 using mozilla::CSSToScreenScale from "Units.h";
 using mozilla::CommandInt from "mozilla/EventForwards.h";
 using mozilla::Modifiers from "mozilla/EventForwards.h";
 using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.h";
-using mozilla::WritingMode from "WritingModes.h";
+using mozilla::WritingMode from "mozilla/WritingModes.h";
 using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 struct NativeKeyBinding
 {
   CommandInt[] singleLineCommands;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2021,18 +2021,18 @@ TabChild::RecvUpdateDimensions(const nsI
                       && (size.width != 0 && size.height != 0);
     if (initialSizing) {
       mHasValidInnerSize = true;
     }
 
     mOrientation = orientation;
     ScreenIntSize oldScreenSize = mInnerSize;
     mInnerSize = size;
-    mWidget->Resize(0, 0, size.width, size.height,
-                    true);
+    mWidget->Resize(rect.x + chromeDisp.x, rect.y + chromeDisp.y, size.width, size.height,
+                     true);
 
     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
     baseWin->SetPositionAndSize(0, 0, size.width, size.height,
                                 true);
 
     if (initialSizing && mContentDocumentIsDisplayed) {
       // If this is the first time we're getting a valid mInnerSize, and the
       // before-first-paint event has already been handled, then we need to set
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -75,16 +75,17 @@
 #include "LoadContext.h"
 #include "nsNetCID.h"
 #include "nsIAuthInformation.h"
 #include "nsIAuthPromptCallback.h"
 #include "nsAuthInformationHolder.h"
 #include "nsICancelable.h"
 #include "gfxPrefs.h"
 #include "nsILoginManagerPrompter.h"
+#include "nsPIWindowRoot.h"
 #include <algorithm>
 
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 using namespace mozilla::services;
 using namespace mozilla::widget;
@@ -319,21 +320,47 @@ void
 TabParent::CacheFrameLoader(nsFrameLoader* aFrameLoader)
 {
   mFrameLoader = aFrameLoader;
 }
 
 void
 TabParent::SetOwnerElement(Element* aElement)
 {
+  // If we held previous content then unregister for its events.
+  RemoveWindowListeners();
+
+  // Update to the new content, and register to listen for events from it.
   mFrameElement = aElement;
+  if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
+    nsCOMPtr<nsPIDOMWindow> window = mFrameElement->OwnerDoc()->GetWindow();
+    nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
+    if (eventTarget) {
+      eventTarget->AddEventListener(NS_LITERAL_STRING("MozUpdateWindowPos"),
+                                    this, false, false);
+    }
+  }
+
   TryCacheDPIAndScale();
 }
 
 void
+TabParent::RemoveWindowListeners()
+{
+  if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
+    nsCOMPtr<nsPIDOMWindow> window = mFrameElement->OwnerDoc()->GetWindow();
+    nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
+    if (eventTarget) {
+      eventTarget->RemoveEventListener(NS_LITERAL_STRING("MozUpdateWindowPos"),
+                                       this, false);
+    }
+  }
+}
+
+void
 TabParent::GetAppType(nsAString& aOut)
 {
   aOut.Truncate();
   nsCOMPtr<Element> elem = do_QueryInterface(mFrameElement);
   if (!elem) {
     return;
   }
 
@@ -874,34 +901,41 @@ TabParent::RecvSetDimensions(const uint3
     return true;
   }
 
   MOZ_ASSERT(false, "Unknown flags!");
   return false;
 }
 
 void
-TabParent::UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size,
-                            const nsIntPoint& aChromeDisp)
+TabParent::UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size)
 {
   if (mIsDestroyed) {
     return;
   }
   hal::ScreenConfiguration config;
   hal::GetCurrentScreenConfiguration(&config);
   ScreenOrientation orientation = config.orientation();
 
   if (!mUpdatedDimensions || mOrientation != orientation ||
       mDimensions != size || !mRect.IsEqualEdges(rect)) {
+    nsCOMPtr<nsIWidget> widget = GetWidget();
+    nsIntRect contentRect = rect;
+    if (widget) {
+      contentRect.x += widget->GetClientOffset().x;
+      contentRect.y += widget->GetClientOffset().y;
+    }
+
     mUpdatedDimensions = true;
-    mRect = rect;
+    mRect = contentRect;
     mDimensions = size;
     mOrientation = orientation;
 
-    unused << SendUpdateDimensions(mRect, mDimensions, mOrientation, aChromeDisp);
+    nsIntPoint chromeOffset = -LayoutDevicePixel::ToUntyped(GetChildProcessOffset());
+    unused << SendUpdateDimensions(mRect, mDimensions, mOrientation, chromeOffset);
   }
 }
 
 void
 TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics)
 {
   if (!mIsDestroyed) {
     unused << SendUpdateFrame(aFrameMetrics);
@@ -2728,16 +2762,37 @@ TabParent::AllocPPluginWidgetParent()
 
 bool
 TabParent::DeallocPPluginWidgetParent(mozilla::plugins::PPluginWidgetParent* aActor)
 {
   delete aActor;
   return true;
 }
 
+nsresult
+TabParent::HandleEvent(nsIDOMEvent* aEvent)
+{
+  nsAutoString eventType;
+  aEvent->GetType(eventType);
+
+  if (eventType.EqualsLiteral("MozUpdateWindowPos") && !mIsDestroyed) {
+    // This event is sent when the widget moved.  Therefore we only update
+    // the position.
+    nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+    if (!frameLoader) {
+      return NS_OK;
+    }
+    nsIntRect windowDims;
+    NS_ENSURE_SUCCESS(frameLoader->GetWindowDimensions(windowDims), NS_ERROR_FAILURE);
+    UpdateDimensions(windowDims, mDimensions);
+    return NS_OK;
+  }
+  return NS_OK;
+}
+
 class FakeChannel final : public nsIChannel,
                               public nsIAuthPromptCallback,
                               public nsIInterfaceRequestor,
                               public nsILoadContext
 {
 public:
   FakeChannel(const nsCString& aUri, uint64_t aCallbackId, Element* aElement)
     : mCallbackId(aCallbackId)
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -2,31 +2,32 @@
 /* vim: set sw=4 ts=8 et 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_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
-#include "mozilla/EventForwards.h"
+#include "js/TypeDecls.h"
+#include "mozilla/dom/ipc/IdType.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PFilePickerParent.h"
 #include "mozilla/dom/TabContext.h"
-#include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/EventForwards.h"
+#include "mozilla/WritingModes.h"
 #include "nsCOMPtr.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIBrowserDOMWindow.h"
+#include "nsIDOMEventListener.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsWeakReference.h"
 #include "Units.h"
-#include "WritingModes.h"
-#include "js/TypeDecls.h"
 
 class nsFrameLoader;
 class nsIFrameLoader;
 class nsIContent;
 class nsIPrincipal;
 class nsIURI;
 class nsIWidget;
 class nsILoadContext;
@@ -54,29 +55,32 @@ struct IMENotification;
 namespace dom {
 
 class ClonedMessageData;
 class nsIContentParent;
 class Element;
 struct StructuredCloneData;
 
 class TabParent final : public PBrowserParent
+                      , public nsIDOMEventListener
                       , public nsITabParent
                       , public nsIAuthPromptProvider
                       , public nsISecureBrowserUI
                       , public nsSupportsWeakReference
                       , public TabContext
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
 
     virtual ~TabParent();
 
 public:
     // nsITabParent
     NS_DECL_NSITABPARENT
+    // nsIDOMEventListener interfaces
+    NS_DECL_NSIDOMEVENTLISTENER
 
     TabParent(nsIContentParent* aManager,
               const TabId& aTabId,
               const TabContext& aContext,
               uint32_t aChromeFlags);
     Element* GetOwnerElement() const { return mFrameElement; }
     void SetOwnerElement(Element* aElement);
 
@@ -101,16 +105,18 @@ public:
     }
 
     already_AddRefed<nsILoadContext> GetLoadContext();
 
     nsIXULBrowserWindow* GetXULBrowserWindow();
 
     void Destroy();
 
+    void RemoveWindowListeners();
+
     virtual bool RecvMoveFocus(const bool& aForward) override;
     virtual bool RecvEvent(const RemoteDOMEvent& aEvent) override;
     virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;
     virtual bool RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent) override;
     virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
                                             const nsString& aURL,
                                             const nsString& aName,
                                             const nsString& aFeatures,
@@ -219,18 +225,17 @@ public:
     AllocPColorPickerParent(const nsString& aTitle, const nsString& aInitialColor) override;
     virtual bool DeallocPColorPickerParent(PColorPickerParent* aColorPicker) override;
 
     void LoadURL(nsIURI* aURI);
     // XXX/cjones: it's not clear what we gain by hiding these
     // message-sending functions under a layer of indirection and
     // eating the return values
     void Show(const ScreenIntSize& size, bool aParentIsActive);
-    void UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size,
-                          const nsIntPoint& chromeDisp);
+    void UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size);
     void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
     void UIResolutionChanged();
     void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
                           const mozilla::CSSPoint& aDestination);
     void AcknowledgeScrollUpdate(const ViewID& aScrollId, const uint32_t& aScrollGeneration);
     void HandleDoubleTap(const CSSPoint& aPoint,
                          Modifiers aModifiers,
                          const ScrollableLayerGuid& aGuid);
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -156,8 +156,10 @@ DataContainerEventWarning=Use of DataCon
 # LOCALIZATION NOTE: Do not translate "window.controllers"
 Window_ControllersWarning=window.controllers is deprecated. Do not use it for UA detection.
 ImportXULIntoContentWarning=Importing XUL nodes into a content document is deprecated. This functionality may be removed soon.
 XMLDocumentLoadPrincipalMismatch=Use of document.load forbidden on Documents that come from other Windows. Only the Window in which a Document was created is allowed to call .load on that Document. Preferably, use XMLHttpRequest instead.
 # LOCALIZATION NOTE: Do not translate "IndexedDB".
 IndexedDBTransactionAbortNavigation=An IndexedDB transaction that was not yet complete has been aborted due to page navigation.
 # LOCALIZATION NOTE (WillChangeBudgetWarning): Do not translate Will-change, %1$S,%2$S,%3$S are numbers.
 WillChangeBudgetWarning=Will-change memory consumption is too high. Surface area covers %1$S pixels, budget is the document surface area multiplied by %2$S (%3$S pixels). All occurences of will-change in the document are ignored when over budget.
+# LOCALIZATION NOTE: Do not translate "ServiceWorker".
+HittingMaxWorkersPerDomain=A ServiceWorker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The ServiceWorker is now queued and will be started after some of the other workers have completed.
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -1001,16 +1001,18 @@ MediaCodecReader::DecodeVideoFrameSync(i
                             1, // We don't know the duration.
                             b,
                             bufferInfo.mFlags & MediaCodec::BUFFER_FLAG_SYNCFRAME,
                             -1,
                             mVideoTrack.mRelativePictureRect);
     }
 
     if (v) {
+      // Notify mDecoder that we have decoded a video frame.
+      mDecoder->NotifyDecodedFrames(0, 1, 0);
       VideoQueue().Push(v);
     } else {
       NS_WARNING("Unable to create VideoData");
     }
   }
 
   if ((bufferInfo.mFlags & MediaCodec::BUFFER_FLAG_EOS) ||
       (status == ERROR_END_OF_STREAM)) {
@@ -1812,16 +1814,20 @@ MediaCodecReader::GetCodecOutputData(Tra
         (info.mFlags & MediaCodec::BUFFER_FLAG_EOS)) {
       aBuffer = info;
       aBuffer.mBuffer = aTrack.mOutputBuffers[info.mIndex];
       aTrack.mOutputEndOfStream = true;
       return ERROR_END_OF_STREAM;
     }
 
     if (status == OK) {
+      // Notify mDecoder that we have parsed a video frame.
+      if (&aTrack == &mVideoTrack) {
+        mDecoder->NotifyDecodedFrames(1, 0, 0);
+      }
       if (!IsValidTimestampUs(aThreshold) || info.mTimeUs >= aThreshold) {
         // Get a valid output buffer.
         break;
       } else {
         aTrack.mCodec->releaseOutputBuffer(info.mIndex);
       }
     } else if (status == INFO_OUTPUT_BUFFERS_CHANGED) {
       // Update output buffers of MediaCodec.
--- a/dom/media/omx/MediaOmxCommonDecoder.cpp
+++ b/dom/media/omx/MediaOmxCommonDecoder.cpp
@@ -96,17 +96,23 @@ void
 MediaOmxCommonDecoder::PauseStateMachine()
 {
   MOZ_ASSERT(NS_IsMainThread());
   GetReentrantMonitor().AssertCurrentThreadIn();
   DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
   if (!mDecoderStateMachine) {
     return;
   }
-  mDecoderStateMachine->SetDormant(true);
+  // enter dormant state
+  RefPtr<nsRunnable> event =
+    NS_NewRunnableMethodWithArg<bool>(
+      mDecoderStateMachine,
+      &MediaDecoderStateMachine::SetDormant,
+      true);
+  mDecoderStateMachine->TaskQueue()->Dispatch(event);
 }
 
 void
 MediaOmxCommonDecoder::ResumeStateMachine()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   DECODER_LOG(PR_LOG_DEBUG, ("%s current time %f", __PRETTY_FUNCTION__,
@@ -119,17 +125,23 @@ MediaOmxCommonDecoder::ResumeStateMachin
   mFallbackToStateMachine = true;
   mAudioOffloadPlayer = nullptr;
   int64_t timeUsecs = 0;
   SecondsToUsecs(mCurrentTime, timeUsecs);
   mRequestedSeekTarget = SeekTarget(timeUsecs, SeekTarget::Accurate);
 
   mNextState = mPlayState;
   ChangeState(PLAY_STATE_LOADING);
-  mDecoderStateMachine->SetDormant(false);
+  // exit dormant state
+  RefPtr<nsRunnable> event =
+    NS_NewRunnableMethodWithArg<bool>(
+      mDecoderStateMachine,
+      &MediaDecoderStateMachine::SetDormant,
+      false);
+  mDecoderStateMachine->TaskQueue()->Dispatch(event);
 }
 
 void
 MediaOmxCommonDecoder::AudioOffloadTearDown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
 
--- a/dom/media/test/mochitest.ini
+++ b/dom/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' || (os == 'win' && strictContentSandbox) # strictContentSandbox (Bug 1042735)
+skip-if = buildapp == 'mulet' || (os == 'win' && strictContentSandbox) || android_version == '18' # strictContentSandbox (Bug 1042735)
 support-files =
   320x240.ogv
   320x240.ogv^headers^
   448636.ogv
   448636.ogv^headers^
   VID_0001.ogg
   VID_0001.ogg^headers^
   allowed.sjs
--- a/dom/media/tests/mochitest/identity/mochitest.ini
+++ b/dom/media/tests/mochitest/identity/mochitest.ini
@@ -1,13 +1,13 @@
 [DEFAULT]
 # strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
 # won't run on b2g desktop tests - bug 1119993
 # broken HTTPS on b2g emulator - bug 1135339
-skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || (buildapp == 'b2g' && toolkit != 'gonk') || (buildapp == 'b2g' && toolkit == 'gonk')
+skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18' || (buildapp == 'b2g' && toolkit != 'gonk') || (buildapp == 'b2g' && toolkit == 'gonk')
 support-files =
   /.well-known/idp-proxy/idp.js
 
 [test_idpproxy.html]
 support-files =
   /.well-known/idp-proxy/idp-redirect-http.js
   /.well-known/idp-proxy/idp-redirect-http.js^headers^
   /.well-known/idp-proxy/idp-redirect-http-trick.js
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
 # strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
-skip-if = (os == 'win' && strictContentSandbox) || android_version == '10'
+skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18'
 support-files =
   head.js
   dataChannel.js
   mediaStreamPlayback.js
   network.js
   nonTrickleIce.js
   pc.js
   templates.js
--- a/dom/media/webaudio/blink/Reverb.cpp
+++ b/dom/media/webaudio/blink/Reverb.cpp
@@ -184,17 +184,17 @@ void Reverb::process(const AudioChunk* s
             m_convolvers[i]->process(sourceBusL, sourceBus->mDuration, destinationChannel, destinationBus->mDuration, framesToProcess);
         }
     } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 2) {
         // 1 -> 1 -> 2
         m_convolvers[0]->process(sourceBusL, sourceBus->mDuration, destinationChannelL, destinationBus->mDuration, framesToProcess);
 
         // simply copy L -> R
         float* destinationChannelR = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[1]));
-        bool isCopySafe = destinationChannelL && destinationChannelR && size_t(destinationBus->mDuration) >= framesToProcess && size_t(destinationBus->mDuration) >= framesToProcess;
+        bool isCopySafe = destinationChannelL && destinationChannelR && size_t(destinationBus->mDuration) >= framesToProcess;
         MOZ_ASSERT(isCopySafe);
         if (!isCopySafe)
             return;
         PodCopy(destinationChannelR, destinationChannelL, framesToProcess);
     } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 1) {
         // 1 -> 1 -> 1
         m_convolvers[0]->process(sourceBusL, sourceBus->mDuration, destinationChannelL, destinationBus->mDuration, framesToProcess);
     } else if (numInputChannels == 2 && numReverbChannels == 4 && numOutputChannels == 2) {
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -115,19 +115,19 @@ skip-if = toolkit == 'android' # bug 114
 [test_mediaElementAudioSourceNodeCrossOrigin.html]
 skip-if = toolkit == 'android' # bug 1145816
 [test_mediaStreamAudioDestinationNode.html]
 [test_mediaStreamAudioSourceNode.html]
 [test_mediaStreamAudioSourceNodeCrossOrigin.html]
 [test_mediaStreamAudioSourceNodePassThrough.html]
 [test_mediaStreamAudioSourceNodeResampling.html]
 [test_mixingRules.html]
-skip-if = android_version == '10' # bug 1091965
+skip-if = android_version == '10' || android_version == '18' # bug 1091965
 [test_mozaudiochannel.html]
-skip-if = (toolkit == 'gonk' && !debug) || android_version == '10' # Android: bug 1061675
+skip-if = (toolkit == 'gonk' && !debug) || android_version == '10' || android_version == '18' # Android: bug 1061675
 [test_nodeToParamConnection.html]
 [test_OfflineAudioContext.html]
 [test_offlineDestinationChannelCountLess.html]
 [test_offlineDestinationChannelCountMore.html]
 [test_oscillatorNode.html]
 [test_oscillatorNode2.html]
 [test_oscillatorNodeNegativeFrequency.html]
 [test_oscillatorNodePassThrough.html]
--- a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
+++ b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
@@ -329,17 +329,18 @@ nsNPAPIPluginStreamListener::OnStartBind
                  ("NPP NewStream called: this=%p, npp=%p, mime=%s, seek=%d, type=%d, return=%d, url=%s\n",
                   this, npp, (char *)contentType, seekable, streamType, error, mNPStreamWrapper->mNPStream.url));
   
   if (error != NPERR_NO_ERROR)
     return NS_ERROR_FAILURE;
 
   if (streamType == nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN) {
     SuspendRequest();
-  } else if (!SetStreamType(streamType, false)) {
+  }
+  if (!SetStreamType(streamType, false)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 bool
 nsNPAPIPluginStreamListener::SetStreamType(uint16_t aType, bool aNeedsResume)
@@ -359,16 +360,22 @@ nsNPAPIPluginStreamListener::SetStreamTy
       mStreamType = NP_SEEK;
       // Seekable streams should continue to exist even after OnStopRequest
       // is fired, so we AddRef ourself an extra time and Release when the
       // plugin calls NPN_DestroyStream (CleanUpStream). If the plugin never
       // calls NPN_DestroyStream the stream will be destroyed before the plugin
       // instance is destroyed.
       NS_ADDREF_THIS();
       break;
+    case nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN:
+      MOZ_ASSERT(!aNeedsResume);
+      mStreamType = nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN;
+      // In this case we just want to set mStreamType but we do not want to
+      // execute anything else in this function.
+      return true;
     default:
       return false;
   }
   mStreamState = eStreamTypeSet;
   if (aNeedsResume) {
     if (mStreamListenerPeer) {
       mStreamListenerPeer->OnStreamTypeSet(mStreamType);
     }
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -785,28 +785,27 @@ NPBool nsPluginInstanceOwner::ConvertPoi
   nsPoint windowPosition = AsNsPoint(rootWidget->GetWindowPosition()) / scaleFactor;
 
   // Window size is tab size + chrome size.
   nsIntRect tabContentBounds;
   NS_ENSURE_SUCCESS(puppetWidget->GetBounds(tabContentBounds), false);
   tabContentBounds.ScaleInverseRoundOut(scaleFactor);
   int32_t windowH = tabContentBounds.height + int(chromeSize.y);
 
-  // This is actually relative to window-chrome.
   nsPoint pluginPosition = AsNsPoint(pluginFrame->GetScreenRect().TopLeft());
 
   // Convert (sourceX, sourceY) to 'real' (not PuppetWidget) screen space.
   // In OSX, the Y-axis increases upward, which is the reverse of ours.
   // We want OSX coordinates for window and screen so those equations are swapped.
   nsPoint sourcePoint(sourceX, sourceY);
   nsPoint screenPoint;
   switch (sourceSpace) {
     case NPCoordinateSpacePlugin:
-      screenPoint = sourcePoint + pluginFrame->GetContentRectRelativeToSelf().TopLeft() +
-        chromeSize + pluginPosition + windowPosition;
+      screenPoint = sourcePoint + pluginPosition +
+        pluginFrame->GetContentRectRelativeToSelf().TopLeft() / nsPresContext::AppUnitsPerCSSPixel();
       break;
     case NPCoordinateSpaceWindow:
       screenPoint = nsPoint(sourcePoint.x, windowH-sourcePoint.y) +
         windowPosition;
       break;
     case NPCoordinateSpaceFlippedWindow:
       screenPoint = sourcePoint + windowPosition;
       break;
@@ -819,18 +818,18 @@ NPBool nsPluginInstanceOwner::ConvertPoi
     default:
       return false;
   }
 
   // Convert from screen to dest space.
   nsPoint destPoint;
   switch (destSpace) {
     case NPCoordinateSpacePlugin:
-      destPoint = screenPoint - pluginFrame->GetContentRectRelativeToSelf().TopLeft() -
-        chromeSize - pluginPosition - windowPosition;
+      destPoint = screenPoint - pluginPosition -
+        pluginFrame->GetContentRectRelativeToSelf().TopLeft() / nsPresContext::AppUnitsPerCSSPixel();
       break;
     case NPCoordinateSpaceWindow:
       destPoint = screenPoint - windowPosition;
       destPoint.y = windowH - destPoint.y;
       break;
     case NPCoordinateSpaceFlippedWindow:
       destPoint = screenPoint - windowPosition;
       break;
@@ -1303,25 +1302,25 @@ GetOffsetRootContent(nsIFrame* aFrame)
     if (parent) {
       f = parent;
     } else {
       nsPoint newOffset(0, 0);
       f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
       int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
       if (!f || newAPD != currAPD) {
         // Convert docOffset to the right APD and add it to offset.
-        offset += docOffset.ConvertAppUnits(currAPD, apd);
+        offset += docOffset.ScaleToOtherAppUnits(currAPD, apd);
         docOffset.x = docOffset.y = 0;
       }
       currAPD = newAPD;
       docOffset += newOffset;
     }
   }
 
-  offset += docOffset.ConvertAppUnits(currAPD, apd);
+  offset += docOffset.ScaleToOtherAppUnits(currAPD, apd);
 
   return offset;
 }
 
 LayoutDeviceRect nsPluginInstanceOwner::GetPluginRect()
 {
   // Get the offset of the content relative to the page
   nsRect bounds = mPluginFrame->GetContentRectRelativeToSelf() + GetOffsetRootContent(mPluginFrame);
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -1180,34 +1180,33 @@ nsresult nsPluginStreamListenerPeer::Set
   }
 
   return NS_OK;
 }
 
 void
 nsPluginStreamListenerPeer::OnStreamTypeSet(const int32_t aStreamType)
 {
+  MOZ_ASSERT(aStreamType != STREAM_TYPE_UNKNOWN);
   MOZ_ASSERT(mRequest);
   mStreamType = aStreamType;
   if (!mUseLocalCache && mStreamType >= NP_ASFILE) {
     // check it out if this is not a file channel.
     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(mRequest);
     if (!fileChannel) {
       mUseLocalCache = true;
     }
   }
 
   if (mUseLocalCache) {
     nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest);
     SetupPluginCacheFile(channel);
   }
 }
 
-const int32_t nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN = UINT16_MAX;
-
 nsresult
 nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
 {
   nsresult rv;
   if (!mPStreamListener)
     return NS_ERROR_FAILURE;
 
   nsAutoCString path;
--- a/dom/plugins/base/nsPluginStreamListenerPeer.h
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.h
@@ -126,17 +126,19 @@ public:
     nsCOMArray<nsIRequest> requestsCopy(mRequests);
     for (int32_t i = 0; i < requestsCopy.Count(); ++i)
       requestsCopy[i]->Resume();
   }
 
   // Called by nsNPAPIPluginStreamListener
   void OnStreamTypeSet(const int32_t aStreamType);
 
-  static const int32_t STREAM_TYPE_UNKNOWN;
+  enum {
+    STREAM_TYPE_UNKNOWN = UINT16_MAX
+  };
 
 private:
   nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
   nsresult SetupPluginCacheFile(nsIChannel* channel);
   nsresult GetInterfaceGlobal(const nsIID& aIID, void** result);
 
   nsCOMPtr<nsIURI> mURL;
   nsCString mURLSpec; // Have to keep this member because GetURL hands out char*
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -1390,17 +1390,17 @@ PluginInstanceParent::NPP_NewStream(NPMI
     Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGIN_STREAM_INIT_MS>
         timer(Module()->GetHistogramKey());
 
     NPError err = NPERR_NO_ERROR;
     if (mParent->IsStartingAsync()) {
         MOZ_ASSERT(mSurrogate);
         mSurrogate->AsyncCallDeparting();
         if (SendAsyncNPP_NewStream(bs, NullableString(type), seekable)) {
-            *stype = UINT16_MAX;
+            *stype = nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN;
         } else {
             err = NPERR_GENERIC_ERROR;
         }
     } else {
         bs->SetAlive();
         if (!CallNPP_NewStream(bs, NullableString(type), seekable, &err, stype)) {
             err = NPERR_GENERIC_ERROR;
         }
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -532,16 +532,23 @@ PluginModuleChromeParent::OnProcessLaunc
 #ifdef MOZ_CRASHREPORTER
     // If this fails, we're having IPC troubles, and we're doomed anyways.
     if (!CrashReporterParent::CreateCrashReporter(this)) {
         mShutdown = true;
         Close();
         OnInitFailure();
         return;
     }
+    CrashReporterParent* crashReporter = CrashReporter();
+    if (crashReporter) {
+        crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
+                                           mIsStartingAsync ?
+                                               NS_LITERAL_CSTRING("1") :
+                                               NS_LITERAL_CSTRING("0"));
+    }
 #ifdef XP_WIN
     { // Scope for lock
         mozilla::MutexAutoLock lock(mCrashReporterMutex);
         mCrashReporter = CrashReporter();
     }
 #endif
 #endif
 
@@ -602,16 +609,22 @@ PluginModuleParent::PluginModuleParent(b
     , mTaskFactory(this)
     , mIsFlashPlugin(false)
     , mIsStartingAsync(false)
     , mNPInitialized(false)
     , mAsyncNewRv(NS_ERROR_NOT_INITIALIZED)
 {
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
     mIsStartingAsync = Preferences::GetBool(kAsyncInitPref, false);
+#if defined(MOZ_CRASHREPORTER)
+    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
+                                       mIsStartingAsync ?
+                                           NS_LITERAL_CSTRING("1") :
+                                           NS_LITERAL_CSTRING("0"));
+#endif
 #endif
 }
 
 PluginModuleParent::~PluginModuleParent()
 {
     if (!OkToCleanup()) {
         NS_RUNTIMEABORT("unsafe destruction");
     }
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -403,22 +403,26 @@ nsCSPHostSrc::permits(nsIURI* aUri, cons
   else if (!mHost.Equals(NS_ConvertUTF8toUTF16(uriHost))) {
     return false;
   }
 
   // 4.9) Path matching: If there is a path, we have to enforce
   // path-level matching, unless the channel got redirected, see:
   // http://www.w3.org/TR/CSP11/#source-list-paths-and-redirects
   if (!aWasRedirected && !mPath.IsEmpty()) {
-    // cloning uri so we can ignore the ref
-    nsCOMPtr<nsIURI> uri;
-    aUri->CloneIgnoringRef(getter_AddRefs(uri));
-
+    // converting aUri into nsIURL so we can strip query and ref
+    // example.com/test#foo     -> example.com/test
+    // example.com/test?val=foo -> example.com/test
+    nsCOMPtr<nsIURL> url = do_QueryInterface(aUri);
+    if (!url) {
+      NS_ASSERTION(false, "can't QI into nsIURI");
+      return false;
+    }
     nsAutoCString uriPath;
-    rv = uri->GetPath(uriPath);
+    rv = url->GetFilePath(uriPath);
     NS_ENSURE_SUCCESS(rv, false);
     // check if the last character of mPath is '/'; if so
     // we just have to check loading resource is within
     // the allowed path.
     if (mPath.Last() == '/') {
       if (!StringBeginsWith(NS_ConvertUTF8toUTF16(uriPath), mPath)) {
         return false;
       }
--- a/dom/svg/test/mochitest.ini
+++ b/dom/svg/test/mochitest.ini
@@ -56,16 +56,17 @@ skip-if = true
 [test_pathAnimInterpolation.xhtml]
 [test_pathLength.html]
 [test_pathSeg.xhtml]
 [test_pointAtLength.xhtml]
 [test_pointer-events-1a.xhtml]
 [test_pointer-events-1b.xhtml]
 [test_pointer-events-2.xhtml]
 [test_pointer-events-3.xhtml]
+skip-if = android_version == '18' # bug 1147994
 [test_pointer-events-4.xhtml]
 [test_pointer-events-5.xhtml]
 [test_pointer-events-6.xhtml]
 [test_pointer-events-7.xhtml]
 [test_scientific.html]
 [test_selectSubString.xhtml]
 [test_stroke-linecap-hit-testing.xhtml]
 [test_SVGLengthList-2.xhtml]
--- a/dom/webidl/WorkerDebuggerGlobalScope.webidl
+++ b/dom/webidl/WorkerDebuggerGlobalScope.webidl
@@ -2,17 +2,23 @@
 /* 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/. */
 
 [Global=(WorkerDebugger), Exposed=WorkerDebugger]
 interface WorkerDebuggerGlobalScope : EventTarget {
   readonly attribute object global;
 
+  void enterEventLoop();
+
+  void leaveEventLoop();
+
   void postMessage(DOMString message);
 
   attribute EventHandler onmessage;
+
+  void reportError(DOMString message);
 };
 
 // So you can debug while you debug
 partial interface WorkerDebuggerGlobalScope {
   void dump(optional DOMString string);
 };
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -9,28 +9,30 @@
 #include "nsIChannel.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIDocument.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIObserverService.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptContext.h"
+#include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISupportsPriority.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsPIDOMWindow.h"
 
 #include <algorithm>
 #include "BackgroundChild.h"
 #include "GeckoProfiler.h"
 #include "jsfriendapi.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
+#include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/WorkerBinding.h"
@@ -1409,16 +1411,22 @@ RuntimeService::RegisterWorker(JSContext
     if (mShuttingDown) {
       JS_ReportError(aCx, "Cannot create worker during shutdown!");
       return false;
     }
   }
 
   nsCString sharedWorkerScriptSpec;
 
+  const bool isServiceWorker = aWorkerPrivate->IsServiceWorker();
+  if (isServiceWorker) {
+    AssertIsOnMainThread();
+    Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_ATTEMPTS, 1);
+  }
+
   bool isSharedOrServiceWorker = aWorkerPrivate->IsSharedWorker() ||
                                  aWorkerPrivate->IsServiceWorker();
   if (isSharedOrServiceWorker) {
     AssertIsOnMainThread();
 
     nsCOMPtr<nsIURI> scriptURI = aWorkerPrivate->GetResolvedScriptURI();
     NS_ASSERTION(scriptURI, "Null script URI!");
 
@@ -1456,16 +1464,29 @@ RuntimeService::RegisterWorker(JSContext
 
     queued = gMaxWorkersPerDomain &&
              domainInfo->ActiveWorkerCount() >= gMaxWorkersPerDomain &&
              !domain.IsEmpty() &&
              !exemptFromPerDomainMax;
 
     if (queued) {
       domainInfo->mQueuedWorkers.AppendElement(aWorkerPrivate);
+      if (isServiceWorker) {
+        AssertIsOnMainThread();
+        // ServiceWorker spawn gets queued due to hitting max workers per domain
+        // limit so let's log a warning.
+        // Note: aWorkerPrivate->GetDocument() call might result nullptr due to
+        // no window so the message warning will show up in the browser console.
+        nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                        NS_LITERAL_CSTRING("DOM"),
+                                        aWorkerPrivate->GetDocument(),
+                                        nsContentUtils::eDOM_PROPERTIES,
+                                        "HittingMaxWorkersPerDomain");
+        Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_GETS_QUEUED, 1);
+      }
     }
     else if (parent) {
       domainInfo->mChildWorkerCount++;
     }
     else {
       domainInfo->mActiveWorkers.AppendElement(aWorkerPrivate);
     }
 
@@ -1524,16 +1545,20 @@ RuntimeService::RegisterWorker(JSContext
       MOZ_ASSERT(aWorkerPrivate->IsSharedWorker());
     }
   }
 
   if (!queued && !ScheduleWorker(aCx, aWorkerPrivate)) {
     return false;
   }
 
+  if (isServiceWorker) {
+    AssertIsOnMainThread();
+    Telemetry::Accumulate(Telemetry::SERVICE_WORKER_WAS_SPAWNED, 1);
+  }
   return true;
 }
 
 void
 RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
 {
   aWorkerPrivate->AssertIsOnParentThread();
 
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -880,26 +880,30 @@ ServiceWorkerManager::Register(nsIDOMWin
   AssertIsOnMainThread();
 
   // XXXnsm Don't allow chrome callers for now, we don't support chrome
   // ServiceWorkers.
   MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
 
+  nsCOMPtr<nsPIDOMWindow> outerWindow = window->GetOuterWindow();
+  bool serviceWorkersTestingEnabled =
+    outerWindow->GetServiceWorkersTestingEnabled();
+
   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   if (!doc) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIURI> documentURI = doc->GetBaseURI();
 
   bool authenticatedOrigin = false;
-  // FIXME(nsm): Bug 1003991. Disable check when devtools are open.
-  if (Preferences::GetBool("dom.serviceWorkers.testing.enabled")) {
+  if (Preferences::GetBool("dom.serviceWorkers.testing.enabled") ||
+      serviceWorkersTestingEnabled) {
     authenticatedOrigin = true;
   }
 
   nsresult rv;
   if (!authenticatedOrigin) {
     nsAutoCString scheme;
     rv = documentURI->GetScheme(scheme);
     if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1500,30 +1500,33 @@ public:
       if (aFireAtScope && (aTarget || aErrorNumber != JSMSG_OVER_RECURSED)) {
         JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
         NS_ASSERTION(global, "This should never be null!");
 
         nsEventStatus status = nsEventStatus_eIgnore;
         nsIScriptGlobalObject* sgo;
 
         if (aWorkerPrivate) {
-          nsIDOMEventTarget* target = nullptr;
           WorkerGlobalScope* globalScope = nullptr;
           UNWRAP_WORKER_OBJECT(WorkerGlobalScope, global, globalScope);
-          if (globalScope) {
-            MOZ_ASSERT(global == globalScope->GetWrapperPreserveColor());
-            target = static_cast<nsIDOMEventTarget*>(globalScope);
-          } else {
+
+          if (!globalScope) {
             WorkerDebuggerGlobalScope* globalScope = nullptr;
             UNWRAP_OBJECT(WorkerDebuggerGlobalScope, global, globalScope);
             MOZ_ASSERT(globalScope);
             MOZ_ASSERT(global == globalScope->GetWrapperPreserveColor());
-            target = static_cast<nsIDOMEventTarget*>(globalScope);
+
+            aWorkerPrivate->ReportErrorToDebugger(aFilename, aLineNumber,
+                                                  aMessage);
+            return true;
           }
 
+          MOZ_ASSERT(global == globalScope->GetWrapperPreserveColor());
+          nsIDOMEventTarget* target = static_cast<nsIDOMEventTarget*>(globalScope);
+
           nsRefPtr<ErrorEvent> event =
             ErrorEvent::Constructor(aTarget, NS_LITERAL_STRING("error"), init);
           event->SetTrusted(true);
 
           if (NS_FAILED(EventDispatcher::DispatchDOMEvent(target, nullptr,
                                                           event, nullptr,
                                                           &status))) {
             NS_WARNING("Failed to dispatch worker thread error event!");
@@ -4209,16 +4212,51 @@ WorkerPrivateParent<Derived>::AssertInne
 
   nsPIDOMWindow* outer = mLoadInfo.mWindow->GetOuterWindow();
   NS_ASSERTION(outer && outer->GetCurrentInnerWindow() == mLoadInfo.mWindow,
                "Inner window no longer correct!");
 }
 
 #endif
 
+class ReportDebuggerErrorRunnable final : public nsIRunnable
+{
+  nsRefPtr<WorkerDebugger> mDebugger;
+  nsString mFilename;
+  uint32_t mLineno;
+  nsString mMessage;
+
+public:
+  ReportDebuggerErrorRunnable(WorkerDebugger* aDebugger,
+                                const nsAString& aFilename, uint32_t aLineno,
+                                const nsAString& aMessage)
+  : mDebugger(aDebugger),
+    mFilename(aFilename),
+    mLineno(aLineno),
+    mMessage(aMessage)
+  {
+  }
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+
+private:
+  ~ReportDebuggerErrorRunnable()
+  { }
+
+  NS_IMETHOD
+  Run() override
+  {
+    mDebugger->ReportErrorToDebuggerOnMainThread(mFilename, mLineno, mMessage);
+
+    return NS_OK;
+  }
+};
+
+NS_IMPL_ISUPPORTS(ReportDebuggerErrorRunnable, nsIRunnable)
+
 WorkerDebugger::WorkerDebugger(WorkerPrivate* aWorkerPrivate)
 : mMutex("WorkerDebugger::mMutex"),
   mCondVar(mMutex, "WorkerDebugger::mCondVar"),
   mWorkerPrivate(aWorkerPrivate),
   mIsEnabled(false),
   mIsInitialized(false)
 {
   mWorkerPrivate->AssertIsOnParentThread();
@@ -4494,27 +4532,63 @@ WorkerDebugger::PostMessageToDebuggerOnM
     listeners.AppendElements(mListeners);
   }
 
   for (size_t index = 0; index < listeners.Length(); ++index) {
     listeners[index]->OnMessage(aMessage);
   }
 }
 
+void
+WorkerDebugger::ReportErrorToDebugger(const nsAString& aFilename,
+                                      uint32_t aLineno,
+                                      const nsAString& aMessage)
+{
+  mWorkerPrivate->AssertIsOnWorkerThread();
+
+  nsCOMPtr<nsIRunnable> runnable =
+    new ReportDebuggerErrorRunnable(this, aFilename, aLineno, aMessage);
+  if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
+    NS_WARNING("Failed to report error to debugger on main thread!");
+  }
+}
+
+void
+WorkerDebugger::ReportErrorToDebuggerOnMainThread(const nsAString& aFilename,
+                                                  uint32_t aLineno,
+                                                  const nsAString& aMessage)
+{
+  AssertIsOnMainThread();
+
+  nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> listeners;
+  {
+    MutexAutoLock lock(mMutex);
+
+    listeners.AppendElements(mListeners);
+  }
+
+  for (size_t index = 0; index < listeners.Length(); ++index) {
+    listeners[index]->OnError(aFilename, aLineno, aMessage);
+  }
+
+  LogErrorToConsole(aMessage, aFilename, nsString(), aLineno, 0, 0, 0);
+}
+
 WorkerPrivate::WorkerPrivate(JSContext* aCx,
                              WorkerPrivate* aParent,
                              const nsAString& aScriptURL,
                              bool aIsChromeWorker, WorkerType aWorkerType,
                              const nsACString& aSharedWorkerName,
                              WorkerLoadInfo& aLoadInfo)
   : WorkerPrivateParent<WorkerPrivate>(aCx, aParent, aScriptURL,
                                        aIsChromeWorker, aWorkerType,
                                        aSharedWorkerName, aLoadInfo)
   , mJSContext(nullptr)
   , mPRThread(nullptr)
+  , mDebuggerEventLoopLevel(0)
   , mErrorHandlerRecursionCount(0)
   , mNextTimeoutId(1)
   , mStatus(Pending)
   , mSuspended(false)
   , mTimerRunning(false)
   , mRunningExpiredTimeouts(false)
   , mCloseHandlerStarted(false)
   , mCloseHandlerFinished(false)
@@ -6109,21 +6183,99 @@ WorkerPrivate::PostMessageToParentMessag
     return;
   }
 
   PostMessageToParentInternal(aCx, aMessage, aTransferable, true,
                               aMessagePortSerial, aRv);
 }
 
 void
+WorkerPrivate::EnterDebuggerEventLoop()
+{
+  AssertIsOnWorkerThread();
+
+  JSContext* cx = GetJSContext();
+  MOZ_ASSERT(cx);
+
+  uint32_t currentEventLoopLevel = ++mDebuggerEventLoopLevel;
+
+  while (currentEventLoopLevel <= mDebuggerEventLoopLevel) {
+    bool debuggerRunnablesPending = false;
+
+    {
+      MutexAutoLock lock(mMutex);
+
+      debuggerRunnablesPending = !mDebuggerQueue.IsEmpty();
+    }
+
+    // Don't block with the periodic GC timer running.
+    if (!debuggerRunnablesPending) {
+      SetGCTimerMode(IdleTimer);
+    }
+
+    // Wait for something to do
+    {
+      MutexAutoLock lock(mMutex);
+
+      while (mControlQueue.IsEmpty() &&
+             !(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty())) {
+        WaitForWorkerEvents();
+      }
+
+      ProcessAllControlRunnablesLocked();
+    }
+
+    if (debuggerRunnablesPending) {
+      // Start the periodic GC timer if it is not already running.
+      SetGCTimerMode(PeriodicTimer);
+
+      WorkerRunnable* runnable;
+
+      {
+        MutexAutoLock lock(mMutex);
+
+        mDebuggerQueue.Pop(runnable);
+      }
+
+      MOZ_ASSERT(runnable);
+      static_cast<nsIRunnable*>(runnable)->Run();
+      runnable->Release();
+
+      // Now *might* be a good time to GC. Let the JS engine make the decision.
+      JS_MaybeGC(cx);
+    }
+  }
+}
+
+void
+WorkerPrivate::LeaveDebuggerEventLoop()
+{
+  AssertIsOnWorkerThread();
+
+  MutexAutoLock lock(mMutex);
+
+  if (mDebuggerEventLoopLevel > 0) {
+    --mDebuggerEventLoopLevel;
+  }
+}
+
+void
 WorkerPrivate::PostMessageToDebugger(const nsAString& aMessage)
 {
   mDebugger->PostMessageToDebugger(aMessage);
 }
 
+void
+WorkerPrivate::ReportErrorToDebugger(const nsAString& aFilename,
+                                     uint32_t aLineno,
+                                     const nsAString& aMessage)
+{
+  mDebugger->ReportErrorToDebugger(aFilename, aLineno, aMessage);
+}
+
 bool
 WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus)
 {
   AssertIsOnWorkerThread();
 
   NS_ASSERTION(aStatus > Running && aStatus < Dead, "Bad status!");
 
   nsRefPtr<EventTarget> eventTarget;
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -51,16 +51,18 @@ class Function;
 }
 namespace ipc {
 class PrincipalInfo;
 }
 }
 
 struct PRThread;
 
+class ReportDebuggerErrorRunnable;
+
 BEGIN_WORKERS_NAMESPACE
 
 class AutoSyncLoopHolder;
 class MessagePort;
 class SharedWorker;
 class ServiceWorkerClientInfo;
 class WorkerControlRunnable;
 class WorkerDebugger;
@@ -716,16 +718,18 @@ public:
 
   void
   AssertInnerWindowIsCorrect() const
   { }
 #endif
 };
 
 class WorkerDebugger : public nsIWorkerDebugger {
+  friend class ::ReportDebuggerErrorRunnable;
+
   mozilla::Mutex mMutex;
   mozilla::CondVar mCondVar;
 
   // Protected by mMutex
   WorkerPrivate* mWorkerPrivate;
   bool mIsEnabled;
 
   // Only touched on the main thread.
@@ -748,25 +752,34 @@ public:
   Enable();
 
   void
   Disable();
 
   void
   PostMessageToDebugger(const nsAString& aMessage);
 
+  void
+  ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno,
+                        const nsAString& aMessage);
+
 private:
   virtual
   ~WorkerDebugger();
 
   void
   NotifyIsEnabled(bool aIsEnabled);
 
   void
   PostMessageToDebuggerOnMainThread(const nsAString& aMessage);
+
+  void
+  ReportErrorToDebuggerOnMainThread(const nsAString& aFilename,
+                                    uint32_t aLineno,
+                                    const nsAString& aMessage);
 };
 
 class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
 {
   friend class WorkerPrivateParent<WorkerPrivate>;
   typedef WorkerPrivateParent<WorkerPrivate> ParentType;
   friend class AutoSyncLoopHolder;
 
@@ -797,16 +810,17 @@ class WorkerPrivate : public WorkerPriva
   PRThread* mPRThread;
 
   // Things touched on worker thread only.
   nsRefPtr<WorkerGlobalScope> mScope;
   nsRefPtr<WorkerDebuggerGlobalScope> mDebuggerScope;
   nsTArray<ParentType*> mChildWorkers;
   nsTArray<WorkerFeature*> mFeatures;
   nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts;
+  uint32_t mDebuggerEventLoopLevel;
 
   struct SyncLoopInfo
   {
     explicit SyncLoopInfo(EventTarget* aEventTarget);
 
     nsRefPtr<EventTarget> mEventTarget;
     bool mCompleted;
     bool mResult;
@@ -958,18 +972,28 @@ public:
   PostMessageToParentMessagePort(
                              JSContext* aCx,
                              uint64_t aMessagePortSerial,
                              JS::Handle<JS::Value> aMessage,
                              const Optional<Sequence<JS::Value>>& aTransferable,
                              ErrorResult& aRv);
 
   void
+  EnterDebuggerEventLoop();
+
+  void
+  LeaveDebuggerEventLoop();
+
+  void
   PostMessageToDebugger(const nsAString& aMessage);
 
+  void
+  ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno,
+                        const nsAString& aMessage);
+
   bool
   NotifyInternal(JSContext* aCx, Status aStatus);
 
   void
   ReportError(JSContext* aCx, const char* aMessage, JSErrorReport* aReport);
 
   int32_t
   SetTimeout(JSContext* aCx,
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -509,22 +509,45 @@ WorkerDebuggerGlobalScope::WrapGlobalObj
 void
 WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
                                      JS::MutableHandle<JSObject*> aGlobal)
 {
   aGlobal.set(mWorkerPrivate->GetOrCreateGlobalScope(aCx)->GetWrapper());
 }
 
 void
+WorkerDebuggerGlobalScope::EnterEventLoop()
+{
+  mWorkerPrivate->EnterDebuggerEventLoop();
+}
+
+void
+WorkerDebuggerGlobalScope::LeaveEventLoop()
+{
+  mWorkerPrivate->LeaveDebuggerEventLoop();
+}
+
+void
 WorkerDebuggerGlobalScope::PostMessage(const nsAString& aMessage)
 {
   mWorkerPrivate->PostMessageToDebugger(aMessage);
 }
 
 void
+WorkerDebuggerGlobalScope::ReportError(JSContext* aCx,
+                                       const nsAString& aMessage)
+{
+  JS::AutoFilename afn;
+  uint32_t lineno = 0;
+  JS::DescribeScriptedCaller(aCx, &afn, &lineno);
+  nsString filename(NS_ConvertUTF8toUTF16(afn.get()));
+  mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage);
+}
+
+void
 WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
                                 const Optional<nsAString>& aString) const
 {
   return mWorkerPrivate->GetOrCreateGlobalScope(aCx)->Dump(aString);
 }
 
 nsIGlobalObject*
 GetGlobalObjectForGlobal(JSObject* global)
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -260,21 +260,30 @@ public:
   {
     return GetWrapper();
   }
 
   void
   GetGlobal(JSContext* aCx, JS::MutableHandle<JSObject*> aGlobal);
 
   void
+  EnterEventLoop();
+
+  void
+  LeaveEventLoop();
+
+  void
   PostMessage(const nsAString& aMessage);
 
   IMPL_EVENT_HANDLER(message)
 
   void
+  ReportError(JSContext* aCx, const nsAString& aMessage);
+
+  void
   Dump(JSContext* aCx, const Optional<nsAString>& aString) const;
 
 private:
   virtual ~WorkerDebuggerGlobalScope();
 };
 
 END_WORKERS_NAMESPACE
 
--- a/dom/workers/nsIWorkerDebugger.idl
+++ b/dom/workers/nsIWorkerDebugger.idl
@@ -1,17 +1,20 @@
 #include "nsISupports.idl"
 
 interface nsIDOMWindow;
 
-[scriptable, uuid(ead45621-22a7-48ef-b7db-c4252ae3e6cb)]
+[scriptable, uuid(55d54034-1573-4889-b1d9-93ba12fc33c7)]
 interface nsIWorkerDebuggerListener : nsISupports
 {
   void onClose();
 
+  void onError(in DOMString filename, in unsigned long lineno,
+               in DOMString message);
+
   void onMessage(in DOMString message);
 };
 
 [scriptable, builtinclass, uuid(28e0a60c-ff10-446c-8c2a-5fbdc01394ea)]
 interface nsIWorkerDebugger : nsISupports
 {
   const unsigned long TYPE_DEDICATED = 0;
   const unsigned long TYPE_SHARED = 1;
--- a/dom/workers/test/WorkerDebugger.postMessage_debugger.js
+++ b/dom/workers/test/WorkerDebugger.postMessage_debugger.js
@@ -1,9 +1,9 @@
 "use strict"
 
-onmessage = function (event) {
+this.onmessage = function (event) {
   switch (event.data) {
   case "ping":
     postMessage("pong");
     break;
   }
 };
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/WorkerDebuggerGlobalScope.enterEventLoop_childWorker.js
@@ -0,0 +1,14 @@
+"use strict";
+
+function f() {
+  debugger;
+}
+
+self.onmessage = function (event) {
+  switch (event.data) {
+  case "ping":
+    debugger;
+    postMessage("pong");
+    break;
+  };
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/WorkerDebuggerGlobalScope.enterEventLoop_debugger.js
@@ -0,0 +1,29 @@
+"use strict";
+
+let frames = [];
+
+var dbg = new Debugger(global);
+dbg.onDebuggerStatement = function (frame) {
+  frames.push(frame);
+  postMessage("paused");
+  enterEventLoop();
+  frames.pop();
+  postMessage("resumed");
+};
+
+this.onmessage = function (event) {
+  switch (event.data) {
+  case "eval":
+    frames[frames.length - 1].eval("f()");
+    postMessage("evalled");
+    break;
+
+  case "ping":
+    postMessage("pong");
+    break;
+
+  case "resume":
+    leaveEventLoop();
+    break;
+  };
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/WorkerDebuggerGlobalScope.enterEventLoop_worker.js
@@ -0,0 +1,25 @@
+"use strict";
+
+function f() {
+  debugger;
+}
+
+var worker = new Worker("WorkerDebuggerGlobalScope.enterEventLoop_childWorker.js");
+
+worker.onmessage = function (event) {
+  postMessage("child:" + event.data);
+};
+
+self.onmessage = function (event) {
+  var message = event.data;
+  if (message.indexOf(":") >= 0) {
+    worker.postMessage(message.split(":")[1]);
+    return;
+  }
+  switch (message) {
+  case "ping":
+    debugger;
+    postMessage("pong");
+    break;
+  };
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/WorkerDebuggerGlobalScope.reportError_childWorker.js
@@ -0,0 +1,5 @@
+"use strict";
+
+self.onerror = function () {
+  postMessage("error");
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/WorkerDebuggerGlobalScope.reportError_debugger.js
@@ -0,0 +1,12 @@
+"use strict";
+
+this.onmessage = function (event) {
+  switch (event.data) {
+  case "report":
+    reportError("reported");
+    break;
+  case "throw":
+    throw new Error("thrown");
+    break;
+  }
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/WorkerDebuggerGlobalScope.reportError_worker.js
@@ -0,0 +1,11 @@
+"use strict";
+
+var worker = new Worker("WorkerDebuggerGlobalScope.reportError_childWorker.js");
+
+worker.onmessage = function (event) {
+  postMessage("child:" + event.data);
+};
+
+self.onerror = function () {
+  postMessage("error");
+};
--- a/dom/workers/test/chrome.ini
+++ b/dom/workers/test/chrome.ini
@@ -2,16 +2,22 @@
 skip-if = buildapp == 'b2g'
 support-files =
   WorkerDebugger.initialize_childWorker.js
   WorkerDebugger.initialize_debugger.js
   WorkerDebugger.initialize_worker.js
   WorkerDebugger.postMessage_childWorker.js
   WorkerDebugger.postMessage_debugger.js
   WorkerDebugger.postMessage_worker.js
+  WorkerDebuggerGlobalScope.enterEventLoop_childWorker.js
+  WorkerDebuggerGlobalScope.enterEventLoop_debugger.js
+  WorkerDebuggerGlobalScope.enterEventLoop_worker.js
+  WorkerDebuggerGlobalScope.reportError_childWorker.js
+  WorkerDebuggerGlobalScope.reportError_debugger.js
+  WorkerDebuggerGlobalScope.reportError_worker.js
   WorkerDebuggerManager_childWorker.js
   WorkerDebuggerManager_worker.js
   WorkerDebugger_childWorker.js
   WorkerDebugger_worker.js
   WorkerDebugger_sharedWorker.js
   WorkerTest.jsm
   WorkerTest_subworker.js
   WorkerTest_worker.js
@@ -32,16 +38,18 @@ support-files =
   jsm_url_worker.js
   workersDisabled_worker.js
   file_url.jsm
   bug1062920_worker.js
 
 [test_WorkerDebugger.xul]
 [test_WorkerDebugger.initialize.xul]
 [test_WorkerDebugger.postMessage.xul]
+[test_WorkerDebuggerGlobalScope.enterEventLoop.xul]
+[test_WorkerDebuggerGlobalScope.reportError.xul]
 [test_WorkerDebuggerManager.xul]
 [test_bug883784.jsm]
 [test_bug883784.xul]
 [test_chromeWorker.xul]
 [test_chromeWorkerJSM.xul]
 [test_extension.xul]
 [test_extensionBootstrap.xul]
 [test_file.xul]
--- a/dom/workers/test/dom_worker_helper.js
+++ b/dom/workers/test/dom_worker_helper.js
@@ -99,16 +99,27 @@ function waitForDebuggerClose(dbg) {
         ok(true, "Debugger should be closed.");
         dbg.removeListener(this);
         resolve();
       }
     });
   });
 }
 
+function waitForDebuggerError(dbg) {
+  return new Promise(function (resolve) {
+    dbg.addListener({
+      onError: function (filename, lineno, message) {
+        dbg.removeListener(this);
+        resolve(new Error(message, filename, lineno));
+      }
+    });
+  });
+}
+
 function waitForDebuggerMessage(dbg, message) {
   return new Promise(function (resolve) {
     dbg.addListener({
       onMessage: function (message1) {
         if (message !== message1) {
           return;
         }
         info(true, "Should receive " + message + " message from debugger.");
--- a/dom/workers/test/test_WorkerDebugger.postMessage.xul
+++ b/dom/workers/test/test_WorkerDebugger.postMessage.xul
@@ -28,24 +28,24 @@
              "debuggers to be registered, and initialize them.");
         let promise = waitForMultiple([
           waitForRegister(WORKER_URL, DEBUGGER_URL),
           waitForRegister(CHILD_WORKER_URL, DEBUGGER_URL)
         ]);
         let worker = new Worker(WORKER_URL);
         let [dbg, childDbg] = yield promise;
 
-        info("Check that posting a ping message to the worker debugger " +
-             "results in a pong message being received.");
+        info("Send a request to the worker debugger. This should cause a " +
+             "response to be received from the worker debugger.");
         promise = waitForDebuggerMessage(dbg, "pong");
         dbg.postMessage("ping");
         yield promise;
 
-        info("Check that posting a ping message to the child worker " +
-             "debugger results in a pong message being received.");
+        info("Send a request to the child worker debugger. This should cause " +
+             "a response to be received from the child worker debugger.");
         promise = waitForDebuggerMessage(childDbg, "pong");
         childDbg.postMessage("ping");
         yield promise;
 
         SimpleTest.finish();
       });
     }
 
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_WorkerDebuggerGlobalScope.enterEventLoop.xul
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<window title="Test for WorkerDebuggerGlobalScope.enterEventLoop"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="test();">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+  <script type="application/javascript" src="dom_worker_helper.js"/>
+
+  <script type="application/javascript">
+  <![CDATA[
+
+    const WORKER_URL = "WorkerDebuggerGlobalScope.enterEventLoop_worker.js";
+    const CHILD_WORKER_URL = "WorkerDebuggerGlobalScope.enterEventLoop_childWorker.js";
+    const DEBUGGER_URL = BASE_URL + "WorkerDebuggerGlobalScope.enterEventLoop_debugger.js";
+
+    function test() {
+      Task.spawn(function* () {
+        SimpleTest.waitForExplicitFinish();
+
+        info("Create a worker that creates a child worker, wait for their " +
+             "debuggers to be registered, and initialize them.");
+        let promise = waitForMultiple([
+          waitForRegister(WORKER_URL, DEBUGGER_URL),
+          waitForRegister(CHILD_WORKER_URL, DEBUGGER_URL)
+        ]);
+        let worker = new Worker(WORKER_URL);
+        let [dbg, childDbg] = yield promise;
+
+        info("Send a request to the child worker. This should cause a nested " +
+             "event loop to be entered.");
+        promise = waitForDebuggerMessage(childDbg, "paused");
+        worker.postMessage("child:ping");
+        yield promise;
+
+        info("Send a request to the child worker debugger. This should cause " +
+             "a second nested event loop to be entered.");
+        promise = waitForDebuggerMessage(childDbg, "paused");
+        childDbg.postMessage("eval");
+        yield promise;
+
+        info("Send a request to the child worker debugger. This should cause " +
+             "the second nested event loop to be left. Check that a response " +
+             "for the previous request is not received from the child worker " +
+             "debugger until after the event loop is left.");
+        promise = waitForMultiple([
+          waitForDebuggerMessage(childDbg, "resumed"),
+          waitForDebuggerMessage(childDbg, "evalled")
+        ]);
+        childDbg.postMessage("resume");
+        yield promise;
+
+        info("Send a request to the child worker debugger. This should cause " +
+             "the first nested event loop to be left. Check that a response " +
+             "for the previous request is not received from the child worker " +
+             "until after the event loop is left.");
+        promise = waitForMultiple([
+          waitForDebuggerMessage(childDbg, "resumed"),
+          waitForWorkerMessage(worker, "child:pong")
+        ]);
+        childDbg.postMessage("resume");
+        yield promise;
+
+        info("Send a request to the worker. This should cause a nested event " +
+             "loop to be entered.");
+        promise = waitForDebuggerMessage(dbg, "paused");
+        worker.postMessage("ping");
+        yield promise;
+
+        info("Terminate the worker. This should not cause the worker " +
+             "debugger to stop running.");
+        worker.terminate();
+
+        worker.onmessage = function () {
+          ok(false, "Worker should have been terminated.");
+        };
+
+        info("Send a request to the worker debugger. This should cause a " +
+             "second nested event loop to be entered.");
+        promise = waitForDebuggerMessage(dbg, "paused");
+        dbg.postMessage("eval");
+        yield promise;
+
+        info("Send a request to the worker debugger. This should cause the " +
+             "second nested event loop to be left. Check that a response for " +
+             "the previous request is not received from the worker " +
+             "debugger until after the event loop is left.");
+        promise = waitForMultiple([
+          waitForDebuggerMessage(dbg, "resumed"),
+          waitForDebuggerMessage(dbg, "evalled")
+        ]);
+        dbg.postMessage("resume");
+        yield promise;
+
+        info("Send a request to the child worker debugger. This should cause " +
+             "the first nested event loop to be left. No response for the " +
+             "previous request should be received from the worker debugger, " +
+             "since it has been terminated.");
+        promise = waitForMultiple([
+          waitForDebuggerMessage(dbg, "resumed"),
+        ]);
+        dbg.postMessage("resume");
+        yield promise;
+
+        SimpleTest.finish();
+      });
+    }
+
+  ]]>
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <p id="display"></p>
+    <div id="content" style="display:none;"></div>
+    <pre id="test"></pre>
+  </body>
+  <label id="test-result"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_WorkerDebuggerGlobalScope.reportError.xul
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<window title="Test for WorkerDebuggerGlobalScope.reportError"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="test();">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+  <script type="application/javascript" src="dom_worker_helper.js"/>
+
+  <script type="application/javascript">
+  <![CDATA[
+
+    const WORKER_URL = "WorkerDebuggerGlobalScope.reportError_worker.js";
+    const CHILD_WORKER_URL = "WorkerDebuggerGlobalScope.reportError_childWorker.js";
+    const DEBUGGER_URL = BASE_URL + "WorkerDebuggerGlobalScope.reportError_debugger.js";
+
+    function test() {
+      Task.spawn(function* () {
+        SimpleTest.waitForExplicitFinish();
+
+        info("Create a worker that creates a child worker, wait for their " +
+             "debuggers to be registered, and initialize them.");
+        let promise = waitForMultiple([
+          waitForRegister(WORKER_URL, DEBUGGER_URL),
+          waitForRegister(CHILD_WORKER_URL, DEBUGGER_URL)
+        ]);
+        let worker = new Worker(WORKER_URL);
+        let [dbg, childDbg] = yield promise;
+
+        worker.onmessage = function () {
+          ok(false, "Debugger error events should not be fired at workers.");
+        };
+
+        info("Send a message to the worker debugger and wait for it to " +
+             "report an error.");
+        promise = waitForDebuggerError(dbg);
+        dbg.postMessage("report");
+        let error = yield promise;
+        is(error.fileName, DEBUGGER_URL,
+           "fileName should be name of file from which error is reported.");
+        is(error.lineNumber, 6,
+           "lineNumber should be line number from which error is reported.");
+        is(error.message, "reported", "message should be reported.");
+
+        info("Send a message to the worker debugger and wait for it to " +
+             "throw an error.");
+        promise = waitForDebuggerError(dbg);
+        dbg.postMessage("throw");
+        error = yield promise;
+        is(error.fileName, DEBUGGER_URL,
+           "fileName should be name of file from which error is thrown");
+        is(error.lineNumber, 9,
+           "lineNumber should be line number from which error is thrown");
+        is(error.message, "Error: thrown", "message should be Error: thrown");
+
+        info("Send a message to the child worker debugger and wait for it to " +
+             "report an error.");
+        promise = waitForDebuggerError(childDbg);
+        childDbg.postMessage("report");
+        error = yield promise;
+        is(error.fileName, DEBUGGER_URL,
+           "fileName should be name of file from which error is reported.");
+        is(error.lineNumber, 6,
+           "lineNumber should be line number from which error is reported.");
+        is(error.message, "reported", "message should be reported.");
+
+        info("Send a message to the child worker debugger and wait for it to " +
+             "report throw an error.");
+        promise = waitForDebuggerError(childDbg);
+        childDbg.postMessage("throw");
+        error = yield promise;
+        is(error.fileName, DEBUGGER_URL,
+           "fileName should be name of file from which error is thrown");
+        is(error.lineNumber, 9,
+           "lineNumber should be line number from which error is thrown");
+        is(error.message, "Error: thrown", "message should be Error: thrown");
+
+        SimpleTest.finish();
+      });
+    }
+
+  ]]>
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <p id="display"></p>
+    <div id="content" style="display:none;"></div>
+    <pre id="test"></pre>
+  </body>
+  <label id="test-result"/>
+</window>
+
--- a/dom/workers/test/test_WorkerDebuggerManager.xul
+++ b/dom/workers/test/test_WorkerDebuggerManager.xul
@@ -52,17 +52,17 @@
              "unregistered.");
         is(dbg.isClosed, false,
            "Worker debugger should not be closed before it is unregistered.");
         is(childDbg.isClosed, false,
            "Child worker debugger should not be closed before it is " +
            "unregistered");
 
         info("Terminate the worker and the child worker, and wait for their " +
-             "debuggers to be unregistered");
+             "debuggers to be unregistered.");
         promise = waitForMultiple([
           waitForUnregister(CHILD_WORKER_URL),
           waitForUnregister(WORKER_URL),
         ]);
         worker.terminate();
         yield promise;
 
         info("Check that worker debuggers are not enumerated after they are " +
--- a/dom/xul/templates/tests/chrome/test_bug330010.xul
+++ b/dom/xul/templates/tests/chrome/test_bug330010.xul
@@ -2,28 +2,36 @@
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:svg="http://www.w3.org/2000/svg"
         xmlns:html="http://www.w3.org/1999/xhtml"
         onload="boom();">
 <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 <script type="text/javascript">
+<![CDATA[
 
 SimpleTest.waitForExplicitFinish();
 function boom()
 {
+  const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].
+                         getService(Components.interfaces.nsIRDFService);
+  var src = window.location.href.replace(/test_bug330010.xul/, "file_bug330010.rdf");
+
+  var ds = RDF.GetDataSourceBlocking(src);
+
   var x = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "hbox");
-  generatedShape = document.getElementById("s").childNodes[3];
+  var generatedShape = document.getElementById("s").childNodes[3];
   generatedShape.appendChild(x);
   document.documentElement.removeChild(document.getElementById("s"));
   ok(true, "Didn't crash");
   SimpleTest.finish();
 }
 
+]]>
 </script>
 
   <html:div datasources="file_bug330010.rdf" ref="urn:root" flex="1" id="s">
     <template>
       <rule>
         <conditions>
           <content uri="?root"/>
           <triple subject="?root"
--- a/editor/libeditor/nsHTMLCSSUtils.cpp
+++ b/editor/libeditor/nsHTMLCSSUtils.cpp
@@ -431,18 +431,17 @@ nsHTMLCSSUtils::IsCSSEditableProperty(ns
   if (aAttribute && aAttribute->EqualsLiteral("align") &&
       content->IsAnyOfHTMLElements(nsGkAtoms::ul,
                                    nsGkAtoms::ol,
                                    nsGkAtoms::dl,
                                    nsGkAtoms::li,
                                    nsGkAtoms::dd,
                                    nsGkAtoms::dt,
                                    nsGkAtoms::address,
-                                   nsGkAtoms::pre,
-                                   nsGkAtoms::ul)) {
+                                   nsGkAtoms::pre)) {
     return true;
   }
 
   return false;
 }
 
 // The lowest level above the transaction; adds the CSS declaration
 // "aProperty : aValue" to the inline styles carried by aElement
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -25,16 +25,17 @@ support-files = test_bug332636.html^head
 skip-if = toolkit == 'android'
 [test_bug404320.html]
 [test_bug408231.html]
 skip-if = toolkit == 'android'
 [test_bug410986.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug414526.html]
 [test_bug417418.html]
+skip-if = android_version == '18' # bug 1147989
 [test_bug432225.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug439808.html]
 [test_bug442186.html]
 [test_bug449243.html]
 [test_bug455992.html]
 [test_bug456244.html]
 [test_bug460740.html]
@@ -55,21 +56,23 @@ skip-if = toolkit == 'android' || e10s
 [test_bug525389.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug527935.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug537046.html]
 [test_bug549262.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug550434.html]
+skip-if = android_version == '18' # bug 1147989
 [test_bug551704.html]
 [test_bug552782.html]
 [test_bug567213.html]
 [test_bug570144.html]
 [test_bug578771.html]
+skip-if = android_version == '18' # bug 1147989
 [test_bug586662.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug587461.html]
 [test_bug590554.html]
 [test_bug592592.html]
 [test_bug596001.html]
 [test_bug596333.html]
 skip-if = toolkit == 'android' || e10s
@@ -96,17 +99,17 @@ skip-if = toolkit == 'android' #TIMED_OU
 [test_bug622371.html]
 skip-if = toolkit == 'android' #bug 957797
 [test_bug625452.html]
 [test_bug629172.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug629845.html]
 [test_bug638596.html]
 [test_bug640321.html]
-skip-if = e10s
+skip-if = android_version == '18' || e10s # bug 1147989
 [test_bug641466.html]
 [test_bug645914.html]
 [test_bug668599.html]
 [test_bug674770-1.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug674770-2.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug674861.html]
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -1447,19 +1447,25 @@ ChromeTooltipListener::sTooltipCallback(
       bool textFound = false;
 
       self->mTooltipTextProvider->GetNodeText(
           self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound);
 
       if (textFound) {
         nsString tipText(tooltipText);
         LayoutDeviceIntPoint screenDot = widget->WidgetToScreenOffset();
-        self->ShowTooltip(self->mMouseScreenX - screenDot.x,
-                          self->mMouseScreenY - screenDot.y,
-                          tipText);
+        double scaleFactor = 1.0;
+        if (shell->GetPresContext()) {
+          scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
+          shell->GetPresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
+        }
+        // ShowTooltip expects widget-relative position.
+        self->ShowTooltip(self->mMouseScreenX - screenDot.x / scaleFactor,
+          self->mMouseScreenY - screenDot.y / scaleFactor,
+          tipText);
       }
     }
 
     // release tooltip target if there is one, NO MATTER WHAT
     self->mPossibleTooltipNode = nullptr;
   } // if "self" data valid
 
 } // sTooltipCallback
--- a/gfx/2d/BaseRect.h
+++ b/gfx/2d/BaseRect.h
@@ -101,17 +101,17 @@ struct BaseRect {
     return !IsEmpty() && !aRect.IsEmpty() &&
            x < aRect.XMost() && aRect.x < XMost() &&
            y < aRect.YMost() && aRect.y < YMost();
   }
   // Returns the rectangle containing the intersection of the points
   // (including edges) of *this and aRect. If there are no points in that
   // intersection, returns an empty rectangle with x/y set to the std::max of the x/y
   // of *this and aRect.
-  Sub Intersect(const Sub& aRect) const
+  MOZ_WARN_UNUSED_RESULT Sub Intersect(const Sub& aRect) const
   {
     Sub result;
     result.x = std::max<T>(x, aRect.x);
     result.y = std::max<T>(y, aRect.y);
     result.width = std::min<T>(x - result.x + width, aRect.x - result.x + aRect.width);
     result.height = std::min<T>(y - result.y + height, aRect.y - result.y + aRect.height);
     if (result.width < 0 || result.height < 0) {
       result.SizeTo(0, 0);
@@ -129,30 +129,30 @@ struct BaseRect {
     *static_cast<Sub*>(this) = aRect1.Intersect(aRect2);
     return !IsEmpty();
   }
 
   // Returns the smallest rectangle that contains both the area of both
   // this and aRect2.
   // Thus, empty input rectangles are ignored.
   // If both rectangles are empty, returns this.
-  Sub Union(const Sub& aRect) const
+  MOZ_WARN_UNUSED_RESULT Sub Union(const Sub& aRect) const
   {
     if (IsEmpty()) {
       return aRect;
     } else if (aRect.IsEmpty()) {
       return *static_cast<const Sub*>(this);
     } else {
       return UnionEdges(aRect);
     }
   }
   // Returns the smallest rectangle that contains both the points (including
   // edges) of both aRect1 and aRect2.
   // Thus, empty input rectangles are allowed to affect the result.
-  Sub UnionEdges(const Sub& aRect) const
+  MOZ_WARN_UNUSED_RESULT Sub UnionEdges(const Sub& aRect) const
   {
     Sub result;
     result.x = std::min(x, aRect.x);
     result.y = std::min(y, aRect.y);
     result.width = std::max(XMost(), aRect.XMost()) - result.x;
     result.height = std::max(YMost(), aRect.YMost()) - result.y;
     return result;
   }
@@ -520,28 +520,28 @@ struct BaseRect {
     width = std::max<T>(0, right - x);
     height = std::max<T>(0, bottom - y);
   }
 
   /**
    * Clamp aPoint to this rectangle. It is allowed to end up on any
    * edge of the rectangle.
    */
-  Point ClampPoint(const Point& aPoint) const
+  MOZ_WARN_UNUSED_RESULT Point ClampPoint(const Point& aPoint) const
   {
     return Point(std::max(x, std::min(XMost(), aPoint.x)),
                  std::max(y, std::min(YMost(), aPoint.y)));
   }
 
   /**
    * Clamp this rectangle to be inside aRect. The function returns a copy of
    * this rect after it is forced inside the bounds of aRect. It will attempt to
    * retain the size but will shrink the dimensions that don't fit.
    */
-  Sub ForceInside(const Sub& aRect) const
+  MOZ_WARN_UNUSED_RESULT Sub ForceInside(const Sub& aRect) const
   {
     Sub rect(std::max(aRect.x, x),
              std::max(aRect.y, y),
              std::min(aRect.width, width),
              std::min(aRect.height, height));
     rect.x = std::min(rect.XMost(), aRect.XMost()) - rect.width;
     rect.y = std::min(rect.YMost(), aRect.YMost()) - rect.height;
     return rect;
--- a/gfx/layers/TextureDIB.cpp
+++ b/gfx/layers/TextureDIB.cpp
@@ -126,24 +126,25 @@ DIBTextureHost::DIBTextureHost(TextureFl
     dont_AddRef(reinterpret_cast<gfxWindowsSurface*>(aDescriptor.surface()));
   MOZ_ASSERT(mSurface);
 
   mSize = ToIntSize(mSurface->GetSize());
   mFormat = ImageFormatToSurfaceFormat(
     gfxPlatform::GetPlatform()->OptimalFormatForContent(mSurface->GetContentType()));
 }
 
-TextureSource*
-DIBTextureHost::GetTextureSources()
+bool
+DIBTextureHost::BindTextureSource(CompositableTextureSourceRef& aTexture)
 {
   if (!mTextureSource) {
     Updated();
   }
 
-  return mTextureSource;
+  aTexture = mTextureSource;
+  return !!aTexture;
 }
 
 void
 DIBTextureHost::Updated(const nsIntRegion* aRegion)
 {
   if (!mTextureSource) {
     mTextureSource = mCompositor->CreateDataTextureSource(mFlags);
   }
--- a/gfx/layers/TextureDIB.h
+++ b/gfx/layers/TextureDIB.h
@@ -67,17 +67,17 @@ protected:
 };
 
 class DIBTextureHost : public TextureHost
 {
 public:
   DIBTextureHost(TextureFlags aFlags,
                  const SurfaceDescriptorDIB& aDescriptor);
 
-  virtual TextureSource* GetTextureSources() override;
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual void DeallocateDeviceData() override;
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
 
   virtual gfx::IntSize GetSize() const override { return mSize; }
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1055,16 +1055,22 @@ APZCTreeManager::CancelAnimation(const S
   if (apzc) {
     apzc->CancelAnimation();
   }
 }
 
 void
 APZCTreeManager::ClearTree()
 {
+  // Ensure that no references to APZCs are alive in any lingering input
+  // blocks. This breaks cycles from InputBlockState::mTargetApzc back to
+  // the InputQueue.
+  APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
+    mInputQueue.get(), &InputQueue::Clear));
+
   MonitorAutoLock lock(mTreeLock);
 
   // This can be done as part of a tree walk but it's easier to
   // just re-use the Collect method that we need in other places.
   // If this is too slow feel free to change it to a recursive walk.
   nsTArray<nsRefPtr<HitTestingTreeNode>> nodesToDestroy;
   Collect(mRootNode, &nodesToDestroy);
   for (size_t i = 0; i < nodesToDestroy.Length(); i++) {
--- a/gfx/layers/apz/src/InputBlockState.cpp
+++ b/gfx/layers/apz/src/InputBlockState.cpp
@@ -260,27 +260,30 @@ WheelBlockState::Type()
 
 bool
 WheelBlockState::ShouldAcceptNewEvent() const
 {
   if (!InTransaction()) {
     // If we're not in a transaction, start a new one.
     return false;
   }
+
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetApzc();
-  if (!apzc || apzc->IsDestroyed()) {
+  if (apzc->IsDestroyed()) {
     return false;
   }
 
   return true;
 }
 
 bool
 WheelBlockState::MaybeTimeout(const ScrollWheelInput& aEvent)
 {
+  MOZ_ASSERT(InTransaction());
+
   if (MaybeTimeout(aEvent.mTimeStamp)) {
     return true;
   }
 
   if (!mLastMouseMove.IsNull()) {
     // If there's a recent mouse movement, we can time out the transaction early.
     TimeDuration duration = TimeStamp::Now() - mLastMouseMove;
     if (duration.ToMilliseconds() >= gfxPrefs::MouseWheelIgnoreMoveDelayMs()) {
@@ -291,16 +294,18 @@ WheelBlockState::MaybeTimeout(const Scro
   }
 
   return false;
 }
 
 bool
 WheelBlockState::MaybeTimeout(const TimeStamp& aTimeStamp)
 {
+  MOZ_ASSERT(InTransaction());
+
   // End the transaction if the event occurred > 1.5s after the most recently
   // seen wheel event.
   TimeDuration duration = aTimeStamp - mLastEventTime;
   if (duration.ToMilliseconds() < gfxPrefs::MouseWheelTransactionTimeoutMs()) {
     return false;
   }
 
   TBS_LOG("%p wheel transaction timed out\n", this);
@@ -312,16 +317,18 @@ WheelBlockState::MaybeTimeout(const Time
 
   EndTransaction();
   return true;
 }
 
 void
 WheelBlockState::OnMouseMove(const ScreenIntPoint& aPoint)
 {
+  MOZ_ASSERT(InTransaction());
+
   if (!GetTargetApzc()->Contains(aPoint)) {
     EndTransaction();
     return;
   }
 
   if (mLastMouseMove.IsNull()) {
     // If the cursor is moving inside the frame, and it is more than the
     // ignoremovedelay time since the last scroll operation, we record
@@ -329,25 +336,42 @@ WheelBlockState::OnMouseMove(const Scree
     TimeStamp now = TimeStamp::Now();
     TimeDuration duration = now - mLastEventTime;
     if (duration.ToMilliseconds() >= gfxPrefs::MouseWheelIgnoreMoveDelayMs()) {
       mLastMouseMove = now;
     }
   }
 }
 
+void
+WheelBlockState::UpdateTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc)
+{
+  InputBlockState::UpdateTargetApzc(aTargetApzc);
+
+  // If we found there was no target apzc, then we end the transaction.
+  if (!GetTargetApzc()) {
+    EndTransaction();
+  }
+}
+
 bool
 WheelBlockState::InTransaction() const
 {
   // We consider a wheel block to be in a transaction if it has a confirmed
   // target and is the most recent wheel input block to be created.
   if (GetBlockId() != sLastWheelBlockId) {
     return false;
   }
-  return !mTransactionEnded;
+
+  if (mTransactionEnded) {
+    return false;
+  }
+
+  MOZ_ASSERT(GetTargetApzc());
+  return true;
 }
 
 bool
 WheelBlockState::AllowScrollHandoff() const
 {
   // If we're in a wheel transaction, we do not allow overscroll handoff until
   // a new event ends the wheel transaction.
   return !IsTargetConfirmed() || !InTransaction();
--- a/gfx/layers/apz/src/InputBlockState.h
+++ b/gfx/layers/apz/src/InputBlockState.h
@@ -41,17 +41,17 @@ public:
   bool SetConfirmedTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc);
   const nsRefPtr<AsyncPanZoomController>& GetTargetApzc() const;
   const nsRefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const;
   uint64_t GetBlockId() const;
 
   bool IsTargetConfirmed() const;
 
 protected:
-  void UpdateTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc);
+  virtual void UpdateTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc);
 
 private:
   nsRefPtr<AsyncPanZoomController> mTargetApzc;
   bool mTargetConfirmed;
   const uint64_t mBlockId;
 protected:
   nsRefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain;
 
@@ -219,16 +219,19 @@ public:
    */
   bool MaybeTimeout(const TimeStamp& aTimeStamp);
 
   /**
    * Update the wheel transaction state for a new event.
    */
   void Update(const ScrollWheelInput& aEvent);
 
+protected:
+  void UpdateTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc) override;
+
 private:
   nsTArray<ScrollWheelInput> mEvents;
   TimeStamp mLastEventTime;
   TimeStamp mLastMouseMove;
   bool mTransactionEnded;
 };
 
 /**
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -455,10 +455,18 @@ InputQueue::ProcessInputBlocks() {
 
     // If we get here, we know there are more touch blocks in the queue after
     // |curBlock|, so we can remove |curBlock| and try to process the next one.
     INPQ_LOG("discarding processed %s block %p\n", curBlock->Type(), curBlock);
     mInputBlockQueue.RemoveElementAt(0);
   } while (!mInputBlockQueue.IsEmpty());
 }
 
+void
+InputQueue::Clear()
+{
+  APZThreadUtils::AssertOnControllerThread();
+
+  mInputBlockQueue.Clear();
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/apz/src/InputQueue.h
+++ b/gfx/layers/apz/src/InputQueue.h
@@ -95,16 +95,20 @@ public:
    * handling.
    */
   bool HasReadyTouchBlock() const;
   /**
    * If there is a wheel transaction, returns the WheelBlockState representing
    * the transaction. Otherwise, returns null.
    */
   WheelBlockState* GetCurrentWheelTransaction() const;
+  /**
+   * Remove all input blocks from the input queue.
+   */
+  void Clear();
 
 private:
   ~InputQueue();
 
   TouchBlockState* StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
                                       bool aTargetConfirmed,
                                       bool aCopyPropertiesFromCurrent);
 
--- a/gfx/layers/apz/util/APZThreadUtils.cpp
+++ b/gfx/layers/apz/util/APZThreadUtils.cpp
@@ -6,72 +6,66 @@
 #include "mozilla/layers/APZThreadUtils.h"
 
 #include "mozilla/layers/Compositor.h"
 
 namespace mozilla {
 namespace layers {
 
 static bool sThreadAssertionsEnabled = true;
-static PRThread* sControllerThread;
+static MessageLoop* sControllerThread;
 
 /*static*/ void
 APZThreadUtils::SetThreadAssertionsEnabled(bool aEnabled) {
   sThreadAssertionsEnabled = aEnabled;
 }
 
 /*static*/ bool
 APZThreadUtils::GetThreadAssertionsEnabled() {
   return sThreadAssertionsEnabled;
 }
 
 /*static*/ void
+APZThreadUtils::SetControllerThread(MessageLoop* aLoop)
+{
+  // We must either be setting the initial controller thread, or removing it,
+  // or re-using an existing controller thread.
+  MOZ_ASSERT(!sControllerThread || !aLoop || sControllerThread == aLoop);
+  sControllerThread = aLoop;
+}
+
+/*static*/ void
 APZThreadUtils::AssertOnControllerThread() {
   if (!GetThreadAssertionsEnabled()) {
     return;
   }
 
-  static bool sControllerThreadDetermined = false;
-  if (!sControllerThreadDetermined) {
-    // Technically this may not actually pick up the correct controller thread,
-    // if the first call to this method happens from a non-controller thread.
-    // If the assertion below fires, it is possible that it is because
-    // sControllerThread is not actually the controller thread.
-    sControllerThread = PR_GetCurrentThread();
-    sControllerThreadDetermined = true;
-  }
-  MOZ_ASSERT(sControllerThread == PR_GetCurrentThread());
+  MOZ_ASSERT(sControllerThread == MessageLoop::current());
 }
 
 /*static*/ void
 APZThreadUtils::AssertOnCompositorThread()
 {
   if (GetThreadAssertionsEnabled()) {
     Compositor::AssertOnCompositorThread();
   }
 }
 
 /*static*/ void
 APZThreadUtils::RunOnControllerThread(Task* aTask)
 {
-#ifdef MOZ_WIDGET_GONK
-  // On B2G the controller thread is the compositor thread, and this function
-  // is always called from the libui thread or the main thread.
-  MessageLoop* loop = CompositorParent::CompositorLoop();
-  if (!loop) {
+  if (!sControllerThread) {
     // Could happen on startup
     NS_WARNING("Dropping task posted to controller thread\n");
     delete aTask;
     return;
   }
-  MOZ_ASSERT(MessageLoop::current() != loop);
-  loop->PostTask(FROM_HERE, aTask);
-#else
-  // On non-B2G platforms this is only ever called from the controller thread
-  // itself.
-  AssertOnControllerThread();
-  aTask->Run();
-  delete aTask;
-#endif
+
+  if (sControllerThread == MessageLoop::current()) {
+    aTask->Run();
+    delete aTask;
+  } else {
+    sControllerThread->PostTask(FROM_HERE, aTask);
+  }
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/apz/util/APZThreadUtils.h
+++ b/gfx/layers/apz/util/APZThreadUtils.h
@@ -18,16 +18,21 @@ public:
    * In the gtest environment everything runs on one thread, so we
    * shouldn't assert that we're on a particular thread. This enables
    * that behaviour.
    */
   static void SetThreadAssertionsEnabled(bool aEnabled);
   static bool GetThreadAssertionsEnabled();
 
   /**
+   * Set the controller thread.
+   */
+  static void SetControllerThread(MessageLoop* aLoop);
+
+  /**
    * This can be used to assert that the current thread is the
    * controller/UI thread (on which input events are received).
    * This does nothing if thread assertions are disabled.
    */
   static void AssertOnControllerThread();
 
   /**
    * This can be used to assert that the current thread is the
--- a/gfx/layers/basic/MacIOSurfaceTextureHostBasic.h
+++ b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.h
@@ -59,19 +59,20 @@ public:
                                const SurfaceDescriptorMacIOSurface& aDescriptor);
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual bool Lock() override;
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
-  virtual TextureSource* GetTextureSources() override
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
   {
-    return mTextureSource;
+    aTexture = mTextureSource;
+    return !!aTexture;
   }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
   }
 
   virtual gfx::IntSize GetSize() const override;
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -105,17 +105,16 @@ CanvasClient2D::Update(gfx::IntSize aSiz
   mBuffer->Unlock();
 
   if (bufferCreated && !AddTextureClient(mBuffer)) {
     mBuffer = nullptr;
     return;
   }
 
   if (updated) {
-    GetForwarder()->UpdatedTexture(this, mBuffer, nullptr);
     GetForwarder()->UseTexture(this, mBuffer);
     mBuffer->SyncWithObject(GetForwarder()->GetSyncObject());
   }
 }
 
 TemporaryRef<TextureClient>
 CanvasClient2D::CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
                                              gfx::IntSize aSize,
@@ -397,17 +396,16 @@ CanvasClientSharedSurface::Update(gfx::I
     GetForwarder()->RemoveTextureFromCompositableAsync(tracker, this, mFrontTex);
 
     mFrontTex = nullptr;
   }
 
   // Use the new TexClient.
   mFrontTex = newTex;
 
-  forwarder->UpdatedTexture(this, mFrontTex, nullptr);
   forwarder->UseTexture(this, mFrontTex);
 }
 
 void
 CanvasClientSharedSurface::ClearSurfaces()
 {
   mFrontTex = nullptr;
   // It is important to destroy the SharedSurface *after* the TextureClient.
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -241,17 +241,16 @@ ImageClientSingle::UpdateImage(ImageCont
       texture->Unlock();
     }
   }
   if (!texture || !AddTextureClient(texture)) {
     return false;
   }
 
   mFrontBuffer = texture;
-  GetForwarder()->UpdatedTexture(this, texture, nullptr);
   GetForwarder()->UseTexture(this, texture);
 
   UpdatePictureRect(image->GetPictureRect());
 
   mLastPaintedImageSerial = image->GetSerial();
   aContainer->NotifyPaintedImage(image);
 
   texture->SyncWithObject(GetForwarder()->GetSyncObject());
--- a/gfx/layers/composite/CanvasLayerComposite.cpp
+++ b/gfx/layers/composite/CanvasLayerComposite.cpp
@@ -61,17 +61,17 @@ CanvasLayerComposite::GetLayer()
   return this;
 }
 
 void
 CanvasLayerComposite::SetLayerManager(LayerManagerComposite* aManager)
 {
   LayerComposite::SetLayerManager(aManager);
   mManager = aManager;
-  if (mImageHost) {
+  if (mImageHost && mCompositor) {
     mImageHost->SetCompositor(mCompositor);
   }
 }
 
 LayerRenderState
 CanvasLayerComposite::GetRenderState()
 {
   if (mDestroyed || !mImageHost || !mImageHost->IsAttached()) {
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -114,27 +114,30 @@ CompositableHost::UseTextureHost(Texture
   }
 }
 
 void
 CompositableHost::UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
                                             TextureHost* aTextureOnWhite)
 {
   MOZ_ASSERT(aTextureOnBlack && aTextureOnWhite);
-  aTextureOnBlack->SetCompositor(GetCompositor());
-  aTextureOnWhite->SetCompositor(GetCompositor());
+  if (GetCompositor()) {
+    aTextureOnBlack->SetCompositor(GetCompositor());
+    aTextureOnWhite->SetCompositor(GetCompositor());
+  }
 }
 
 void
 CompositableHost::RemoveTextureHost(TextureHost* aTexture)
 {}
 
 void
 CompositableHost::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   mCompositor = aCompositor;
 }
 
 bool
 CompositableHost::AddMaskEffect(EffectChain& aEffects,
                                 const gfx::Matrix4x4& aTransform,
                                 bool aIs3D)
 {
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -38,16 +38,17 @@ ImageHost::~ImageHost()
 }
 
 void
 ImageHost::UseTextureHost(TextureHost* aTexture)
 {
   CompositableHost::UseTextureHost(aTexture);
   mFrontBuffer = aTexture;
   if (mFrontBuffer) {
+    mFrontBuffer->Updated();
     mFrontBuffer->PrepareTextureSource(mTextureSource);
   }
 }
 
 void
 ImageHost::RemoveTextureHost(TextureHost* aTexture)
 {
   CompositableHost::RemoveTextureHost(aTexture);
--- a/gfx/layers/composite/PaintedLayerComposite.cpp
+++ b/gfx/layers/composite/PaintedLayerComposite.cpp
@@ -84,17 +84,17 @@ PaintedLayerComposite::GetLayer()
   return this;
 }
 
 void
 PaintedLayerComposite::SetLayerManager(LayerManagerComposite* aManager)
 {
   LayerComposite::SetLayerManager(aManager);
   mManager = aManager;
-  if (mBuffer) {
+  if (mBuffer && mCompositor) {
     mBuffer->SetCompositor(mCompositor);
   }
 }
 
 TiledLayerComposer*
 PaintedLayerComposite::GetTiledLayerComposer()
 {
   if (!mBuffer) {
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -142,23 +142,16 @@ TextureHost::AsTextureHost(PTextureParen
 }
 
 PTextureParent*
 TextureHost::GetIPDLActor()
 {
   return mActor;
 }
 
-bool
-TextureHost::BindTextureSource(CompositableTextureSourceRef& texture)
-{
-  texture = GetTextureSources();
-  return !!texture;
-}
-
 FenceHandle
 TextureHost::GetAndResetReleaseFenceHandle()
 {
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   TextureHostOGL* hostOGL = this->AsHostOGL();
   if (!hostOGL) {
     return FenceHandle();
   }
@@ -404,16 +397,17 @@ BufferTextureHost::Updated(const nsIntRe
     DebugOnly<bool> result = MaybeUpload(!mNeedsFullUpdate ? &mMaybeUpdatedRegion : nullptr);
     NS_WARN_IF_FALSE(result, "Failed to upload a texture");
   }
 }
 
 void
 BufferTextureHost::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   if (mCompositor == aCompositor) {
     return;
   }
   RefPtr<TextureSource> it = mFirstSource;
   while (it) {
     it->SetCompositor(aCompositor);
     it = it->GetNextSibling();
   }
@@ -444,22 +438,23 @@ BufferTextureHost::Lock()
 
 void
 BufferTextureHost::Unlock()
 {
   MOZ_ASSERT(mLocked);
   mLocked = false;
 }
 
-TextureSource*
-BufferTextureHost::GetTextureSources()
+bool
+BufferTextureHost::BindTextureSource(CompositableTextureSourceRef& aTexture)
 {
   MOZ_ASSERT(mLocked);
   MOZ_ASSERT(mFirstSource);
-  return mFirstSource;
+  aTexture = mFirstSource;
+  return !!aTexture;
 }
 
 gfx::SurfaceFormat
 BufferTextureHost::GetFormat() const
 {
   // mFormat is the format of the data that we share with the content process.
   // GetFormat, on the other hand, expects the format that we present to the
   // Compositor (it is used to choose the effect type).
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -199,29 +199,16 @@ public:
     }
     if (mRef) {
       mRef->ReleaseCompositableRef();
     }
     mRef = aOther.get();
     return *this;
   }
 
-  CompositableTextureRef& operator=(const TemporaryRef<T>& aOther)
-  {
-    RefPtr<T> temp = aOther;
-    if (temp) {
-      temp->AddCompositableRef();
-    }
-    if (mRef) {
-      mRef->ReleaseCompositableRef();
-    }
-    mRef = temp;
-    return *this;
-  }
-
   CompositableTextureRef& operator=(T* aOther)
   {
     if (aOther) {
       aOther->AddCompositableRef();
     }
     if (mRef) {
       mRef->ReleaseCompositableRef();
     }
@@ -374,37 +361,28 @@ public:
   /**
    * Note that the texture host format can be different from its corresponding
    * texture source's. For example a ShmemTextureHost can have the ycbcr
    * format and produce 3 "alpha" textures sources.
    */
   virtual gfx::SurfaceFormat GetFormat() const = 0;
 
   /**
-   * Return a list of TextureSources for use with a Compositor.
-   *
-   * This can trigger texture uploads, so do not call it inside transactions
-   * so as to not upload textures while the main thread is blocked.
-   * Must not be called while this TextureHost is not sucessfully Locked.
-   */
-  virtual TextureSource* GetTextureSources() = 0;
-
-  /**
    * Called during the transaction. The TextureSource may or may not be composited.
    *
    * Note that this is called outside of lock/unlock.
    */
   virtual void PrepareTextureSource(CompositableTextureSourceRef& aTexture) {}
 
   /**
    * Called at composition time, just before compositing the TextureSource composited.
    *
    * Note that this is called only withing lock/unlock.
    */
-  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture);
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) = 0;
 
   /**
    * Called when another TextureHost will take over.
    */
   virtual void UnbindTextureSource() {}
 
   /**
    * Is called before compositing if the shared data has changed since last
@@ -581,25 +559,25 @@ public:
   virtual size_t GetBufferSize() = 0;
 
   virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
 
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
-  virtual TextureSource* GetTextureSources() override;
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual void DeallocateDeviceData() override;
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   /**
    * Return the format that is exposed to the compositor when calling
-   * GetTextureSources.
+   * BindTextureSource.
    *
    * If the shared format is YCbCr and the compositor does not support it,
    * GetFormat will be RGB32 (even though mFormat is SurfaceFormat::YUV).
    */
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
@@ -718,20 +696,21 @@ public:
     mCompositor = aCompositor;
   }
 
 public:
 
   virtual bool Lock() override;
   virtual void Unlock() override;
 
-  virtual TextureSource* GetTextureSources() override {
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override {
     MOZ_ASSERT(mIsLocked);
     MOZ_ASSERT(mTexSource);
-    return mTexSource;
+    aTexture = mTexSource;
+    return !!aTexture;
   }
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual gfx::IntSize GetSize() const override;
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() override { return "SharedSurfaceTextureHost"; }
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -207,16 +207,17 @@ TiledLayerBufferComposite::ValidateTile(
   }
 #endif
   return aTile;
 }
 
 void
 TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   if (!IsValid()) {
     return;
   }
   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
     if (mRetainedTiles[i].IsPlaceholderTile()) continue;
     mRetainedTiles[i].mTextureHost->SetCompositor(aCompositor);
     if (mRetainedTiles[i].mTextureHostOnWhite) {
       mRetainedTiles[i].mTextureHostOnWhite->SetCompositor(aCompositor);
@@ -386,16 +387,17 @@ TiledContentHost::UseTiledLayerBuffer(IS
 void
 TiledContentHost::Composite(EffectChain& aEffectChain,
                             float aOpacity,
                             const gfx::Matrix4x4& aTransform,
                             const gfx::Filter& aFilter,
                             const gfx::Rect& aClipRect,
                             const nsIntRegion* aVisibleRegion /* = nullptr */)
 {
+  MOZ_ASSERT(mCompositor);
   if (mPendingUpload) {
     mTiledBuffer.SetCompositor(mCompositor);
     mTiledBuffer.Upload();
 
     // For a single-buffered tiled buffer, Upload will upload the shared memory
     // surface to texture memory and we no longer need to read from them.
     if (!mTiledBuffer.HasDoubleBufferedTiles()) {
       mTiledBuffer.ReadUnlock();
--- a/gfx/layers/composite/X11TextureHost.h
+++ b/gfx/layers/composite/X11TextureHost.h
@@ -25,19 +25,20 @@ public:
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual bool Lock() override;
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual gfx::IntSize GetSize() const override;
 
-  virtual TextureSource* GetTextureSources() override
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
   {
-    return mTextureSource;
+    aTexture = mTextureSource;
+    return !!aTexture;
   }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
   }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -293,30 +293,34 @@ CompositorD3D11::Initialize()
       D3D11_COLOR_WRITE_ENABLE_ALL
     };
     blendDesc.RenderTarget[0] = rtBlendDisabled;
     hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mDisabledBlendState));
     if (FAILED(hr)) {
       return false;
     }
 
-    CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, 1, 1, 1, 1,
-                                D3D11_BIND_SHADER_RESOURCE |
-                                D3D11_BIND_RENDER_TARGET);
-    desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+    if (!gfxWindowsPlatform::GetPlatform()->IsWARP()) {
+      // It's okay to do this on Windows 8. But for now we'll just bail
+      // whenever we're using WARP.
+      CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, 1, 1, 1, 1,
+                                 D3D11_BIND_SHADER_RESOURCE |
+                                 D3D11_BIND_RENDER_TARGET);
+      desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
 
-    RefPtr<ID3D11Texture2D> texture;
-    hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(texture));
-    if (FAILED(hr)) {
-      return false;
-    }
+      RefPtr<ID3D11Texture2D> texture;
+      hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(texture));
+      if (FAILED(hr)) {
+        return false;
+      }
 
-    hr = texture->QueryInterface((IDXGIResource**)byRef(mAttachments->mSyncTexture));
-    if (FAILED(hr)) {
-      return false;
+      hr = texture->QueryInterface((IDXGIResource**)byRef(mAttachments->mSyncTexture));
+      if (FAILED(hr)) {
+        return false;
+      }
     }
     
     //
     // VR additions
     //
     D3D11_INPUT_ELEMENT_DESC vrlayout[] =
     {
       { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT,       0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
@@ -1096,26 +1100,28 @@ CompositorD3D11::BeginFrame(const nsIntR
 
   mContext->RSSetState(mAttachments->mRasterizerState);
 
   SetRenderTarget(mDefaultRT);
 
   // ClearRect will set the correct blend state for us.
   ClearRect(Rect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height));
 
-  RefPtr<IDXGIKeyedMutex> mutex;
-  mAttachments->mSyncTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
+  if (mAttachments->mSyncTexture) {
+    RefPtr<IDXGIKeyedMutex> mutex;
+    mAttachments->mSyncTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
 
-  MOZ_ASSERT(mutex);
-  HRESULT hr = mutex->AcquireSync(0, 10000);
-  if (hr == WAIT_TIMEOUT) {
-    MOZ_CRASH();
+    MOZ_ASSERT(mutex);
+    HRESULT hr = mutex->AcquireSync(0, 10000);
+    if (hr == WAIT_TIMEOUT) {
+      MOZ_CRASH();
+    }
+
+    mutex->ReleaseSync(0);
   }
-
-  mutex->ReleaseSync(0);
 }
 
 void
 CompositorD3D11::EndFrame()
 {
   nsIntSize oldSize = mSize;
   EnsureSize();
   UINT presentInterval = 0;
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -600,16 +600,17 @@ ID3D11Device*
 DXGITextureHostD3D11::GetDevice()
 {
   return gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
 }
 
 void
 DXGITextureHostD3D11::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   mCompositor = static_cast<CompositorD3D11*>(aCompositor);
 }
 
 bool
 DXGITextureHostD3D11::Lock()
 {
   if (!GetDevice()) {
     NS_WARNING("trying to lock a TextureHost without a D3D device");
@@ -631,23 +632,24 @@ DXGITextureHostD3D11::Lock()
 void
 DXGITextureHostD3D11::Unlock()
 {
   MOZ_ASSERT(mIsLocked);
   UnlockD3DTexture(mTextureSource->GetD3D11Texture());
   mIsLocked = false;
 }
 
-TextureSource*
-DXGITextureHostD3D11::GetTextureSources()
+bool
+DXGITextureHostD3D11::BindTextureSource(CompositableTextureSourceRef& aTexture)
 {
   MOZ_ASSERT(mIsLocked);
   // If Lock was successful we must have a valid TextureSource.
   MOZ_ASSERT(mTextureSource);
-  return mTextureSource.get();
+  aTexture = mTextureSource;
+  return !!aTexture;
 }
 
 DXGIYCbCrTextureHostD3D11::DXGIYCbCrTextureHostD3D11(TextureFlags aFlags,
   const SurfaceDescriptorDXGIYCbCr& aDescriptor)
   : TextureHost(aFlags)
   , mSize(aDescriptor.size())
   , mIsLocked(false)
 {
@@ -694,16 +696,17 @@ ID3D11Device*
 DXGIYCbCrTextureHostD3D11::GetDevice()
 {
   return gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
 }
 
 void
 DXGIYCbCrTextureHostD3D11::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   mCompositor = static_cast<CompositorD3D11*>(aCompositor);
 }
 
 bool
 DXGIYCbCrTextureHostD3D11::Lock()
 {
   if (!GetDevice()) {
     NS_WARNING("trying to lock a TextureHost without a D3D device");
@@ -733,23 +736,24 @@ DXGIYCbCrTextureHostD3D11::Unlock()
 {
   MOZ_ASSERT(mIsLocked);
   UnlockD3DTexture(mTextureSources[0]->GetD3D11Texture());
   UnlockD3DTexture(mTextureSources[1]->GetD3D11Texture());
   UnlockD3DTexture(mTextureSources[2]->GetD3D11Texture());
   mIsLocked = false;
 }
 
-TextureSource*
-DXGIYCbCrTextureHostD3D11::GetTextureSources()
+bool
+DXGIYCbCrTextureHostD3D11::BindTextureSource(CompositableTextureSourceRef& aTexture)
 {
   MOZ_ASSERT(mIsLocked);
   // If Lock was successful we must have a valid TextureSource.
   MOZ_ASSERT(mTextureSources[0] && mTextureSources[1] && mTextureSources[2]);
-  return mTextureSources[0].get();
+  aTexture = mTextureSources[0].get();
+  return !!aTexture;
 }
 
 bool
 DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
                                nsIntRegion* aDestRegion,
                                IntPoint* aSrcOffset)
 {
   // Incremental update with a source offset is only used on Mac so it is not
@@ -881,16 +885,17 @@ DataTextureSourceD3D11::GetTileRect()
 {
   IntRect rect = GetTileRect(mCurrentTile);
   return nsIntRect(rect.x, rect.y, rect.width, rect.height);
 }
 
 void
 DataTextureSourceD3D11::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   CompositorD3D11* d3dCompositor = static_cast<CompositorD3D11*>(aCompositor);
   if (mCompositor && mCompositor != d3dCompositor) {
     Reset();
   }
   mCompositor = d3dCompositor;
 }
 
 CompositingRenderTargetD3D11::CompositingRenderTargetD3D11(ID3D11Texture2D* aTexture,
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -239,17 +239,17 @@ protected:
  * A TextureHost for shared D3D11 textures.
  */
 class DXGITextureHostD3D11 : public TextureHost
 {
 public:
   DXGITextureHostD3D11(TextureFlags aFlags,
                        const SurfaceDescriptorD3D10& aDescriptor);
 
-  virtual TextureSource* GetTextureSources() override;
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual void DeallocateDeviceData() override {}
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
 
   virtual bool Lock() override;
@@ -278,17 +278,17 @@ protected:
 };
 
 class DXGIYCbCrTextureHostD3D11 : public TextureHost
 {
 public:
   DXGIYCbCrTextureHostD3D11(TextureFlags aFlags,
                             const SurfaceDescriptorDXGIYCbCr& aDescriptor);
 
-  virtual TextureSource* GetTextureSources() override;
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual void DeallocateDeviceData() override{}
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual gfx::SurfaceFormat GetFormat() const override{ return gfx::SurfaceFormat::YUV; }
 
   virtual bool Lock() override;
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -512,16 +512,17 @@ DataTextureSourceD3D9::Update(gfxWindows
   }
 
   return true;
 }
 
 void
 DataTextureSourceD3D9::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   CompositorD3D9* d3dCompositor = static_cast<CompositorD3D9*>(aCompositor);
   if (mCompositor && mCompositor != d3dCompositor) {
     Reset();
   }
   mCompositor = d3dCompositor;
 }
 
 void
@@ -912,22 +913,23 @@ void
 TextureHostD3D9::SetCompositor(Compositor* aCompositor)
 {
   mCompositor = static_cast<CompositorD3D9*>(aCompositor);
   if (mTextureSource) {
     mTextureSource->SetCompositor(aCompositor);
   }
 }
 
-TextureSource*
-TextureHostD3D9::GetTextureSources()
+bool
+TextureHostD3D9::BindTextureSource(CompositableTextureSourceRef& aTexture)
 {
   MOZ_ASSERT(mIsLocked);
   MOZ_ASSERT(mTextureSource);
-  return mTextureSource;
+  aTexture = mTextureSource;
+  return !!aTexture;
 }
 
 bool
 TextureHostD3D9::Lock()
 {
   MOZ_ASSERT(!mIsLocked);
   // XXX - Currently if a TextureHostD3D9 is created but Update is never called,
   // it will not have a TextureSource although it could since it has a valid
@@ -988,22 +990,23 @@ DXGITextureHostD3D9::OpenSharedHandle()
     return;
   }
 
   mTextureSource = new DataTextureSourceD3D9(mFormat, mSize, mCompositor, texture);
 
   return;
 }
 
-TextureSource*
-DXGITextureHostD3D9::GetTextureSources()
+bool
+DXGITextureHostD3D9::BindTextureSource(CompositableTextureSourceRef& aTexture)
 {
   MOZ_ASSERT(mIsLocked);
   MOZ_ASSERT(mTextureSource);
-  return mTextureSource;
+  aTexture = mTextureSource;
+  return !!aTexture;
 }
 
 bool
 DXGITextureHostD3D9::Lock()
 {
   MOZ_ASSERT(!mIsLocked);
 
   if (!GetDevice()) {
@@ -1022,16 +1025,17 @@ DXGITextureHostD3D9::Unlock()
 {
   MOZ_ASSERT(mIsLocked);
   mIsLocked = false;
 }
 
 void
 DXGITextureHostD3D9::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   mCompositor = static_cast<CompositorD3D9*>(aCompositor);
 }
 
 void
 DXGITextureHostD3D9::DeallocateDeviceData()
 {
   mTextureSource = nullptr;
 }
@@ -1053,16 +1057,17 @@ IDirect3DDevice9*
 DXGIYCbCrTextureHostD3D9::GetDevice()
 {
   return mCompositor ? mCompositor->device() : nullptr;
 }
 
 void
 DXGIYCbCrTextureHostD3D9::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   mCompositor = static_cast<CompositorD3D9*>(aCompositor);
 }
 
 bool
 DXGIYCbCrTextureHostD3D9::Lock()
 {
   if (!GetDevice()) {
     NS_WARNING("trying to lock a TextureHost without a D3D device");
@@ -1104,19 +1109,20 @@ DXGIYCbCrTextureHostD3D9::Lock()
 
 void
 DXGIYCbCrTextureHostD3D9::Unlock()
 {
   MOZ_ASSERT(mIsLocked);
   mIsLocked = false;
 }
 
-TextureSource*
-DXGIYCbCrTextureHostD3D9::GetTextureSources()
+bool
+DXGIYCbCrTextureHostD3D9::BindTextureSource(CompositableTextureSourceRef& aTexture)
 {
   MOZ_ASSERT(mIsLocked);
   // If Lock was successful we must have a valid TextureSource.
   MOZ_ASSERT(mTextureSources[0] && mTextureSources[1] && mTextureSources[2]);
-  return mTextureSources[0].get();
+  aTexture = mTextureSources[0].get();
+  return !!aTexture;
 }
 
 }
 }
--- a/gfx/layers/d3d9/TextureD3D9.h
+++ b/gfx/layers/d3d9/TextureD3D9.h
@@ -293,17 +293,17 @@ private:
 };
 
 class TextureHostD3D9 : public TextureHost
 {
 public:
   TextureHostD3D9(TextureFlags aFlags,
                   const SurfaceDescriptorD3D9& aDescriptor);
 
-  virtual TextureSource* GetTextureSources() override;
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual void DeallocateDeviceData() override;
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
 
   virtual bool Lock() override;
@@ -334,17 +334,17 @@ protected:
 };
 
 class DXGITextureHostD3D9 : public TextureHost
 {
 public:
   DXGITextureHostD3D9(TextureFlags aFlags,
     const SurfaceDescriptorD3D10& aDescriptor);
 
-  virtual TextureSource* GetTextureSources() override;
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual void DeallocateDeviceData() override;
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
 
   virtual gfx::IntSize GetSize() const override { return mSize; }
@@ -371,17 +371,17 @@ protected:
 };
 
 class DXGIYCbCrTextureHostD3D9 : public TextureHost
 {
 public:
   DXGIYCbCrTextureHostD3D9(TextureFlags aFlags,
                            const SurfaceDescriptorDXGIYCbCr& aDescriptor);
 
-  virtual TextureSource* GetTextureSources() override;
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual void DeallocateDeviceData() override {}
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual gfx::SurfaceFormat GetFormat() const override { return gfx::SurfaceFormat::YUV; }
 
   virtual bool Lock() override;
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -151,25 +151,16 @@ public:
    * the next composition.
    */
   virtual void UseTexture(CompositableClient* aCompositable,
                           TextureClient* aClient) = 0;
   virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
                                          TextureClient* aClientOnBlack,
                                          TextureClient* aClientOnWhite) = 0;
 
-  /**
-   * Tell the compositor side that the shared data has been modified so that
-   * it can react accordingly (upload textures, etc.).
-   */
-  virtual void UpdatedTexture(CompositableClient* aCompositable,
-                              TextureClient* aTexture,
-                              nsIntRegion* aRegion) = 0;
-
-
   virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
                                PTextureChild* aTexture,
                                const FenceHandle& aFence) = 0;
 
   virtual void SendPendingAsyncMessges() = 0;
 
   void IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier);
 
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -203,27 +203,16 @@ CompositableParentManager::ReceiveCompos
     case CompositableOperation::TOpUseOverlaySource: {
       const OpUseOverlaySource& op = aEdit.get_OpUseOverlaySource();
       CompositableHost* compositable = AsCompositable(op);
       MOZ_ASSERT(compositable->GetType() == CompositableType::IMAGE_OVERLAY, "Invalid operation!");
       compositable->UseOverlaySource(op.overlay());
       break;
     }
 #endif
-    case CompositableOperation::TOpUpdateTexture: {
-      const OpUpdateTexture& op = aEdit.get_OpUpdateTexture();
-      RefPtr<TextureHost> texture = TextureHost::AsTextureHost(op.textureParent());
-      MOZ_ASSERT(texture);
-
-      texture->Updated(op.region().type() == MaybeRegion::TnsIntRegion
-                       ? &op.region().get_nsIntRegion()
-                       : nullptr); // no region means invalidate the entire surface
-      break;
-    }
-
     default: {
       MOZ_ASSERT(false, "bad type");
     }
   }
 
   return true;
 }
 
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -148,32 +148,16 @@ ImageBridgeChild::UseOverlaySource(Compo
                                    const OverlaySource& aOverlay)
 {
   MOZ_ASSERT(aCompositable);
   mTxn->AddEdit(OpUseOverlaySource(nullptr, aCompositable->GetIPDLActor(), aOverlay));
 }
 #endif
 
 void
-ImageBridgeChild::UpdatedTexture(CompositableClient* aCompositable,
-                                 TextureClient* aTexture,
-                                 nsIntRegion* aRegion)
-{
-  MOZ_ASSERT(aCompositable);
-  MOZ_ASSERT(aTexture);
-  MOZ_ASSERT(aCompositable->GetIPDLActor());
-  MOZ_ASSERT(aTexture->GetIPDLActor());
-  MaybeRegion region = aRegion ? MaybeRegion(*aRegion)
-                               : MaybeRegion(null_t());
-  mTxn->AddNoSwapEdit(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
-                                      nullptr, aTexture->GetIPDLActor(),
-                                      region));
-}
-
-void
 ImageBridgeChild::SendFenceHandle(AsyncTransactionTracker* aTracker,
                                   PTextureChild* aTexture,
                                   const FenceHandle& aFence)
 {
   HoldUntilComplete(aTracker);
   InfallibleTArray<AsyncChildMessageData> messages;
   messages.AppendElement(OpDeliverFenceFromChild(aTracker->GetId(),
                                                  nullptr, aTexture,
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -202,23 +202,16 @@ public:
    * Flush all Images sent to CompositableHost.
    */
   static void FlushAllImages(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront);
 
   // CompositableForwarder
 
   virtual void Connect(CompositableClient* aCompositable) override;
 
-  /**
-   * See CompositableForwarder::UpdatedTexture
-   */
-  virtual void UpdatedTexture(CompositableClient* aCompositable,
-                              TextureClient* aTexture,
-                              nsIntRegion* aRegion) override;
-
   virtual bool IsImageBridgeChild() const override { return true; }
 
   /**
    * See CompositableForwarder::UseTexture
    */
   virtual void UseTexture(CompositableClient* aCompositable,
                           TextureClient* aClient) override;
   virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -386,22 +386,16 @@ struct OpUseComponentAlphaTextures {
   PTexture textureOnWhite;
 };
 
 union MaybeRegion {
   nsIntRegion;
   null_t;
 };
 
-struct OpUpdateTexture {
-  PCompositable compositable;
-  PTexture texture;
-  MaybeRegion region;
-};
-
 struct OpDeliverFence {
   uint64_t transactionId;
   PTexture texture;
   FenceHandle fence;
 };
 
 struct OpDeliverFenceToTracker {
   uint64_t transactionId;
@@ -425,17 +419,16 @@ union CompositableOperation {
 
   OpPaintTextureRegion;
 
   OpUseTiledLayerBuffer;
 
   OpRemoveTexture;
   OpRemoveTextureAsync;
 
-  OpUpdateTexture;
   OpUseTexture;
   OpUseComponentAlphaTextures;
   OpUseOverlaySource;
 };
 
 // A unit of a changeset; a set of these comprise a changeset
 union Edit {
   OpCreatePaintedLayer;
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -106,32 +106,36 @@ ParamTraits<MagicGrallocBufferHandle>::W
     aMsg->WriteFileDescriptor(FileDescriptor(fds[n], false));
   }
 }
 
 bool
 ParamTraits<MagicGrallocBufferHandle>::Read(const Message* aMsg,
                                             void** aIter, paramType* aResult)
 {
+  MOZ_ASSERT(!aResult->mGraphicBuffer.get());
+  MOZ_ASSERT(aResult->mRef.mOwner == 0);
+  MOZ_ASSERT(aResult->mRef.mKey == -1);
+
   size_t nbytes;
   const char* data;
   int owner;
   int64_t index;
 
   if (!aMsg->ReadInt(aIter, &owner) ||
       !aMsg->ReadInt64(aIter, &index) ||
       !aMsg->ReadSize(aIter, &nbytes) ||
       !aMsg->ReadBytes(aIter, &data, nbytes)) {
     printf_stderr("ParamTraits<MagicGrallocBufferHandle>::Read() failed to read a message\n");
     return false;
   }
 
   size_t nfds = aMsg->num_fds();
   int fds[nfds];
-  bool sameProcess = (XRE_GetProcessType() == GeckoProcessType_Default);
+
   for (size_t n = 0; n < nfds; ++n) {
     FileDescriptor fd;
     if (!aMsg->ReadFileDescriptor(aIter, &fd)) {
       printf_stderr("ParamTraits<MagicGrallocBufferHandle>::Read() failed to read file descriptors\n");
       return false;
     }
     // If the GraphicBuffer was shared cross-process, SCM_RIGHTS does
     // the right thing and dup's the fd. If it's shared cross-thread,
@@ -139,40 +143,37 @@ ParamTraits<MagicGrallocBufferHandle>::R
     // But in shared cross-thread, dup fd is not necessary because we get
     // a pointer to the GraphicBuffer directly from SharedBufferManagerParent
     // and don't create a new GraphicBuffer around the fd.
     fds[n] = fd.fd;
   }
 
   aResult->mRef.mOwner = owner;
   aResult->mRef.mKey = index;
-  if (sameProcess) {
+  if (XRE_GetProcessType() == GeckoProcessType_Default) {
+    // If we are in chrome process, we can just get GraphicBuffer directly from
+    // SharedBufferManagerParent.
     aResult->mGraphicBuffer = SharedBufferManagerParent::GetGraphicBuffer(aResult->mRef);
   } else {
-    if (SharedBufferManagerChild::GetSingleton()->IsValidKey(index)) {
-      aResult->mGraphicBuffer = SharedBufferManagerChild::GetSingleton()->GetGraphicBuffer(index);
-    }
-    MOZ_ASSERT(!aResult->mGraphicBuffer.get());
-
     // Deserialize GraphicBuffer
 #if ANDROID_VERSION >= 19
     sp<GraphicBuffer> buffer(new GraphicBuffer());
     const void* datap = (const void*)data;
     const int* fdsp = &fds[0];
     if (NO_ERROR != buffer->unflatten(datap, nbytes, fdsp, nfds)) {
       buffer = nullptr;
     }
 #else
     sp<GraphicBuffer> buffer(new GraphicBuffer());
     Flattenable *flattenable = buffer.get();
     if (NO_ERROR != flattenable->unflatten(data, nbytes, fds, nfds)) {
       buffer = nullptr;
     }
 #endif
-    if(buffer.get() && !aResult->mGraphicBuffer.get()) {
+    if (buffer.get()) {
       aResult->mGraphicBuffer = buffer;
     }
   }
 
   if (!aResult->mGraphicBuffer.get()) {
     printf_stderr("ParamTraits<MagicGrallocBufferHandle>::Read() failed to get gralloc buffer\n");
     return false;
   }
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -357,54 +357,39 @@ ShadowLayerForwarder::UpdatePictureRect(
                                         const nsIntRect& aRect)
 {
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(aCompositable->GetIPDLActor());
   mTxn->AddNoSwapPaint(OpUpdatePictureRect(nullptr, aCompositable->GetIPDLActor(), aRect));
 }
 
 void
-ShadowLayerForwarder::UpdatedTexture(CompositableClient* aCompositable,
-                                     TextureClient* aTexture,
-                                     nsIntRegion* aRegion)
-{
-  MOZ_ASSERT(aCompositable);
-  MOZ_ASSERT(aTexture);
-  MOZ_ASSERT(aCompositable->GetIPDLActor());
-  MOZ_ASSERT(aTexture->GetIPDLActor());
-  MaybeRegion region = aRegion ? MaybeRegion(*aRegion)
-                               : MaybeRegion(null_t());
-  if (aTexture->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD) {
-    mTxn->AddPaint(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
-                                   nullptr, aTexture->GetIPDLActor(),
-                                   region));
-  } else {
-    mTxn->AddNoSwapPaint(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
-                                         nullptr, aTexture->GetIPDLActor(),
-                                         region));
-  }
-}
-
-void
 ShadowLayerForwarder::UseTexture(CompositableClient* aCompositable,
                                  TextureClient* aTexture)
 {
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(aCompositable->GetIPDLActor());
   MOZ_ASSERT(aTexture->GetIPDLActor());
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   FenceHandle handle = aTexture->GetAcquireFenceHandle();
   if (handle.IsValid()) {
     RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(handle);
     SendFenceHandle(tracker, aTexture->GetIPDLActor(), handle);
   }
 #endif
   mTxn->AddEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
                              nullptr, aTexture->GetIPDLActor()));
+  if (aTexture->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD
+      && aTexture->HasInternalBuffer()) {
+    // We use IMMEDIATE_UPLOAD when we want to be sure that the upload cannot
+    // race with updates on the main thread. In this case we want the transaction
+    // to be synchronous.
+    mTxn->MarkSyncTransaction();
+  }
 }
 
 void
 ShadowLayerForwarder::UseComponentAlphaTextures(CompositableClient* aCompositable,
                                                 TextureClient* aTextureOnBlack,
                                                 TextureClient* aTextureOnWhite)
 {
   MOZ_ASSERT(aCompositable);
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -256,23 +256,16 @@ public:
 
   /**
    * Communicate the picture rect of an image to the compositor
    */
   void UpdatePictureRect(CompositableClient* aCompositable,
                          const nsIntRect& aRect) override;
 
   /**
-   * See CompositableForwarder::UpdatedTexture
-   */
-  virtual void UpdatedTexture(CompositableClient* aCompositable,
-                              TextureClient* aTexture,
-                              nsIntRegion* aRegion) override;
-
-  /**
    * See CompositableForwarder::UseTexture
    */
   virtual void UseTexture(CompositableClient* aCompositable,
                           TextureClient* aClient) override;
   virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
                                          TextureClient* aClientOnBlack,
                                          TextureClient* aClientOnWhite) override;
 #ifdef MOZ_WIDGET_GONK
--- a/gfx/layers/ipc/SharedBufferManagerChild.cpp
+++ b/gfx/layers/ipc/SharedBufferManagerChild.cpp
@@ -270,24 +270,27 @@ SharedBufferManagerChild::AllocGrallocBu
                                                 const uint32_t& aUsage,
                                                 mozilla::layers::MaybeMagicGrallocBufferHandle* aHandle)
 {
   // These are protected functions, we can just assert and ask the caller to test
   MOZ_ASSERT(aSize.width >= 0 && aSize.height >= 0);
 
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   mozilla::layers::MaybeMagicGrallocBufferHandle handle;
-  SendAllocateGrallocBuffer(aSize, aFormat, aUsage, &handle);
+  if (!SendAllocateGrallocBuffer(aSize, aFormat, aUsage, &handle)) {
+    return false;
+  }
   if (handle.type() != mozilla::layers::MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle) {
     return false;
   }
   *aHandle = handle.get_MagicGrallocBufferHandle().mRef;
 
   {
     MutexAutoLock lock(mBufferMutex);
+    MOZ_ASSERT(mBuffers.count(handle.get_MagicGrallocBufferHandle().mRef.mKey)==0);
     mBuffers[handle.get_MagicGrallocBufferHandle().mRef.mKey] = handle.get_MagicGrallocBufferHandle().mGraphicBuffer;
   }
   return true;
 #else
   NS_RUNTIMEABORT("No GrallocBuffer for you");
   return true;
 #endif
 }
@@ -360,21 +363,10 @@ SharedBufferManagerChild::GetGraphicBuff
   if (mBuffers.count(key) == 0) {
     printf_stderr("SharedBufferManagerChild::GetGraphicBuffer -- invalid key");
     return nullptr;
   }
   return mBuffers[key];
 }
 #endif
 
-bool
-SharedBufferManagerChild::IsValidKey(int64_t key)
-{
-#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
-  if (mBuffers.count(key) != 1) {
-    return false;
-  }
-#endif
-  return true;
-}
-
 } /* namespace layers */
 } /* namespace mozilla */
--- a/gfx/layers/ipc/SharedBufferManagerChild.h
+++ b/gfx/layers/ipc/SharedBufferManagerChild.h
@@ -108,18 +108,16 @@ public:
   DropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aHandle);
 
   virtual bool RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aHandle);
 
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   android::sp<android::GraphicBuffer> GetGraphicBuffer(int64_t key);
 #endif
 
-  bool IsValidKey(int64_t key);
-
   base::Thread* GetThread() const;
 
   MessageLoop* GetMessageLoop() const;
 
   static bool IsCreated();
 
   static base::Thread* sSharedBufferManagerChildThread;
   static SharedBufferManagerChild* sSharedBufferManagerChildSingleton;
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -122,16 +122,17 @@ GrallocTextureHostOGL::GrallocTextureHos
 GrallocTextureHostOGL::~GrallocTextureHostOGL()
 {
   DestroyEGLImage();
 }
 
 void
 GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   mCompositor = static_cast<CompositorOGL*>(aCompositor);
   if (mGLTextureSource) {
     mGLTextureSource->SetCompositor(mCompositor);
   }
 
   if (mCompositor && aCompositor != mCompositor) {
     DestroyEGLImage();
   }
@@ -238,22 +239,16 @@ GrallocTextureHostOGL::GetAsSurface() {
                                                   GetSize(), GetFormat());
   RefPtr<gfx::DataSourceSurface> surf = CreateDataSourceSurfaceByCloning(grallocTempSurf);
 
   graphicBuffer->unlock();
 
   return surf.forget();
 }
 
-TextureSource*
-GrallocTextureHostOGL::GetTextureSources()
-{
-  return nullptr;
-}
-
 void
 GrallocTextureHostOGL::UnbindTextureSource()
 {
   // Clear the reference to the TextureSource (if any), because we know that
   // another TextureHost is being bound to the TextureSource. This means that
   // we will have to re-do gl->fEGLImageTargetTexture2D next time we go through
   // BindTextureSource (otherwise we would have skipped it).
   // Note that this doesn't "unlock" the gralloc buffer or force it to be
--- a/gfx/layers/opengl/GrallocTextureHost.h
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -48,18 +48,16 @@ public:
   virtual LayerRenderState GetRenderState() override;
 
   virtual void PrepareTextureSource(CompositableTextureSourceRef& aTextureSource) override;
 
   virtual bool BindTextureSource(CompositableTextureSourceRef& aTextureSource) override;
 
   virtual void UnbindTextureSource() override;
 
-  virtual TextureSource* GetTextureSources() override;
-
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   virtual TextureHostOGL* AsHostOGL() override
   {
     return this;
   }
 #endif
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override;
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h
@@ -69,19 +69,20 @@ public:
   virtual void DeallocateDeviceData() override {}
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual bool Lock() override;
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
-  virtual TextureSource* GetTextureSources() override
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
   {
-    return mTextureSource;
+    aTexture = mTextureSource;
+    return !!aTexture;
   }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
   }
 
   gl::GLContext* gl() const;
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -304,16 +304,17 @@ TextureImageTextureSourceOGL::CopyTo(con
   mCompositor->BlitTextureImageHelper()->BlitTextureImage(mTexImage, aSourceRect,
                                                   dest->mTexImage, aDestRect);
   dest->mTexImage->MarkValid();
 }
 
 void
 TextureImageTextureSourceOGL::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
 
   if (!glCompositor || (mCompositor != glCompositor)) {
     DeallocateDeviceData();
     mCompositor = glCompositor;
   }
 }
 
@@ -409,16 +410,17 @@ GLTextureSource::BindTexture(GLenum aTex
   gl()->fActiveTexture(aTextureUnit);
   gl()->fBindTexture(mTextureTarget, mTextureHandle);
   ApplyFilterToBoundTexture(gl(), aFilter, mTextureTarget);
 }
 
 void
 GLTextureSource::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   mCompositor = static_cast<CompositorOGL*>(aCompositor);
 }
 
 bool
 GLTextureSource::IsValid() const
 {
   return !!gl() && mTextureHandle != 0;
 }
@@ -467,16 +469,17 @@ SurfaceTextureSource::BindTexture(GLenum
   mSurfTex->UpdateTexImage();
 
   ApplyFilterToBoundTexture(gl(), aFilter, mTextureTarget);
 }
 
 void
 SurfaceTextureSource::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   if (mCompositor != aCompositor) {
     DeallocateDeviceData();
   }
 
   mCompositor = static_cast<CompositorOGL*>(aCompositor);
 }
 
 bool
@@ -548,16 +551,17 @@ void
 SurfaceTextureHost::Unlock()
 {
   mSurfTex->Detach();
 }
 
 void
 SurfaceTextureHost::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
   mCompositor = glCompositor;
   if (mTextureSource) {
     mTextureSource->SetCompositor(glCompositor);
   }
 }
 
 gfx::SurfaceFormat
@@ -608,16 +612,17 @@ EGLImageTextureSource::BindTexture(GLenu
   gl()->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mImage);
 
   ApplyFilterToBoundTexture(gl(), aFilter, mTextureTarget);
 }
 
 void
 EGLImageTextureSource::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   mCompositor = static_cast<CompositorOGL*>(aCompositor);
 }
 
 bool
 EGLImageTextureSource::IsValid() const
 {
   return !!gl();
 }
@@ -689,16 +694,17 @@ EGLImageTextureHost::Lock()
 void
 EGLImageTextureHost::Unlock()
 {
 }
 
 void
 EGLImageTextureHost::SetCompositor(Compositor* aCompositor)
 {
+  MOZ_ASSERT(aCompositor);
   CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
   mCompositor = glCompositor;
   if (mTextureSource) {
     mTextureSource->SetCompositor(glCompositor);
   }
 }
 
 gfx::SurfaceFormat
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -395,19 +395,20 @@ public:
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
-  virtual TextureSource* GetTextureSources() override
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
   {
-    return mTextureSource;
+    aTexture = mTextureSource;
+    return !!aTexture;
   }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
   }
 
   gl::GLContext* gl() const;
@@ -487,19 +488,20 @@ public:
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
-  virtual TextureSource* GetTextureSources() override
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
   {
-    return mTextureSource;
+    aTexture = mTextureSource;
+    return !!aTexture;
   }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
   }
 
   gl::GLContext* gl() const;
--- a/gfx/src/nsPoint.h
+++ b/gfx/src/nsPoint.h
@@ -21,18 +21,23 @@ struct nsPoint : public mozilla::gfx::Ba
   nsPoint() : Super() {}
   nsPoint(const nsPoint& aPoint) : Super(aPoint) {}
   nsPoint(nscoord aX, nscoord aY) : Super(aX, aY) {}
 
   inline nsIntPoint ScaleToNearestPixels(float aXScale, float aYScale,
                                          nscoord aAppUnitsPerPixel) const;
   inline nsIntPoint ToNearestPixels(nscoord aAppUnitsPerPixel) const;
 
-  // Converts this point from aFromAPP, an appunits per pixel ratio, to aToAPP.
-  inline nsPoint ConvertAppUnits(int32_t aFromAPP, int32_t aToAPP) const;
+  /**
+   * Return this point scaled to a different appunits per pixel (APP) ratio.
+   * @param aFromAPP the APP to scale from
+   * @param aToAPP the APP to scale to
+   */
+  MOZ_WARN_UNUSED_RESULT inline nsPoint
+    ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const;
 };
 
 // nsIntPoint represents a point in one of the types of pixels.
 // Uses of nsIntPoint should eventually be converted to CSSIntPoint,
 // LayoutDeviceIntPoint, etc. (see layout/base/Units.h).
 
 struct nsIntPoint : public mozilla::gfx::BasePoint<int32_t, nsIntPoint> {
   typedef mozilla::gfx::BasePoint<int32_t, nsIntPoint> Super;
@@ -55,17 +60,17 @@ nsPoint::ScaleToNearestPixels(float aXSc
 
 inline nsIntPoint
 nsPoint::ToNearestPixels(nscoord aAppUnitsPerPixel) const
 {
   return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
 }
 
 inline nsPoint
-nsPoint::ConvertAppUnits(int32_t aFromAPP, int32_t aToAPP) const
+nsPoint::ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP != aToAPP) {
     nsPoint point;
     point.x = NSToCoordRound(NSCoordScale(x, aFromAPP, aToAPP));
     point.y = NSToCoordRound(NSCoordScale(y, aFromAPP, aToAPP));
     return point;
   }
   return *this;
--- a/gfx/src/nsRect.h
+++ b/gfx/src/nsRect.h
@@ -54,28 +54,28 @@ struct NS_GFX nsRect :
     MOZ_COUNT_DTOR(nsRect);
   }
 #endif
 
   // We have saturating versions of all the Union methods. These avoid
   // overflowing nscoord values in the 'width' and 'height' fields by
   // clamping the width and height values to nscoord_MAX if necessary.
 
-  nsRect SaturatingUnion(const nsRect& aRect) const
+  MOZ_WARN_UNUSED_RESULT nsRect SaturatingUnion(const nsRect& aRect) const
   {
     if (IsEmpty()) {
       return aRect;
     } else if (aRect.IsEmpty()) {
       return *static_cast<const nsRect*>(this);
     } else {
       return SaturatingUnionEdges(aRect);
     }
   }
 
-  nsRect SaturatingUnionEdges(const nsRect& aRect) const
+  MOZ_WARN_UNUSED_RESULT nsRect SaturatingUnionEdges(const nsRect& aRect) const
   {
 #ifdef NS_COORD_IS_FLOAT
     return UnionEdges(aRect);
 #else
     nsRect result;
     result.x = std::min(aRect.x, x);
     int64_t w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x;
     if (MOZ_UNLIKELY(w > nscoord_MAX)) {
@@ -102,25 +102,25 @@ struct NS_GFX nsRect :
     }
     result.height = nscoord(h);
     return result;
 #endif
   }
 
 #ifndef NS_COORD_IS_FLOAT
   // Make all nsRect Union methods be saturating.
-  nsRect UnionEdges(const nsRect& aRect) const
+  MOZ_WARN_UNUSED_RESULT nsRect UnionEdges(const nsRect& aRect) const
   {
     return SaturatingUnionEdges(aRect);
   }
   void UnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
   {
     *this = aRect1.UnionEdges(aRect2);
   }
-  nsRect Union(const nsRect& aRect) const
+  MOZ_WARN_UNUSED_RESULT nsRect Union(const nsRect& aRect) const
   {
     return SaturatingUnion(aRect);
   }
   void UnionRect(const nsRect& aRect1, const nsRect& aRect2)
   {
     *this = aRect1.Union(aRect2);
   }
 #endif
@@ -129,35 +129,52 @@ struct NS_GFX nsRect :
   {
     *this = aRect1.SaturatingUnion(aRect2);
   }
   void SaturatingUnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
   {
     *this = aRect1.SaturatingUnionEdges(aRect2);
   }
 
-  // Converts this rect from aFromAPP, an appunits per pixel ratio, to aToAPP.
-  // In the RoundOut version we make the rect the smallest rect containing the
-  // unrounded result. In the RoundIn version we make the rect the largest rect
-  // contained in the unrounded result.
-  // Note: this can turn an empty rectangle into a non-empty rectangle
-  inline nsRect ConvertAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const;
-  inline nsRect ConvertAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const;
+  /**
+   * Return this rect scaled to a different appunits per pixel (APP) ratio.
+   * In the RoundOut version we make the rect the smallest rect containing the
+   * unrounded result. In the RoundIn version we make the rect the largest rect
+   * contained in the unrounded result.
+   * @param aFromAPP the APP to scale from
+   * @param aToAPP the APP to scale to
+   * @note this can turn an empty rectangle into a non-empty rectangle
+   */
+  MOZ_WARN_UNUSED_RESULT inline nsRect
+    ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const;
+  MOZ_WARN_UNUSED_RESULT inline nsRect
+    ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const;
+
+  MOZ_WARN_UNUSED_RESULT inline nsIntRect
+  ScaleToNearestPixels(float aXScale, float aYScale,
+                       nscoord aAppUnitsPerPixel) const;
 
-  inline nsIntRect ScaleToNearestPixels(float aXScale, float aYScale,
-                                        nscoord aAppUnitsPerPixel) const;
-  inline nsIntRect ToNearestPixels(nscoord aAppUnitsPerPixel) const;
+  MOZ_WARN_UNUSED_RESULT inline nsIntRect
+  ToNearestPixels(nscoord aAppUnitsPerPixel) const;
+
+  // Note: this can turn an empty rectangle into a non-empty rectangle
+  MOZ_WARN_UNUSED_RESULT inline nsIntRect
+  ScaleToOutsidePixels(float aXScale, float aYScale,
+                       nscoord aAppUnitsPerPixel) const;
+
   // Note: this can turn an empty rectangle into a non-empty rectangle
-  inline nsIntRect ScaleToOutsidePixels(float aXScale, float aYScale,
-                                        nscoord aAppUnitsPerPixel) const;
-  // Note: this can turn an empty rectangle into a non-empty rectangle
-  inline nsIntRect ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
-  inline nsIntRect ScaleToInsidePixels(float aXScale, float aYScale,
-                                       nscoord aAppUnitsPerPixel) const;
-  inline nsIntRect ToInsidePixels(nscoord aAppUnitsPerPixel) const;
+  MOZ_WARN_UNUSED_RESULT inline nsIntRect
+  ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
+
+  MOZ_WARN_UNUSED_RESULT inline nsIntRect
+  ScaleToInsidePixels(float aXScale, float aYScale,
+                      nscoord aAppUnitsPerPixel) const;
+
+  MOZ_WARN_UNUSED_RESULT inline nsIntRect
+  ToInsidePixels(nscoord aAppUnitsPerPixel) const;
 
   // This is here only to keep IPDL-generated code happy. DO NOT USE.
   bool operator==(const nsRect& aRect) const
   {
     return IsEqualEdges(aRect);
   }
 };
 
@@ -175,17 +192,18 @@ struct NS_GFX nsIntRect :
   nsIntRect(const nsIntPoint& aOrigin, const nsIntSize &aSize) : Super(aOrigin, aSize)
   {
   }
   nsIntRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight) :
       Super(aX, aY, aWidth, aHeight)
   {
   }
 
-  inline nsRect ToAppUnits(nscoord aAppUnitsPerPixel) const;
+  MOZ_WARN_UNUSED_RESULT inline nsRect
+  ToAppUnits(nscoord aAppUnitsPerPixel) const;
 
   // Returns a special nsIntRect that's used in some places to signify
   // "all available space".
   static const nsIntRect& GetMaxSizedIntRect() {
     static const nsIntRect r(0, 0, INT32_MAX, INT32_MAX);
     return r;
   }
 
@@ -196,17 +214,17 @@ struct NS_GFX nsIntRect :
   }
 };
 
 /*
  * App Unit/Pixel conversions
  */
 
 inline nsRect
-nsRect::ConvertAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const
+nsRect::ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP == aToAPP) {
     return *this;
   }
 
   nsRect rect;
   nscoord right = NSToCoordCeil(NSCoordScale(XMost(), aFromAPP, aToAPP));
   nscoord bottom = NSToCoordCeil(NSCoordScale(YMost(), aFromAPP, aToAPP));
@@ -214,17 +232,17 @@ nsRect::ConvertAppUnitsRoundOut(int32_t 
   rect.y = NSToCoordFloor(NSCoordScale(y, aFromAPP, aToAPP));
   rect.width = (right - rect.x);
   rect.height = (bottom - rect.y);
 
   return rect;
 }
 
 inline nsRect
-nsRect::ConvertAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const
+nsRect::ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP == aToAPP) {
     return *this;
   }
 
   nsRect rect;
   nscoord right = NSToCoordFloor(NSCoordScale(XMost(), aFromAPP, aToAPP));
   nscoord bottom = NSToCoordFloor(NSCoordScale(YMost(), aFromAPP, aToAPP));
--- a/gfx/src/nsRegion.cpp
+++ b/gfx/src/nsRegion.cpp
@@ -634,52 +634,52 @@ nsRegion& nsRegion::Transform (const gfx
   pixman_region32_init_rects(&region, boxes, n);
 
   pixman_region32_fini(&mImpl);
   mImpl = region;
   return *this;
 }
 
 
-nsRegion nsRegion::ConvertAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const
+nsRegion nsRegion::ScaleToOtherAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP == aToAPP) {
     return *this;
   }
 
   nsRegion region = *this;
   int n;
   pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
   for (int i=0; i<n; i++) {
     nsRect rect = BoxToRect(boxes[i]);
-    rect = rect.ConvertAppUnitsRoundOut(aFromAPP, aToAPP);
+    rect = rect.ScaleToOtherAppUnitsRoundOut(aFromAPP, aToAPP);
     boxes[i] = RectToBox(rect);
   }
 
   pixman_region32_t pixmanRegion;
   // This will union all of the rectangles and runs in about O(n lg(n))
   pixman_region32_init_rects(&pixmanRegion, boxes, n);
 
   pixman_region32_fini(&region.mImpl);
   region.mImpl = pixmanRegion;
   return region;
 }
 
-nsRegion nsRegion::ConvertAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const
+nsRegion nsRegion::ScaleToOtherAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP == aToAPP) {
     return *this;
   }
 
   nsRegion region = *this;
   int n;
   pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
   for (int i=0; i<n; i++) {
     nsRect rect = BoxToRect(boxes[i]);
-    rect = rect.ConvertAppUnitsRoundIn(aFromAPP, aToAPP);
+    rect = rect.ScaleToOtherAppUnitsRoundIn(aFromAPP, aToAPP);
     boxes[i] = RectToBox(rect);
   }
 
   pixman_region32_t pixmanRegion;
   // This will union all of the rectangles and runs in about O(n lg(n))
   pixman_region32_init_rects(&pixmanRegion, boxes, n);
 
   pixman_region32_fini(&region.mImpl);
--- a/gfx/src/nsRegion.h
+++ b/gfx/src/nsRegion.h
@@ -280,21 +280,28 @@ public:
   {
     // Work around pixman bug. Sometimes pixman creates regions with 1 rect
     // that's empty.
     uint32_t result = pixman_region32_n_rects(Impl());
     return (result == 1 && GetBounds().IsEmpty()) ? 0 : result;
   }
   const nsRect GetBounds () const { return BoxToRect(mImpl.extents); }
   uint64_t Area () const;
-  // Converts this region from aFromAPP, an appunits per pixel ratio, to
-  // aToAPP. This applies nsRect::ConvertAppUnitsRoundOut/In to each rect of
-  // the region.
-  nsRegion ConvertAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const;
-  nsRegion ConvertAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
+
+  /**
+   * Return this region scaled to a different appunits per pixel (APP) ratio.
+   * This applies nsRect::ScaleToOtherAppUnitsRoundOut/In to each rect of the region.
+   * @param aFromAPP the APP to scale from
+   * @param aToAPP the APP to scale to
+   * @note this can turn an empty region into a non-empty region
+   */
+  MOZ_WARN_UNUSED_RESULT nsRegion
+    ScaleToOtherAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const;
+  MOZ_WARN_UNUSED_RESULT nsRegion
+    ScaleToOtherAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
   nsRegion& ScaleRoundOut(float aXScale, float aYScale);
   nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
   nsRegion& Transform (const gfx3DMatrix &aTransform);
   nsIntRegion ScaleToOutsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
   nsIntRegion ScaleToInsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
   nsIntRegion ScaleToNearestPixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
   nsIntRegion ToOutsidePixels (nscoord aAppUnitsPerPixel) const;
   nsIntRegion ToNearestPixels (nscoord aAppUnitsPerPixel) const;
--- a/gfx/src/nsSize.h
+++ b/gfx/src/nsSize.h
@@ -21,18 +21,23 @@ struct nsSize : public mozilla::gfx::Bas
 
   nsSize() : Super() {}
   nsSize(nscoord aWidth, nscoord aHeight) : Super(aWidth, aHeight) {}
 
   inline nsIntSize ScaleToNearestPixels(float aXScale, float aYScale,
                                         nscoord aAppUnitsPerPixel) const;
   inline nsIntSize ToNearestPixels(nscoord aAppUnitsPerPixel) const;
 
-  // Converts this size from aFromAPP, an appunits per pixel ratio, to aToAPP.
-  inline nsSize ConvertAppUnits(int32_t aFromAPP, int32_t aToAPP) const;
+  /**
+   * Return this size scaled to a different appunits per pixel (APP) ratio.
+   * @param aFromAPP the APP to scale from
+   * @param aToAPP the APP to scale to
+   */
+  MOZ_WARN_UNUSED_RESULT inline nsSize
+    ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const;
 };
 
 struct nsIntSize : public mozilla::gfx::BaseSize<int32_t, nsIntSize> {
   typedef mozilla::gfx::BaseSize<int32_t, nsIntSize> Super;
 
   nsIntSize() : Super() {}
   nsIntSize(int32_t aWidth, int32_t aHeight) : Super(aWidth, aHeight) {}
 
@@ -54,17 +59,17 @@ nsSize::ScaleToNearestPixels(float aXSca
 
 inline nsIntSize
 nsSize::ToNearestPixels(nscoord aAppUnitsPerPixel) const
 {
   return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
 }
 
 inline nsSize
-nsSize::ConvertAppUnits(int32_t aFromAPP, int32_t aToAPP) const {
+nsSize::ScaleToOtherAppUnits(int32_t aFromAPP, int32_t aToAPP) const {
   if (aFromAPP != aToAPP) {
     nsSize size;
     size.width = NSToCoordRound(NSCoordScale(width, aFromAPP, aToAPP));
     size.height = NSToCoordRound(NSCoordScale(height, aFromAPP, aToAPP));
     return size;
   }
   return *this;
 }
--- a/gfx/thebes/gfxVR.cpp
+++ b/gfx/thebes/gfxVR.cpp
@@ -605,28 +605,32 @@ VRHMDManagerOculusImpl::Init()
 
   if (!PlatformInit())
     return false;
 
   int count = ovrHmd_Detect();
 
   for (int i = 0; i < count; ++i) {
     ovrHmd hmd = ovrHmd_Create(i);
+    if (!hmd)
+      continue;
     nsRefPtr<HMDInfoOculus> oc = new HMDInfoOculus(hmd);
     mOculusHMDs.AppendElement(oc);
   }
 
   // VRAddTestDevices == 1: add test device only if no real devices present
   // VRAddTestDevices == 2: add test device always
   if ((count == 0 && gfxPrefs::VRAddTestDevices() == 1) ||
       (gfxPrefs::VRAddTestDevices() == 2))
   {
     ovrHmd hmd = ovrHmd_CreateDebug(ovrHmd_DK2);
-    nsRefPtr<HMDInfoOculus> oc = new HMDInfoOculus(hmd);
-    mOculusHMDs.AppendElement(oc);
+    if (hmd) {
+      nsRefPtr<HMDInfoOculus> oc = new HMDInfoOculus(hmd);
+      mOculusHMDs.AppendElement(oc);
+    }
   }
 
   mOculusInitialized = true;
   return true;
 }
 
 void
 VRHMDManagerOculusImpl::Destroy()
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -2130,17 +2130,17 @@ public:
           // The qpcVBlank is always AFTER Now(), so it behaves like b2g
           // Using WaitForVBlank, the whole system dies :/
           WinUtils::dwmFlushProcPtr();
           HRESULT hr = WinUtils::dwmGetCompositionTimingInfoPtr(0, &vblankTime);
           vsync = TimeStamp::Now();
           if (SUCCEEDED(hr)) {
             QueryPerformanceCounter(&qpcNow);
             QPC_TIME adjust = qpcNow.QuadPart - vblankTime.qpcVBlank;
-            MOZ_ASSERT(adjust > 0);
+            MOZ_ASSERT(adjust >= 0);
             uint64_t usAdjust = (adjust * microseconds) / frequency.QuadPart;
             vsync -= TimeDuration::FromMicroseconds((double) usAdjust);
           }
         } // end for
       }
 
     private:
       virtual ~D3DVsyncDisplay()
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -80,17 +80,17 @@ nsICODecoder::FinishInternal()
   // We shouldn't be called in error cases
   MOZ_ASSERT(!HasError(), "Shouldn't call FinishInternal after error!");
 
   // Finish the internally used decoder as well
   if (mContainedDecoder) {
     mContainedDecoder->FinishSharedDecoder();
     mDecodeDone = mContainedDecoder->GetDecodeDone();
     mProgress |= mContainedDecoder->TakeProgress();
-    mInvalidRect.Union(mContainedDecoder->TakeInvalidRect());
+    mInvalidRect.UnionRect(mInvalidRect, mContainedDecoder->TakeInvalidRect());
   }
 }
 
 // Returns a buffer filled with the bitmap file header in little endian:
 // Signature 2 bytes 'BM'
 // FileSize      4 bytes File size in bytes
 // reserved      4 bytes unused (=0)
 // DataOffset    4 bytes File offset to Raster Data
@@ -593,17 +593,17 @@ nsICODecoder::WriteInternal(const char* 
   }
 }
 
 bool
 nsICODecoder::WriteToContainedDecoder(const char* aBuffer, uint32_t aCount)
 {
   mContainedDecoder->Write(aBuffer, aCount);
   mProgress |= mContainedDecoder->TakeProgress();
-  mInvalidRect.Union(mContainedDecoder->TakeInvalidRect());
+  mInvalidRect.UnionRect(mInvalidRect, mContainedDecoder->TakeInvalidRect());
   if (mContainedDecoder->HasDataError()) {
     mDataError = mContainedDecoder->HasDataError();
   }
   if (mContainedDecoder->HasDecoderError()) {
     PostDecoderError(mContainedDecoder->GetDecoderError());
   }
   return !HasError();
 }
@@ -641,17 +641,17 @@ nsresult
 nsICODecoder::AllocateFrame(const nsIntSize& aTargetSize /* = nsIntSize() */)
 {
   nsresult rv;
 
   if (mContainedDecoder) {
     rv = mContainedDecoder->AllocateFrame(aTargetSize);
     mCurrentFrame = mContainedDecoder->GetCurrentFrameRef();
     mProgress |= mContainedDecoder->TakeProgress();
-    mInvalidRect.Union(mContainedDecoder->TakeInvalidRect());
+    mInvalidRect.UnionRect(mInvalidRect, mContainedDecoder->TakeInvalidRect());
     return rv;
   }
 
   // Grab a strong ref that we'll later hand over to the contained decoder. This
   // lets us avoid creating a RawAccessFrameRef off-main-thread.
   rv = Decoder::AllocateFrame(aTargetSize);
   mRefForContainedDecoder = GetCurrentFrameRef();
   return rv;
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -1171,65 +1171,73 @@ js::AsmJSModuleToString(JSContext *cx, H
 {
     AsmJSModule &module = ModuleFunctionToModuleObject(fun).module();
 
     uint32_t begin = module.srcStart();
     uint32_t end = module.srcEndAfterCurly();
     ScriptSource *source = module.scriptSource();
     StringBuffer out(cx);
 
-    // Whether the function has been created with a Function ctor
-    bool funCtor = begin == 0 && end == source->length() && source->argumentsNotIncluded();
-
     if (addParenToLambda && fun->isLambda() && !out.append("("))
         return nullptr;
 
     if (!out.append("function "))
         return nullptr;
 
     if (fun->atom() && !out.append(fun->atom()))
         return nullptr;
 
-    if (funCtor) {
-        // Functions created with the function constructor don't have arguments in their source.
-        if (!out.append("("))
+    bool haveSource = source->hasSourceData();
+    if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
+        return nullptr;
+
+    if (!haveSource) {
+        if (!out.append("() {\n    [sourceless code]\n}"))
             return nullptr;
-
-        if (PropertyName *argName = module.globalArgumentName()) {
-            if (!out.append(argName))
+    } else {
+        // Whether the function has been created with a Function ctor
+        bool funCtor = begin == 0 && end == source->length() && source->argumentsNotIncluded();
+        if (funCtor) {
+            // Functions created with the function constructor don't have arguments in their source.
+            if (!out.append("("))
                 return nullptr;
-        }
-        if (PropertyName *argName = module.importArgumentName()) {
-            if (!out.append(", ") || !out.append(argName))
-                return nullptr;
-        }
-        if (PropertyName *argName = module.bufferArgumentName()) {
-            if (!out.append(", ") || !out.append(argName))
+
+            if (PropertyName *argName = module.globalArgumentName()) {
+                if (!out.append(argName))
+                    return nullptr;
+            }
+            if (PropertyName *argName = module.importArgumentName()) {
+                if (!out.append(", ") || !out.append(argName))
+                    return nullptr;
+            }
+            if (PropertyName *argName = module.bufferArgumentName()) {
+                if (!out.append(", ") || !out.append(argName))
+                    return nullptr;
+            }
+
+            if (!out.append(") {\n"))
                 return nullptr;
         }
 
-        if (!out.append(") {\n"))
+        Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
+        if (!src)
+            return nullptr;
+
+        if (module.strict()) {
+            if (!AppendUseStrictSource(cx, fun, src, out))
+                return nullptr;
+        } else {
+            if (!out.append(src))
+                return nullptr;
+        }
+
+        if (funCtor && !out.append("\n}"))
             return nullptr;
     }
 
-    Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
-    if (!src)
-        return nullptr;
-
-    if (module.strict()) {
-        if (!AppendUseStrictSource(cx, fun, src, out))
-            return nullptr;
-    } else {
-        if (!out.append(src))
-            return nullptr;
-    }
-
-    if (funCtor && !out.append("\n}"))
-        return nullptr;
-
     if (addParenToLambda && fun->isLambda() && !out.append(")"))
         return nullptr;
 
     return out.finishString();
 }
 
 bool
 js::IsAsmJSModuleLoadedFromCache(JSContext *cx, unsigned argc, Value *vp)
@@ -1271,39 +1279,52 @@ js::AsmJSFunctionToString(JSContext *cx,
     AsmJSModule &module = FunctionToEnclosingModule(fun);
     const AsmJSModule::ExportedFunction &f = FunctionToExportedFunction(fun, module);
     uint32_t begin = module.srcStart() + f.startOffsetInModule();
     uint32_t end = module.srcStart() + f.endOffsetInModule();
 
     ScriptSource *source = module.scriptSource();
     StringBuffer out(cx);
 
-    // asm.js functions cannot have been created with a Function constructor
-    // as they belong within a module.
-    MOZ_ASSERT(!(begin == 0 && end == source->length() && source->argumentsNotIncluded()));
-
     if (!out.append("function "))
         return nullptr;
 
-    if (module.strict()) {
-        // AppendUseStrictSource expects its input to start right after the
-        // function name, so split the source chars from the src into two parts:
-        // the function name and the rest (arguments + body).
+    bool haveSource = source->hasSourceData();
+    if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
+        return nullptr;
 
+    if (!haveSource) {
         // asm.js functions can't be anonymous
         MOZ_ASSERT(fun->atom());
         if (!out.append(fun->atom()))
             return nullptr;
-
-        size_t nameEnd = begin + fun->atom()->length();
-        Rooted<JSFlatString*> src(cx, source->substring(cx, nameEnd, end));
-        if (!AppendUseStrictSource(cx, fun, src, out))
+        if (!out.append("() {\n    [sourceless code]\n}"))
             return nullptr;
     } else {
-        Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
-        if (!src)
-            return nullptr;
-        if (!out.append(src))
-            return nullptr;
+        // asm.js functions cannot have been created with a Function constructor
+        // as they belong within a module.
+        MOZ_ASSERT(!(begin == 0 && end == source->length() && source->argumentsNotIncluded()));
+
+        if (module.strict()) {
+            // AppendUseStrictSource expects its input to start right after the
+            // function name, so split the source chars from the src into two parts:
+            // the function name and the rest (arguments + body).
+
+            // asm.js functions can't be anonymous
+            MOZ_ASSERT(fun->atom());
+            if (!out.append(fun->atom()))
+                return nullptr;
+
+            size_t nameEnd = begin + fun->atom()->length();
+            Rooted<JSFlatString*> src(cx, source->substring(cx, nameEnd, end));
+            if (!AppendUseStrictSource(cx, fun, src, out))
+                return nullptr;
+        } else {
+            Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
+            if (!src)
+                return nullptr;
+            if (!out.append(src))
+                return nullptr;
+        }
     }
 
     return out.finishString();
 }
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -881,18 +881,18 @@ class AsmJSModule
     }
     bool strict() const {
         return pod.strict_;
     }
     bool usesSignalHandlersForInterrupt() const {
         return pod.usesSignalHandlers_;
     }
     bool usesSignalHandlersForOOB() const {
-#ifdef JS_CODEGEN_X64
-        return usesSignalHandlersForInterrupt();
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+        return pod.usesSignalHandlers_;
 #else
         return false;
 #endif
     }
     bool loadedFromCache() const {
         return loadedFromCache_;
     }
 
--- a/js/src/asmjs/AsmJSSignalHandlers.cpp
+++ b/js/src/asmjs/AsmJSSignalHandlers.cpp
@@ -308,17 +308,17 @@ enum { REG_EIP = 14 };
 #if !defined(XP_WIN)
 # define CONTEXT ucontext_t
 #endif
 
 // Define a context type for use in the emulator code. This is usually just
 // the same as CONTEXT, but on Mac we use a different structure since we call
 // into the emulator code from a Mach exception handler rather than a
 // sigaction-style signal handler.
-#if defined(XP_MACOSX)
+#if defined(XP_MACOSX) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 # if defined(JS_CODEGEN_X64)
 struct macos_x64_context {
     x86_thread_state64_t thread;
     x86_float_state64_t float_;
 };
 #  define EMULATOR_CONTEXT macos_x64_context
 # else
 struct macos_x86_context {
@@ -346,16 +346,18 @@ ContextToPC(CONTEXT *context)
 {
 #ifdef JS_CODEGEN_NONE
     MOZ_CRASH();
 #else
      return reinterpret_cast<uint8_t**>(&PC_sig(context));
 #endif
 }
 
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+
 #if defined(JS_CODEGEN_X64)
 MOZ_COLD static void
 SetFPRegToNaN(size_t size, void *fp_reg)
 {
     MOZ_RELEASE_ASSERT(size <= Simd128DataSize);
     memset(fp_reg, 0, Simd128DataSize);
     switch (size) {
       case 4: *static_cast<float *>(fp_reg) = GenericNaN(); break;
@@ -515,16 +517,17 @@ AddressOfGPRegisterSlot(EMULATOR_CONTEXT
       case X86Encoding::r13: return &context->thread.__r13;
       case X86Encoding::r14: return &context->thread.__r14;
       case X86Encoding::r15: return &context->thread.__r15;
       default: break;
     }
     MOZ_CRASH();
 }
 # endif  // !XP_MACOSX
+#endif // JS_CODEGEN_X64
 
 MOZ_COLD static void
 SetRegisterToCoercedUndefined(EMULATOR_CONTEXT *context, size_t size,
                               const Disassembler::OtherOperand &value)
 {
     if (value.kind() == Disassembler::OtherOperand::FPR)
         SetFPRegToNaN(size, AddressOfFPRegisterSlot(context, value.fpr()));
     else
@@ -709,18 +712,16 @@ EmulateHeapAccess(EMULATOR_CONTEXT *cont
           case Disassembler::HeapAccess::Unknown:
             MOZ_CRASH("Failed to disassemble instruction");
         }
     }
 
     return end;
 }
 
-#endif // JS_CODEGEN_X64
-
 #if defined(XP_WIN)
 
 static bool
 HandleFault(PEXCEPTION_POINTERS exception)
 {
     EXCEPTION_RECORD *record = exception->ExceptionRecord;
     CONTEXT *context = exception->ContextRecord;
 
@@ -738,17 +739,16 @@ HandleFault(PEXCEPTION_POINTERS exceptio
     if (!rt || rt->handlingSignal)
         return false;
     AutoSetHandlingSignal handling(rt);
 
     AsmJSActivation *activation = rt->asmJSActivationStack();
     if (!activation)
         return false;
 
-# if defined(JS_CODEGEN_X64)
     const AsmJSModule &module = activation->module();
 
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     uint8_t *faultingAddress = reinterpret_cast<uint8_t *>(record->ExceptionInformation[1]);
     if (!module.maybeHeap() ||
         faultingAddress < module.maybeHeap() ||
         faultingAddress >= module.maybeHeap() + AsmJSMappedSize)
@@ -775,21 +775,17 @@ HandleFault(PEXCEPTION_POINTERS exceptio
         return false;
     }
 
     const AsmJSHeapAccess *heapAccess = module.lookupHeapAccess(pc);
     if (!heapAccess)
         return false;
 
     *ppc = EmulateHeapAccess(context, pc, faultingAddress, heapAccess, module);
-
     return true;
-# else
-    return false;
-# endif
 }
 
 static LONG WINAPI
 AsmJSFaultHandler(LPEXCEPTION_POINTERS exception)
 {
     if (HandleFault(exception))
         return EXCEPTION_CONTINUE_EXECUTION;
 
@@ -881,17 +877,16 @@ HandleMachException(JSRuntime *rt, const
     AsmJSActivation *activation = rt->asmJSActivationStack();
     if (!activation)
         return false;
 
     const AsmJSModule &module = activation->module();
     if (!module.containsFunctionPC(pc))
         return false;
 
-# if defined(JS_CODEGEN_X64)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     uint8_t *faultingAddress = reinterpret_cast<uint8_t *>(request.body.code[1]);
     if (!module.maybeHeap() ||
         faultingAddress < module.maybeHeap() ||
         faultingAddress >= module.maybeHeap() + AsmJSMappedSize)
     {
         return false;
@@ -907,19 +902,16 @@ HandleMachException(JSRuntime *rt, const
     kret = thread_set_state(rtThread, float_state, (thread_state_t)&context.float_, float_state_count);
     if (kret != KERN_SUCCESS)
         return false;
     kret = thread_set_state(rtThread, thread_state, (thread_state_t)&context.thread, thread_state_count);
     if (kret != KERN_SUCCESS)
         return false;
 
     return true;
-# else
-    return false;
-# endif
 }
 
 // Taken from mach_exc in /usr/include/mach/mach_exc.defs.
 static const mach_msg_id_t sExceptionId = 2405;
 
 // The choice of id here is arbitrary, the only constraint is that sQuitId != sExceptionId.
 static const mach_msg_id_t sQuitId = 42;
 
@@ -1095,17 +1087,16 @@ HandleFault(int signum, siginfo_t *info,
     AsmJSActivation *activation = rt->asmJSActivationStack();
     if (!activation)
         return false;
 
     const AsmJSModule &module = activation->module();
     if (!module.containsFunctionPC(pc))
         return false;
 
-# if defined(JS_CODEGEN_X64)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     uint8_t *faultingAddress = reinterpret_cast<uint8_t *>(info->si_addr);
     if (!module.maybeHeap() ||
         faultingAddress < module.maybeHeap() ||
         faultingAddress >= module.maybeHeap() + AsmJSMappedSize)
     {
         return false;
@@ -1113,19 +1104,16 @@ HandleFault(int signum, siginfo_t *info,
 
     const AsmJSHeapAccess *heapAccess = module.lookupHeapAccess(pc);
     if (!heapAccess)
         return false;
 
     *ppc = EmulateHeapAccess(context, pc, faultingAddress, heapAccess, module);
 
     return true;
-# else
-    return false;
-# endif
 }
 
 static struct sigaction sPrevSEGVHandler;
 
 static void
 AsmJSFaultHandler(int signum, siginfo_t *info, void *context)
 {
     if (HandleFault(signum, info, context))
@@ -1147,16 +1135,18 @@ AsmJSFaultHandler(int signum, siginfo_t 
         sPrevSEGVHandler.sa_sigaction(signum, info, context);
     else if (sPrevSEGVHandler.sa_handler == SIG_DFL || sPrevSEGVHandler.sa_handler == SIG_IGN)
         sigaction(signum, &sPrevSEGVHandler, nullptr);
     else
         sPrevSEGVHandler.sa_handler(signum);
 }
 #endif
 
+#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+
 static void
 RedirectIonBackedgesToInterruptCheck(JSRuntime *rt)
 {
     if (jit::JitRuntime *jitRuntime = rt->jitRuntime()) {
         // If the backedge list is being mutated, the pc must be in C++ code and
         // thus not in a JIT iloop. We assume that the interrupt flag will be
         // checked at least once before entering JIT code (if not, no big deal;
         // the browser will just request another interrupt in a second).
@@ -1204,17 +1194,17 @@ JitInterruptHandler(int signum, siginfo_
     if (JSRuntime *rt = RuntimeForCurrentThread())
         RedirectJitCodeToInterruptCheck(rt, (CONTEXT*)context);
 }
 #endif
 
 bool
 js::EnsureSignalHandlersInstalled(JSRuntime *rt)
 {
-#if defined(XP_MACOSX)
+#if defined(XP_MACOSX) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
     // On OSX, each JSRuntime gets its own handler thread.
     if (!rt->asmJSMachExceptionHandler.installed() && !rt->asmJSMachExceptionHandler.install(rt))
         return false;
 #endif
 
     // All the rest of the handlers are process-wide and thus must only be
     // installed once. We assume that there are no races creating the first
     // JSRuntime of the process.
@@ -1238,56 +1228,60 @@ js::EnsureSignalHandlersInstalled(JSRunt
     }
 # if defined(MOZ_LINKER)
     // Signal handling is broken on some android systems.
     if (IsSignalHandlingBroken())
         return false;
 # endif
 #endif
 
-#if defined(XP_WIN)
-    // Windows uses SuspendThread to stop the main thread from another thread,
-    // so the only handler we need is for asm.js out-of-bound faults.
-    if (!AddVectoredExceptionHandler(/* FirstHandler = */ true, AsmJSFaultHandler))
-        return false;
-#else
     // The interrupt handler allows the main thread to be paused from another
     // thread (see InterruptRunningJitCode).
+#if defined(XP_WIN)
+    // Windows uses SuspendThread to stop the main thread from another thread.
+#else
     struct sigaction interruptHandler;
     interruptHandler.sa_flags = SA_SIGINFO;
     interruptHandler.sa_sigaction = &JitInterruptHandler;
     sigemptyset(&interruptHandler.sa_mask);
     struct sigaction prev;
     if (sigaction(sInterruptSignal, &interruptHandler, &prev))
         MOZ_CRASH("unable to install interrupt handler");
 
     // There shouldn't be any other handlers installed for sInterruptSignal. If
     // there are, we could always forward, but we need to understand what we're
     // doing to avoid problematic interference.
     if ((prev.sa_flags & SA_SIGINFO && prev.sa_sigaction) ||
         (prev.sa_handler != SIG_DFL && prev.sa_handler != SIG_IGN))
     {
         MOZ_CRASH("contention for interrupt signal");
     }
+#endif // defined(XP_WIN)
 
-    // Lastly, install a SIGSEGV handler to handle safely-out-of-bounds asm.js
-    // heap access. OSX handles seg faults via the Mach exception handler above,
-    // so don't install AsmJSFaultHandler.
-# if !defined(XP_MACOSX)
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+    // Install a SIGSEGV handler to handle safely-out-of-bounds asm.js heap
+    // access.
+# if defined(XP_WIN)
+    if (!AddVectoredExceptionHandler(/* FirstHandler = */ true, AsmJSFaultHandler))
+        return false;
+# elif defined(XP_MACOSX)
+    // OSX handles seg faults via the Mach exception handler above, so don't
+    // install AsmJSFaultHandler.
+# else
     // SA_NODEFER allows us to reenter the signal handler if we crash while
     // handling the signal, and fall through to the Breakpad handler by testing
     // handlingSignal.
     struct sigaction faultHandler;
     faultHandler.sa_flags = SA_SIGINFO | SA_NODEFER;
     faultHandler.sa_sigaction = &AsmJSFaultHandler;
     sigemptyset(&faultHandler.sa_mask);
     if (sigaction(SIGSEGV, &faultHandler, &sPrevSEGVHandler))
         MOZ_CRASH("unable to install segv handler");
-# endif // defined(XP_MACOSX)
-#endif // defined(XP_WIN)
+# endif
+#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 
     sResult = true;
     return true;
 }
 
 // JSRuntime::requestInterrupt sets interrupt_ (which is checked frequently by
 // C++ code at every Baseline JIT loop backedge) and jitStackLimit_ (which is
 // checked at every Baseline and Ion JIT function prologue). The remaining
--- a/js/src/asmjs/AsmJSSignalHandlers.h
+++ b/js/src/asmjs/AsmJSSignalHandlers.h
@@ -14,43 +14,43 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef asmjs_AsmJSSignalHandlers_h
 #define asmjs_AsmJSSignalHandlers_h
 
-struct JSRuntime;
-
-#ifdef XP_MACOSX
+#if defined(XP_MACOSX) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 # include <mach/mach.h>
 # include "jslock.h"
 #endif
 
+struct JSRuntime;
+
 namespace js {
 
 // Set up any signal/exception handlers needed to execute code in the given
 // runtime. Return whether runtime can:
 //  - rely on fault handler support for avoiding asm.js heap bounds checks
 //  - rely on InterruptRunningJitCode to halt running Ion/asm.js from any thread
 bool
 EnsureSignalHandlersInstalled(JSRuntime *rt);
 
 // Force any currently-executing asm.js code to call HandleExecutionInterrupt.
 extern void
 InterruptRunningJitCode(JSRuntime *rt);
 
+#if defined(XP_MACOSX) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 // On OSX we are forced to use the lower-level Mach exception mechanism instead
 // of Unix signals. Mach exceptions are not handled on the victim's stack but
 // rather require an extra thread. For simplicity, we create one such thread
 // per JSRuntime (upon the first use of asm.js in the JSRuntime). This thread
 // and related resources are owned by AsmJSMachExceptionHandler which is owned
 // by JSRuntime.
-#ifdef XP_MACOSX
 class AsmJSMachExceptionHandler
 {
     bool installed_;
     PRThread *thread_;
     mach_port_t port_;
 
     void uninstall();
 
--- a/js/src/asmjs/AsmJSValidate.h
+++ b/js/src/asmjs/AsmJSValidate.h
@@ -49,36 +49,38 @@ typedef frontend::ParseContext<frontend:
 // amount and the entire function should be reparsed from the beginning.
 extern bool
 ValidateAsmJS(ExclusiveContext *cx, AsmJSParser &parser, frontend::ParseNode *stmtList,
              bool *validated);
 
 // The assumed page size; dynamically checked in ValidateAsmJS.
 const size_t AsmJSPageSize = 4096;
 
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+
 // Targets define AsmJSImmediateRange to be the size of an address immediate,
 // and AsmJSCheckedImmediateRange, to be the size of an address immediate that
 // can be supported by signal-handler OOB handling.
 static_assert(jit::AsmJSCheckedImmediateRange <= jit::AsmJSImmediateRange,
               "AsmJSImmediateRange should be the size of an unconstrained "
               "address immediate");
 
-#ifdef JS_CPU_X64
-// On x64, the internal ArrayBuffer data array is inflated to 4GiB (only the
+// To support the use of signal handlers for catching Out Of Bounds accesses,
+// the internal ArrayBuffer data array is inflated to 4GiB (only the
 // byteLength portion of which is accessible) so that out-of-bounds accesses
 // (made using a uint32 index) are guaranteed to raise a SIGSEGV.
 // Then, an additional extent is added to permit folding of small immediate
 // values into addresses. And finally, unaligned accesses and mask optimizations
 // might also try to access a few bytes after this limit, so just inflate it by
 // AsmJSPageSize.
 static const size_t AsmJSMappedSize = 4 * 1024ULL * 1024ULL * 1024ULL +
                                       jit::AsmJSCheckedImmediateRange +
                                       AsmJSPageSize;
 
-#endif
+#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 
 // From the asm.js spec Linking section:
 //  the heap object's byteLength must be either
 //    2^n for n in [12, 24)
 //  or
 //    2^24 * n for n >= 1.
 
 inline uint32_t
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -228,61 +228,16 @@ if test -n "$gonkdir" ; then
     fi
 
     AC_DEFINE(ANDROID)
     AC_DEFINE(GONK)
 else
     MOZ_ANDROID_NDK
 fi
 
-dnl ==============================================================
-dnl Get mozilla version from central milestone file
-dnl ==============================================================
-MOZILLA_VERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir`
-MOZILLA_UAVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --uaversion`
-MOZILLA_SYMBOLVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --symbolversion`
-
-AC_DEFINE_UNQUOTED(MOZILLA_VERSION,"$MOZILLA_VERSION")
-AC_DEFINE_UNQUOTED(MOZILLA_VERSION_U,$MOZILLA_VERSION)
-AC_DEFINE_UNQUOTED(MOZILLA_UAVERSION,"$MOZILLA_UAVERSION")
-AC_SUBST(MOZILLA_SYMBOLVERSION)
-
-# Separate version into components for use in shared object naming etc
-changequote(,)
-MOZJS_MAJOR_VERSION=`echo $MOZILLA_VERSION | sed "s|\(^[0-9]*\)\.[0-9]*.*|\1|"`
-MOZJS_MINOR_VERSION=`echo $MOZILLA_VERSION | sed "s|^[0-9]*\.\([0-9]*\).*|\1|"`
-MOZJS_PATCH_VERSION=`echo $MOZILLA_VERSION | sed "s|^[0-9]*\.[0-9]*[^0-9]*||"`
-IS_ALPHA=`echo $MOZILLA_VERSION | grep '[ab]'`
-
-dnl XXX in a temporary bid to avoid developer anger at renaming files
-dnl XXX before "js" symlinks exist, don't change names.
-dnl
-dnl if test -n "$JS_STANDALONE"; then
-dnl JS_SHELL_NAME=js$MOZJS_MAJOR_VERSION
-dnl JS_CONFIG_NAME=js$MOZJS_MAJOR_VERSION-config
-dnl else
-JS_SHELL_NAME=js
-JS_CONFIG_NAME=js-config
-dnl fi
-
-changequote([,])
-if test -n "$IS_ALPHA"; then
-  changequote(,)
-  MOZJS_ALPHA=`echo $MOZILLA_VERSION | sed "s|^[0-9]*\.[0-9\.]*\([^0-9]\).*|\1|"`
-  changequote([,])
-fi
-AC_DEFINE_UNQUOTED(MOZJS_MAJOR_VERSION,$MOZJS_MAJOR_VERSION)
-AC_DEFINE_UNQUOTED(MOZJS_MINOR_VERSION,$MOZJS_MINOR_VERSION)
-AC_SUBST(JS_SHELL_NAME)
-AC_SUBST(JS_CONFIG_NAME)
-AC_SUBST(MOZJS_MAJOR_VERSION)
-AC_SUBST(MOZJS_MINOR_VERSION)
-AC_SUBST(MOZJS_PATCH_VERSION)
-AC_SUBST(MOZJS_ALPHA)
-
 dnl ========================================================
 dnl Checks for compilers.
 dnl ========================================================
 
 dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269)
 AR_FLAGS='crs $@'
 
 if test "$COMPILE_ENVIRONMENT"; then
@@ -733,16 +688,62 @@ fi
 if test "$COMPILE_ENVIRONMENT"; then
 
 AC_PATH_XTRA
 
 XCFLAGS="$X_CFLAGS"
 
 fi # COMPILE_ENVIRONMENT
 
+dnl ==============================================================
+dnl Get mozilla version from central milestone file
+dnl ==============================================================
+MOZILLA_VERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir`
+MOZILLA_UAVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --uaversion`
+MOZILLA_SYMBOLVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --symbolversion`
+
+AC_DEFINE_UNQUOTED(MOZILLA_VERSION,"$MOZILLA_VERSION")
+AC_DEFINE_UNQUOTED(MOZILLA_VERSION_U,$MOZILLA_VERSION)
+AC_DEFINE_UNQUOTED(MOZILLA_UAVERSION,"$MOZILLA_UAVERSION")
+AC_SUBST(MOZILLA_SYMBOLVERSION)
+
+# Separate version into components for use in shared object naming etc
+changequote(,)
+MOZJS_MAJOR_VERSION=`echo $MOZILLA_VERSION | sed "s|\(^[0-9]*\)\.[0-9]*.*|\1|"`
+MOZJS_MINOR_VERSION=`echo $MOZILLA_VERSION | sed "s|^[0-9]*\.\([0-9]*\).*|\1|"`
+MOZJS_PATCH_VERSION=`echo $MOZILLA_VERSION | sed "s|^[0-9]*\.[0-9]*[^0-9]*||"`
+IS_ALPHA=`echo $MOZILLA_VERSION | grep '[ab]'`
+
+dnl XXX in a temporary bid to avoid developer anger at renaming files
+dnl XXX before "js" symlinks exist, don't change names.
+dnl
+dnl if test -n "$JS_STANDALONE"; then
+dnl JS_SHELL_NAME=js$MOZJS_MAJOR_VERSION
+dnl JS_CONFIG_NAME=js$MOZJS_MAJOR_VERSION-config
+dnl else
+JS_SHELL_NAME=js
+JS_CONFIG_NAME=js-config
+dnl fi
+
+changequote([,])
+if test -n "$IS_ALPHA"; then
+  changequote(,)
+  MOZJS_ALPHA=`echo $MOZILLA_VERSION | sed "s|^[0-9]*\.[0-9\.]*\([^0-9]\).*|\1|"`
+  changequote([,])
+fi
+AC_DEFINE_UNQUOTED(MOZJS_MAJOR_VERSION,$MOZJS_MAJOR_VERSION)
+AC_DEFINE_UNQUOTED(MOZJS_MINOR_VERSION,$MOZJS_MINOR_VERSION)
+AC_SUBST(JS_SHELL_NAME)
+AC_SUBST(JS_CONFIG_NAME)
+AC_SUBST(MOZJS_MAJOR_VERSION)
+AC_SUBST(MOZJS_MINOR_VERSION)
+AC_SUBST(MOZJS_PATCH_VERSION)
+AC_SUBST(MOZJS_ALPHA)
+
+
 dnl ========================================================
 dnl set the defaults first
 dnl ========================================================
 AS_BIN=$AS
 AR_LIST='$(AR) t'
 AR_EXTRACT='$(AR) x'
 AR_DELETE='$(AR) d'
 AS='$(CC)'
@@ -3156,31 +3157,37 @@ elif test -n "$JS_MIPS_SIMULATOR"; then
     AC_DEFINE(JS_CODEGEN_MIPS)
     JS_CODEGEN_MIPS=1
 elif test "$CPU_ARCH" = "x86"; then
     AC_DEFINE(JS_CODEGEN_X86)
     JS_CODEGEN_X86=1
 elif test "$CPU_ARCH" = "x86_64"; then
     AC_DEFINE(JS_CODEGEN_X64)
     JS_CODEGEN_X64=1
+
+    dnl Signal-handler OOM checking requires large mprotected guard regions, so
+    dnl currently it is only implemented on x64.
+    AC_DEFINE(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+    ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB=1
 elif test "$CPU_ARCH" = "arm"; then
     AC_DEFINE(JS_CODEGEN_ARM)
     JS_CODEGEN_ARM=1
 elif test "$CPU_ARCH" = "mips"; then
     AC_DEFINE(JS_CODEGEN_MIPS)
     JS_CODEGEN_MIPS=1
 fi
 
 AC_SUBST(JS_ARM_SIMULATOR)
 AC_SUBST(JS_MIPS_SIMULATOR)
 AC_SUBST(JS_CODEGEN_ARM)
 AC_SUBST(JS_CODEGEN_MIPS)
 AC_SUBST(JS_CODEGEN_X86)
 AC_SUBST(JS_CODEGEN_X64)
 AC_SUBST(JS_CODEGEN_NONE)
+AC_SUBST(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 
 dnl ========================================================
 dnl jprof
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(jprof,
 [  --enable-jprof          Enable jprof profiling tool (needs mozilla/tools/jprof). Implies --enable-profiling.],
     MOZ_JPROF=1,
     MOZ_JPROF= )
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/testBug1147144.js
@@ -0,0 +1,14 @@
+load(libdir + 'asm.js');
+setLazyParsingEnabled(false)
+assertEq(eval(`(function asmModule() { "use asm"; function asmFun() {} return asmFun })`).toString(), "function asmModule() {\n    [sourceless code]\n}");
+assertEq(eval(`(function asmModule() { "use asm"; function asmFun() {} return asmFun })`).toSource(), "(function asmModule() {\n    [sourceless code]\n})");
+assertEq(eval(`(function asmModule() { "use asm"; function asmFun() {} return asmFun })`)().toString(), "function asmFun() {\n    [sourceless code]\n}");
+assertEq(eval(`(function asmModule() { "use asm"; function asmFun() {} return asmFun })`)().toSource(), "function asmFun() {\n    [sourceless code]\n}");
+assertEq((evaluate(`function asmModule1() { "use asm"; function asmFun() {} return asmFun }`), asmModule1).toString(), "function asmModule1() {\n    [sourceless code]\n}");
+assertEq((evaluate(`function asmModule2() { "use asm"; function asmFun() {} return asmFun }`), asmModule2).toSource(), "function asmModule2() {\n    [sourceless code]\n}");
+assertEq((evaluate(`function asmModule3() { "use asm"; function asmFun() {} return asmFun }`), asmModule3)().toString(), "function asmFun() {\n    [sourceless code]\n}");
+assertEq((evaluate(`function asmModule4() { "use asm"; function asmFun() {} return asmFun }`), asmModule4)().toSource(), "function asmFun() {\n    [sourceless code]\n}");
+assertEq(asmCompile(USE_ASM + `function asmFun() {} return asmFun`).toString(), "function anonymous() {\n    [sourceless code]\n}");
+assertEq(asmCompile(USE_ASM + `function asmFun() {} return asmFun`).toSource(), "(function anonymous() {\n    [sourceless code]\n})");
+assertEq(asmCompile(USE_ASM + `function asmFun() {} return asmFun`)().toString(), "function asmFun() {\n    [sourceless code]\n}");
+assertEq(asmCompile(USE_ASM + `function asmFun() {} return asmFun`)().toSource(), "function asmFun() {\n    [sourceless code]\n}");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1147907.js
@@ -0,0 +1,13 @@
+var evalInFrame = (function (global) {
+  var dbgGlobal = newGlobal();
+  var dbg = new dbgGlobal.Debugger();
+  return function evalInFrame(upCount, code) {
+    dbg.addDebuggee(global);
+    var frame = dbg.getNewestFrame().older;
+    var completion = frame.eval(code);
+  };
+})(this);
+var x = 5;
+let (x = eval("x++")) {
+  evalInFrame(0, ("for (var x = 0; x < 3; ++x) { (function(){})() } "))
+}
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -414,19 +414,18 @@ function rfloor_object(i) {
     assertRecoveredOnBailout(x, false);
     return i;
 }
 
 var uceFault_ceil_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_ceil_number'));
 function rceil_number(i) {
     var x = Math.ceil(-i - 0.12010799100);
     if (uceFault_ceil_number(i) || uceFault_ceil_number(i))
-        assertEq(x, - i);
-    // NYI: uses MMathFunction and not MCeil.
-    // assertRecoveredOnBailout(x, true);
+        assertEq(x, -i);
+    assertRecoveredOnBailout(x, true);
     return i;
 }
 
 var uceFault_round_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_round'));
 function rround_number(i) {
     var x = Math.round(i + 1.4);
     if (uceFault_round_number(i) || uceFault_round_number(i))
         assertEq(x, 100); /* = i + 1*/
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/lexical-check-4.js
@@ -0,0 +1,15 @@
+var caught = false;
+try {
+    (function() {
+        let x = (function f(y) {
+            if (y == 0) {
+                x
+                return
+            }
+            return f(y - 1)
+        })(3)
+    })()
+} catch(e) {
+    caught = true;
+}
+assertEq(caught, true);
--- a/js/src/jit-test/tests/xdr/lazy.js
+++ b/js/src/jit-test/tests/xdr/lazy.js
@@ -133,8 +133,28 @@ checkAfter = function (ctx) {
 };
 evalWithCache(test, {
   assertEqBytecode: true,  // Check that we re-encode the same thing.
   assertEqResult: true,    // The function should remain relazifiable, if it was
                            // during the first run.
   checkAfter: checkAfter   // Check that relazifying the restored function works
                            // if the original was relazifiable.
 });
+
+// Ensure that if a function is encoded when non-lazy but relazifiable, then
+// decoded, relazified, and then delazified, the result actually works.
+test = `
+  function f() { return true; };
+  var canBeLazy = isRelazifiableFunction(f) || isLazyFunction(f);
+  relazifyFunctions();
+  assertEq(isLazyFunction(f), canBeLazy);
+  f()`
+evalWithCache(test, { assertEqBytecode: true, assertEqResult: true });
+
+// And more of the same, in a slightly different way
+var g1 = newGlobal();
+var g2 = newGlobal();
+var res = "function f(){}";
+var code = cacheEntry(res + "; f();");
+evaluate(code, {global:g1, compileAndGo: true, saveBytecode: {value: true}});
+evaluate(code, {global:g2, loadBytecode: true});
+gc();
+assertEq(g2.f.toString(), res);
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -3054,12 +3054,26 @@ jit::JitSupportsFloatingPoint()
 }
 
 bool
 jit::JitSupportsSimd()
 {
     return js::jit::MacroAssembler::SupportsSimd();
 }
 
+bool
+jit::JitSupportsAtomics()
+{
+#if defined(JS_CODEGEN_ARM)
+    // Bug 1146902, bug 1077318: Enable Ion inlining of Atomics
+    // operations on ARM only when the CPU has byte, halfword, and
+    // doubleword load-exclusive and store-exclusive instructions,
+    // until we can add support for systems that don't have those.
+    return js::jit::HasLDSTREXBHD();
+#else
+    return true;
+#endif
+}
+
 // If you change these, please also change the comment in TempAllocator.
 /* static */ const size_t TempAllocator::BallastSize            = 16 * 1024;
 /* static */ const size_t TempAllocator::PreferredLifoChunkSize = 32 * 1024;
 
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -196,13 +196,14 @@ void ForbidCompilation(JSContext *cx, JS
 
 void PurgeCaches(JSScript *script);
 size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf);
 void DestroyJitScripts(FreeOp *fop, JSScript *script);
 void TraceJitScripts(JSTracer* trc, JSScript *script);
 
 bool JitSupportsFloatingPoint();
 bool JitSupportsSimd();
+bool JitSupportsAtomics();
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_Ion_h */
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -2824,16 +2824,19 @@ IonBuilder::inlineAtomicsStore(CallInfo 
 IonBuilder::InliningStatus
 IonBuilder::inlineAtomicsFence(CallInfo &callInfo)
 {
     if (callInfo.argc() != 0 || callInfo.constructing()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
     }
 
+    if (!JitSupportsAtomics())
+        return InliningStatus_NotInlined;
+
     callInfo.setImplicitlyUsedUnchecked();
 
     MMemoryBarrier *fence = MMemoryBarrier::New(alloc());
     current->add(fence);
     pushConstant(UndefinedValue());
 
     // Fences are considered effectful (they execute a memory barrier).
     if (!resumeAfter(fence))
@@ -2894,16 +2897,19 @@ IonBuilder::inlineAtomicsBinop(CallInfo 
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }
 
 bool
 IonBuilder::atomicsMeetsPreconditions(CallInfo &callInfo, Scalar::Type *arrayType)
 {
+    if (!JitSupportsAtomics())
+        return false;
+
     if (callInfo.getArg(0)->type() != MIRType_Object)
         return false;
 
     if (callInfo.getArg(1)->type() != MIRType_Int32)
         return false;
 
     // Ensure that the first argument is a valid SharedTypedArray.
     //
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1486,18 +1486,18 @@ class MSimdSplatX4
 class MSimdConstant
   : public MNullaryInstruction
 {
     SimdConstant value_;
 
   protected:
     MSimdConstant(const SimdConstant &v, MIRType type) : value_(v) {
         MOZ_ASSERT(IsSimdType(type));
+        setMovable();
         setResultType(type);
-        setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(SimdConstant)
     static MSimdConstant *New(TempAllocator &alloc, const SimdConstant &v, MIRType type) {
         return new(alloc) MSimdConstant(v, type);
     }
 
@@ -1522,16 +1522,17 @@ class MSimdConstant
 class MSimdConvert
   : public MUnaryInstruction,
     public SimdPolicy<0>::Data
 {
     MSimdConvert(MDefinition *obj, MIRType fromType, MIRType toType)
       : MUnaryInstruction(obj)
     {
         MOZ_ASSERT(IsSimdType(toType));
+        setMovable();
         setResultType(toType);
         specialization_ = fromType; // expects fromType as input
     }
 
   public:
     INSTRUCTION_HEADER(SimdConvert)
     static MSimdConvert *NewAsmJS(TempAllocator &alloc, MDefinition *obj, MIRType fromType,
                                   MIRType toType)
@@ -1559,16 +1560,17 @@ class MSimdConvert
 class MSimdReinterpretCast
   : public MUnaryInstruction,
     public SimdPolicy<0>::Data
 {
     MSimdReinterpretCast(MDefinition *obj, MIRType fromType, MIRType toType)
       : MUnaryInstruction(obj)
     {
         MOZ_ASSERT(IsSimdType(toType));
+        setMovable();
         setResultType(toType);
         specialization_ = fromType; // expects fromType as input
     }
 
   public:
     INSTRUCTION_HEADER(SimdReinterpretCast)
     static MSimdReinterpretCast* NewAsmJS(TempAllocator &alloc, MDefinition *obj, MIRType fromType,
                                           MIRType toType)
@@ -1603,16 +1605,17 @@ class MSimdExtractElement
     MSimdExtractElement(MDefinition *obj, MIRType vecType, MIRType scalarType, SimdLane lane)
       : MUnaryInstruction(obj), lane_(lane)
     {
         MOZ_ASSERT(IsSimdType(vecType));
         MOZ_ASSERT(uint32_t(lane) < SimdTypeToLength(vecType));
         MOZ_ASSERT(!IsSimdType(scalarType));
         MOZ_ASSERT(SimdTypeToScalarType(vecType) == scalarType);
 
+        setMovable();
         specialization_ = vecType;
         setResultType(scalarType);
     }
 
   public:
     INSTRUCTION_HEADER(SimdExtractElement)
 
     static MSimdExtractElement *NewAsmJS(TempAllocator &alloc, MDefinition *obj, MIRType type,
@@ -7048,16 +7051,17 @@ class MLexicalCheck
     public BoxPolicy<0>::Data
 {
     explicit MLexicalCheck(MDefinition *input)
       : MUnaryInstruction(input)
     {
         setResultType(MIRType_Value);
         setResultTypeSet(input->resultTypeSet());
         setMovable();
+        setGuard();
     }
 
   public:
     INSTRUCTION_HEADER(LexicalCheck)
 
     static MLexicalCheck *New(TempAllocator &alloc, MDefinition *input) {
         return new(alloc) MLexicalCheck(input);
     }
@@ -12630,16 +12634,20 @@ class MAsmJSLoadHeap
 
     MDefinition *ptr() const { return getOperand(0); }
     void replacePtr(MDefinition *newPtr) { replaceOperand(0, newPtr); }
     MemoryBarrierBits barrierBefore() const { return barrierBefore_; }
     MemoryBarrierBits barrierAfter() const { return barrierAfter_; }
 
     bool congruentTo(const MDefinition *ins) const override;
     AliasSet getAliasSet() const override {
+        // When a barrier is needed make the instruction effectful by
+        // giving it a "store" effect.
+        if (barrierBefore_|barrierAfter_)
+            return AliasSet::Store(AliasSet::AsmJSHeap);
         return AliasSet::Load(AliasSet::AsmJSHeap);
     }
     bool mightAlias(const MDefinition *def) const override;
 };
 
 class MAsmJSStoreHeap
   : public MBinaryInstruction,
     public MAsmJSHeapAccess,
--- a/js/src/jit/MIRGenerator.h
+++ b/js/src/jit/MIRGenerator.h
@@ -199,17 +199,19 @@ class MIRGenerator
     // minor GC while compilation happens off-thread. This Vector should only
     // be accessed on the main thread (IonBuilder, nursery GC or
     // CodeGenerator::link).
     ObjectVector nurseryObjects_;
 
     void addAbortedPreliminaryGroup(ObjectGroup *group);
 
     Label *outOfBoundsLabel_;
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
     bool usesSignalHandlersForAsmJSOOB_;
+#endif
 
     void setForceAbort() {
         shouldForceAbort_ = true;
     }
     bool shouldForceAbort() {
         return shouldForceAbort_;
     }
 
@@ -232,17 +234,17 @@ class MIRGenerator
     Label *outOfBoundsLabel() const {
         return outOfBoundsLabel_;
     }
     bool needsAsmJSBoundsCheckBranch(const MAsmJSHeapAccess *access) const {
         // A heap access needs a bounds-check branch if we're not relying on signal
         // handlers to catch errors, and if it's not proven to be within bounds.
         // We use signal-handlers on x64, but on x86 there isn't enough address
         // space for a guard region.
-#ifdef JS_CODEGEN_X64
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
         if (usesSignalHandlersForAsmJSOOB_)
             return false;
 #endif
         return access->needsBoundsCheck();
     }
 };
 
 } // namespace jit
--- a/js/src/jit/MIRGraph.cpp
+++ b/js/src/jit/MIRGraph.cpp
@@ -37,17 +37,19 @@ MIRGenerator::MIRGenerator(CompileCompar
     usesSimd_(false),
     usesSimdCached_(false),
     minAsmJSHeapLength_(0),
     modifiesFrameArguments_(false),
     instrumentedProfiling_(false),
     instrumentedProfilingIsCached_(false),
     nurseryObjects_(*alloc),
     outOfBoundsLabel_(outOfBoundsLabel),
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
     usesSignalHandlersForAsmJSOOB_(usesSignalHandlersForAsmJSOOB),
+#endif
     options(options)
 { }
 
 bool
 MIRGenerator::usesSimd()
 {
     if (usesSimdCached_)
         return usesSimd_;
--- a/js/src/jit/OptimizationTracking.cpp
+++ b/js/src/jit/OptimizationTracking.cpp
@@ -1035,16 +1035,21 @@ IonBuilder::startTrackingOptimizations()
         BytecodeSite *site = maybeTrackedOptimizationSite(current->trackedSite()->pc());
 
         if (!site) {
             site = current->trackedSite();
             site->setOptimizations(new(alloc()) TrackedOptimizations(alloc()));
             // OOMs are handled as if optimization tracking were turned off.
             if (!trackedOptimizationSites_.append(site))
                 site = nullptr;
+        } else {
+            // The same bytecode may be visited multiple times (see
+            // restartLoop). Only the last time matters, so clear any previous
+            // tracked optimizations.
+            site->optimizations()->clear();
         }
 
         if (site)
             current->updateTrackedSite(site);
     }
 }
 
 void
--- a/js/src/jit/OptimizationTracking.h
+++ b/js/src/jit/OptimizationTracking.h
@@ -102,16 +102,22 @@ class TrackedOptimizations : public Temp
 
   public:
     explicit TrackedOptimizations(TempAllocator &alloc)
       : types_(alloc),
         attempts_(alloc),
         currentAttempt_(UINT32_MAX)
     { }
 
+    void clear() {
+        types_.clear();
+        attempts_.clear();
+        currentAttempt_ = UINT32_MAX;
+    }
+
     bool trackTypeInfo(OptimizationTypeInfo &&ty);
 
     bool trackAttempt(JS::TrackedStrategy strategy);
     void amendAttempt(uint32_t index);
     void trackOutcome(JS::TrackedOutcome outcome);
     void trackSuccess();
 
     bool matchTypes(const TempOptimizationTypeInfoVector &other) const;
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -2045,34 +2045,44 @@ js::NewFunctionWithProto(ExclusiveContex
     RootedObject funobj(cx);
     // Don't mark asm.js module functions as singleton since they are
     // cloned (via CloneFunctionObjectIfNotSingleton) which assumes that
     // isSingleton implies isInterpreted.
     if (native && !IsAsmJSModuleNative(native))
         newKind = SingletonObject;
 #ifdef DEBUG
     RootedObject nonScopeParent(cx, SkipScopeParent(enclosingDynamicScope));
-    MOZ_ASSERT(!nonScopeParent || nonScopeParent == cx->global());
+    // We'd like to assert that nonScopeParent is null-or-global, but
+    // js::ExecuteInGlobalAndReturnScope and debugger eval bits mess that up.
+    // Assert that it's one of those or a debug scope proxy or the unqualified
+    // var obj, since it should still be ok to parent to the global in that
+    // case.
+    MOZ_ASSERT(!nonScopeParent || nonScopeParent == cx->global() ||
+               nonScopeParent->is<DebugScopeObject>() ||
+               nonScopeParent->isUnqualifiedVarObj());
 #endif
     funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, allocKind,
                                      newKind);
     if (!funobj)
         return nullptr;
 
     RootedFunction fun(cx, &funobj->as<JSFunction>());
 
     if (allocKind == JSFunction::ExtendedFinalizeKind)
         flags = JSFunction::Flags(flags | JSFunction::EXTENDED);
 
     /* Initialize all function members. */
     fun->setArgCount(uint16_t(nargs));
     fun->setFlags(flags);
     if (fun->isInterpreted()) {
         MOZ_ASSERT(!native);
-        fun->mutableScript().init(nullptr);
+        if (fun->isInterpretedLazy())
+            fun->initLazyScript(nullptr);
+        else
+            fun->initScript(nullptr);
         fun->initEnvironment(enclosingDynamicScope);
     } else {
         MOZ_ASSERT(fun->isNative());
         MOZ_ASSERT(native);
         fun->initNative(native, nullptr);
     }
     if (allocKind == JSFunction::ExtendedFinalizeKind)
         fun->initializeExtended();
@@ -2133,20 +2143,22 @@ js::CloneFunctionObject(JSContext *cx, H
     if (!cloneProto && fun->isStarGenerator()) {
         cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
         if (!cloneProto)
             return nullptr;
     }
 #ifdef DEBUG
     RootedObject realParent(cx, SkipScopeParent(parent));
     // We'd like to assert that realParent is null-or-global, but
-    // js::ExecuteInGlobalAndReturnScope messes that up.  Assert that it's one
-    // of those or the unqualified var obj, since it should still be ok to
-    // parent to the global in that case.
+    // js::ExecuteInGlobalAndReturnScope and debugger eval bits mess that up.
+    // Assert that it's one of those or a debug scope proxy or the unqualified
+    // var obj, since it should still be ok to parent to the global in that
+    // case.
     MOZ_ASSERT(!realParent || realParent == cx->global() ||
+               realParent->is<DebugScopeObject>() ||
                realParent->isUnqualifiedVarObj());
 #endif
     JSObject *cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto,
                                                  allocKind, newKind);
     if (!cloneobj)
         return nullptr;
     RootedFunction clone(cx, &cloneobj->as<JSFunction>());
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -329,21 +329,16 @@ class JSFunction : public js::NativeObje
         if (self->isInterpretedLazy() && !self->getOrCreateScript(cx))
             return false;
 
         *length = self->hasScript() ? self->nonLazyScript()->funLength()
                                     : (self->nargs() - self->hasRest());
         return true;
     }
 
-    js::HeapPtrScript &mutableScript() {
-        MOZ_ASSERT(isInterpreted());
-        return *(js::HeapPtrScript *)&u.i.s.script_;
-    }
-
     js::LazyScript *lazyScript() const {
         MOZ_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
         return u.i.s.lazy_;
     }
 
     js::LazyScript *lazyScriptOrNull() const {
         MOZ_ASSERT(isInterpretedLazy());
         return u.i.s.lazy_;
@@ -362,22 +357,20 @@ class JSFunction : public js::NativeObje
 
     bool isGenerator() const { return generatorKind() != js::NotGenerator; }
 
     bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
 
     bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
 
     void setScript(JSScript *script_) {
-        MOZ_ASSERT(hasScript());
         mutableScript() = script_;
     }
 
     void initScript(JSScript *script_) {
-        MOZ_ASSERT(hasScript());
         mutableScript().init(script_);
     }
 
     void setUnlazifiedScript(JSScript *script) {
         // Note: createScriptForLazilyInterpretedFunction triggers a barrier on
         // lazy script before it is overwritten here.
         MOZ_ASSERT(isInterpretedLazy());
         if (!lazyScript()->maybeScript())
@@ -446,16 +439,21 @@ class JSFunction : public js::NativeObje
                                   const js::Value *args, unsigned argslen);
 
     JSObject *getBoundFunctionTarget() const;
     const js::Value &getBoundFunctionThis() const;
     const js::Value &getBoundFunctionArgument(unsigned which) const;
     size_t getBoundFunctionArgumentCount() const;
 
   private:
+    js::HeapPtrScript &mutableScript() {
+        MOZ_ASSERT(hasScript());
+        return *(js::HeapPtrScript *)&u.i.s.script_;
+    }
+
     inline js::FunctionExtended *toExtended();
     inline const js::FunctionExtended *toExtended() const;
 
   public:
     inline bool isExtended() const {
         MOZ_ASSERT_IF(isTenured(), !!(flags() & EXTENDED) == (asTenured().getAllocKind() == ExtendedFinalizeKind));
         return !!(flags() & EXTENDED);
     }
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -308,17 +308,17 @@ js::math_ceil_impl(double x)
 bool
 js::math_ceil_handle(JSContext *cx, HandleValue v, MutableHandleValue res)
 {
     double d;
     if(!ToNumber(cx, v, &d))
         return false;
 
     double result = math_ceil_impl(d);
-    res.setDouble(result);
+    res.setNumber(result);
     return true;
 }
 
 bool
 js::math_ceil(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -479,17 +479,17 @@ XDRLazyFreeVariables(XDRState<mode> *xdr
 
     return true;
 }
 
 // Code the missing part needed to re-create a LazyScript from a JSScript.
 template<XDRMode mode>
 static bool
 XDRRelazificationInfo(XDRState<mode> *xdr, HandleFunction fun, HandleScript script,
-                      MutableHandle<LazyScript *> lazy)
+                      HandleObject enclosingScope, MutableHandle<LazyScript *> lazy)
 {
     MOZ_ASSERT_IF(mode == XDR_ENCODE, script->isRelazifiable() && script->maybeLazyScript());
     MOZ_ASSERT_IF(mode == XDR_ENCODE, !lazy->numInnerFunctions());
 
     JSContext *cx = xdr->cx();
 
     uint64_t packedFields;
     {
@@ -511,16 +511,19 @@ XDRRelazificationInfo(XDRState<mode> *xd
 
         if (mode == XDR_DECODE) {
             lazy.set(LazyScript::Create(cx, fun, packedFields, begin, end, lineno, column));
 
             // As opposed to XDRLazyScript, we need to restore the runtime bits
             // of the script, as we are trying to match the fact this function
             // has already been parsed and that it would need to be re-lazified.
             lazy->initRuntimeFields(packedFields);
+
+            MOZ_ASSERT(!lazy->sourceObject());
+            lazy->setParent(enclosingScope, &script->scriptSourceUnwrap());
         }
     }
 
     // Code free variables.
     if (!XDRLazyFreeVariables(xdr, lazy))
         return false;
 
     return true;
@@ -1076,17 +1079,17 @@ js::XDRScript(XDRState<mode> *xdr, Handl
             return false;
     }
 
     if (scriptBits & (1 << HasLazyScript)) {
         Rooted<LazyScript *> lazy(cx);
         if (mode == XDR_ENCODE)
             lazy = script->maybeLazyScript();
 
-        if (!XDRRelazificationInfo(xdr, fun, script, &lazy))
+        if (!XDRRelazificationInfo(xdr, fun, script, enclosingScope, &lazy))
             return false;
 
         if (mode == XDR_DECODE)
             script->setLazyScript(lazy);
     }
 
     if (mode == XDR_DECODE) {
         scriptp.set(script);
@@ -3178,35 +3181,33 @@ js::CloneScript(JSContext *cx, HandleObj
     MOZ_ASSERT_IF(dst->hasPollutedGlobalScope(), !dst->isRelazifiable());
     return dst;
 }
 
 bool
 js::CloneFunctionScript(JSContext *cx, HandleFunction original, HandleFunction clone,
                         PollutedGlobalScopeOption polluted, NewObjectKind newKind)
 {
-    MOZ_ASSERT(clone->isInterpreted());
-
     RootedScript script(cx, clone->nonLazyScript());
     MOZ_ASSERT(script);
     MOZ_ASSERT(script->compartment() == original->compartment());
 
     // The only scripts with enclosing static scopes that may be cloned across
     // compartments are non-strict, indirect eval scripts, as their dynamic
     // scope chains terminate in the global scope immediately.
     RootedObject scope(cx, script->enclosingStaticScope());
     if (script->compartment() != cx->compartment() && scope) {
         MOZ_ASSERT(!scope->as<StaticEvalObject>().isDirect() &&
                    !scope->as<StaticEvalObject>().isStrict());
         scope = StaticEvalObject::create(cx, NullPtr());
         if (!scope)
             return false;
     }
 
-    clone->mutableScript().init(nullptr);
+    clone->initScript(nullptr);
 
     JSScript *cscript = CloneScript(cx, scope, clone, script, polluted, newKind);
     if (!cscript)
         return false;
 
     clone->setScript(cscript);
     cscript->setFunction(clone);
 
@@ -3876,17 +3877,17 @@ LazyScript::hasUncompiledEnclosingScript
     //
     // If the enclosing scope is a function with a null script or has a script
     // without code, it was not successfully compiled.
 
     if (!enclosingScope() || !enclosingScope()->is<JSFunction>())
         return false;
 
     JSFunction &fun = enclosingScope()->as<JSFunction>();
-    return fun.isInterpreted() && (!fun.mutableScript() || !fun.nonLazyScript()->code());
+    return fun.isInterpreted() && (!fun.hasScript() || !fun.nonLazyScript()->code());
 }
 
 uint32_t
 LazyScript::staticLevel(JSContext *cx) const
 {
     for (StaticScopeIter<NoGC> ssi(enclosingScope()); !ssi.done(); ssi++) {
         if (ssi.type() == StaticScopeIter<NoGC>::Function)
             return ssi.funScript()->staticLevel() + 1;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -6240,17 +6240,17 @@ main(int argc, char **argv, char **envp)
     {
         return EXIT_FAILURE;
     }
 
     op.setArgTerminatesOptions("script", true);
     op.setArgCapturesRest("scriptArgs");
 
     switch (op.parseArgs(argc, argv)) {
-      case OptionParser::ParseHelp:
+      case OptionParser::EarlyExit:
         return EXIT_SUCCESS;
       case OptionParser::ParseError:
         op.printHelp(argv[0]);
         return EXIT_FAILURE;
       case OptionParser::Fail:
         return EXIT_FAILURE;
       case OptionParser::Okay:
         break;
--- a/js/src/shell/jsoptparse.cpp
+++ b/js/src/shell/jsoptparse.cpp
@@ -180,18 +180,18 @@ OptionParser::printHelp(const char *prog
     }
 
     if (descr) {
         putchar('\n');
         PrintParagraph(descr, 2, descrWidth, true);
         putchar('\n');
     }
 
-    if (ver)
-        printf("\nVersion: %s\n\n", ver);
+    if (version)
+        printf("\nVersion: %s\n\n", version);
 
     if (!arguments.empty()) {
         printf("Arguments:\n");
 
         static const char fmt[] = "  %s ";
         size_t fmtChars = sizeof(fmt) - 2;
         size_t lhsLen = 0;
         for (Option **it = arguments.begin(), **end = arguments.end(); it != end; ++it)
@@ -245,17 +245,25 @@ OptionParser::printHelp(const char *prog
             }
             for (; chars < lhsLen; ++chars)
                 putchar(' ');
             PrintParagraph(opt->help, lhsLen, helpWidth, false);
             putchar('\n');
         }
     }
 
-    return ParseHelp;
+    return EarlyExit;
+}
+
+OptionParser::Result
+OptionParser::printVersion()
+{
+    MOZ_ASSERT(version);
+    printf("%s\n", version);
+    return EarlyExit;
 }
 
 OptionParser::Result
 OptionParser::extractValue(size_t argc, char **argv, size_t *i, char **value)
 {
     MOZ_ASSERT(*i < argc);
     char *eq = strchr(argv[*i], '=');
     if (eq) {
@@ -279,16 +287,18 @@ OptionParser::handleOption(Option *opt, 
     if (opt->getTerminatesOptions())
         *optionsAllowed = false;
 
     switch (opt->kind) {
       case OptionKindBool:
       {
         if (opt == &helpOption)
             return printHelp(argv[0]);
+        if (opt == &versionOption)
+            return printVersion();
         opt->asBoolOption()->value = true;
         return Okay;
       }
       /*
        * Valued options are allowed to specify their values either via
        * successive arguments or a single --longflag=value argument.
        */
       case OptionKindString:
@@ -468,16 +478,19 @@ OptionParser::~OptionParser()
 Option *
 OptionParser::findOption(char shortflag)
 {
     for (Option **it = options.begin(), **end = options.end(); it != end; ++it) {
         if ((*it)->shortflag == shortflag)
             return *it;
     }
 
+    if (versionOption.shortflag == shortflag)
+        return &versionOption;
+
     return helpOption.shortflag == shortflag ? &helpOption : nullptr;
 }
 
 const Option *
 OptionParser::findOption(char shortflag) const
 {
     return const_cast<OptionParser *>(this)->findOption(shortflag);
 }
@@ -498,16 +511,19 @@ OptionParser::findOption(const char *lon
                 return *it;
         } else {
             if (strcmp(target, longflag) == 0)
                 return *it;
         }
   no_match:;
     }
 
+    if (strcmp(versionOption.longflag, longflag) == 0)
+        return &versionOption;
+
     return strcmp(helpOption.longflag, longflag) ? nullptr : &helpOption;
 }
 
 const Option *
 OptionParser::findOption(const char *longflag) const
 {
     return const_cast<OptionParser *>(this)->findOption(longflag);
 }
--- a/js/src/shell/jsoptparse.h
+++ b/js/src/shell/jsoptparse.h
@@ -188,29 +188,31 @@ class MultiStringRange
 class OptionParser
 {
   public:
     enum Result
     {
         Okay = 0,
         Fail,       /* As in, allocation fail. */
         ParseError, /* Successfully parsed but with an error. */
-        ParseHelp   /* Aborted on help flag. */
+        EarlyExit   /* Successfully parsed but exits the program,
+                     * for example with --help and --version. */
     };
 
   private:
     typedef Vector<detail::Option *, 0, SystemAllocPolicy> Options;
     typedef detail::Option Option;
     typedef detail::BoolOption BoolOption;
 
     Options     options;
     Options     arguments;
     BoolOption  helpOption;
+    BoolOption  versionOption;
     const char  *usage;
-    const char  *ver;
+    const char  *version;
     const char  *descr;
     size_t      descrWidth;
     size_t      helpWidth;
     size_t      nextArgument;
 
     // If '--' is passed, all remaining arguments should be interpreted as the
     // argument at index 'restArgument'. Defaults to the next unassigned
     // argument.
@@ -229,28 +231,30 @@ class OptionParser
     Result error(const char *fmt, ...);
     Result extractValue(size_t argc, char **argv, size_t *i, char **value);
     Result handleArg(size_t argc, char **argv, size_t *i, bool *optsAllowed);
     Result handleOption(Option *opt, size_t argc, char **argv, size_t *i, bool *optsAllowed);
 
   public:
     explicit OptionParser(const char *usage)
       : helpOption('h', "help", "Display help information"),
-        usage(usage), ver(nullptr), descr(nullptr), descrWidth(80), helpWidth(80),
+        versionOption('v', "version", "Display version information and exit"),
+        usage(usage), version(nullptr), descr(nullptr), descrWidth(80), helpWidth(80),
         nextArgument(0), restArgument(-1)
     {}
 
     ~OptionParser();
 
     Result parseArgs(int argc, char **argv);
     Result printHelp(const char *progname);
+    Result printVersion();
 
     /* Metadata */
 
-    void setVersion(const char *version) { ver = version; }
+    void setVersion(const char *v) { version = v; }
     void setHelpWidth(size_t width) { helpWidth = width; }
     void setDescriptionWidth(size_t width) { descrWidth = width; }
     void setDescription(const char *description) { descr = description; }
     void setHelpOption(char shortflag, const char *longflag, const char *help);
     void setArgTerminatesOptions(const char *name, bool enabled);
     void setArgCapturesRest(const char *name);
 
     /* Arguments: no further arguments may be added after a variadic argument. */
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -229,17 +229,17 @@ bool
 ArrayBufferObject::fun_isView(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setBoolean(args.get(0).isObject() &&
                            JS_IsArrayBufferViewObject(&args.get(0).toObject()));
     return true;
 }
 
-#ifdef JS_CPU_X64
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 static void
 ReleaseAsmJSMappedData(void *base)
 {
     MOZ_ASSERT(uintptr_t(base) % AsmJSPageSize == 0);
 #  ifdef XP_WIN
     VirtualFree(base, 0, MEM_RELEASE);
 #  else
     munmap(base, AsmJSMappedSize);
@@ -251,22 +251,22 @@ ReleaseAsmJSMappedData(void *base)
     }
 #   endif
 #  endif
 }
 #else
 static void
 ReleaseAsmJSMappedData(void *base)
 {
-    MOZ_CRASH("Only x64 has asm.js mapped buffers");
+    MOZ_CRASH("asm.js only uses mapped buffers when using signal-handler OOB checking");
 }
 #endif
 
 #ifdef NIGHTLY_BUILD
-# ifdef JS_CPU_X64
+# if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 static bool
 TransferAsmJSMappedBuffer(JSContext *cx, CallArgs args, Handle<ArrayBufferObject*> oldBuffer,
                           size_t newByteLength)
 {
     size_t oldByteLength = oldBuffer->byteLength();
     MOZ_ASSERT(oldByteLength % AsmJSPageSize == 0);
     MOZ_ASSERT(newByteLength % AsmJSPageSize == 0);
 
@@ -324,17 +324,17 @@ TransferAsmJSMappedBuffer(JSContext *cx,
     if (!newBuffer) {
         ReleaseAsmJSMappedData(data);
         return false;
     }
 
     args.rval().setObject(*newBuffer);
     return true;
 }
-# endif  // defined(JS_CPU_X64)
+# endif  // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 
 /*
  * Experimental implementation of ArrayBuffer.transfer:
  *   https://gist.github.com/andhow/95fb9e49996615764eff
  * which is currently in the early stages of proposal for ES7.
  */
 bool
 ArrayBufferObject::fun_transfer(JSContext *cx, unsigned argc, Value *vp)
@@ -388,17 +388,17 @@ ArrayBufferObject::fun_transfer(JSContex
         newByteLength = size_t(i32);
     }
 
     UniquePtr<uint8_t, JS::FreePolicy> newData;
     if (!newByteLength) {
         if (!ArrayBufferObject::neuter(cx, oldBuffer, oldBuffer->contents()))
             return false;
     } else {
-# ifdef JS_CPU_X64
+# if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
         // With a 4gb mapped asm.js buffer, we can simply enable/disable access
         // to the delta as long as the requested length is page-sized.
         if (oldBuffer->isAsmJSMapped() && (newByteLength % AsmJSPageSize) == 0)
             return TransferAsmJSMappedBuffer(cx, args, oldBuffer, newByteLength);
 # endif
 
         // Since we try to realloc below, only allow stealing malloc'd buffers.
         // If !hasMallocedContents, stealContents will malloc a copy which we
@@ -614,17 +614,17 @@ ArrayBufferObject::prepareForAsmJSNoSign
         memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
         buffer->changeContents(cx, contents);
     }
 
     buffer->setIsAsmJSMalloced();
     return true;
 }
 
-#ifdef JS_CODEGEN_X64
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 /* static */ bool
 ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer,
                                    bool usesSignalHandlers)
 {
     // If we can't use signal handlers, just do it like on other platforms.
     if (!usesSignalHandlers)
         return prepareForAsmJSNoSignals(cx, buffer);
 
@@ -680,23 +680,22 @@ ArrayBufferObject::prepareForAsmJS(JSCon
     // Swap the new elements into the ArrayBufferObject. Mark the
     // ArrayBufferObject so we don't do this again.
     BufferContents newContents = BufferContents::create<ASMJS_MAPPED>(data);
     buffer->changeContents(cx, newContents);
     MOZ_ASSERT(data == buffer->dataPointer());
 
     return true;
 }
-#else // JS_CODEGEN_X64
+#else // ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB
 bool
 ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer,
                                    bool usesSignalHandlers)
 {
-    // Platforms other than x64 don't use signalling for bounds checking, so
-    // just use the variant with no signals.
+    // Just use the variant with no signals.
     MOZ_ASSERT(!usesSignalHandlers);
     return prepareForAsmJSNoSignals(cx, buffer);
 }
 #endif
 
 ArrayBufferObject::BufferContents
 ArrayBufferObject::createMappedContents(int fd, size_t offset, size_t length)
 {
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -1085,17 +1085,17 @@ struct JSRuntime : public JS::shadow::Ru
      * Head of circular list of all enabled Debuggers that have
      * onNewGlobalObject handler methods established.
      */
     JSCList             onNewGlobalObjectWatchers;
 
     /* Client opaque pointers */
     void                *data;
 
-#ifdef XP_MACOSX
+#if defined(XP_MACOSX) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
     js::AsmJSMachExceptionHandler asmJSMachExceptionHandler;
 #endif
 
   private:
     // Whether EnsureSignalHandlersInstalled succeeded in installing all the
     // relevant handlers for this platform.
     bool signalHandlersInstalled_;
 
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -62,17 +62,17 @@ MarkValidRegion(void *addr, size_t len)
     return true;
 #else
     if (mprotect(addr, len, PROT_READ | PROT_WRITE))
         return false;
     return true;
 #endif
 }
 
-#ifdef JS_CODEGEN_X64
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 // Since this SharedArrayBuffer will likely be used for asm.js code, prepare it
 // for asm.js by mapping the 4gb protected zone described in AsmJSValidate.h.
 // Since we want to put the SharedArrayBuffer header immediately before the
 // heap but keep the heap page-aligned, allocate an extra page before the heap.
 static const uint64_t SharedArrayMappedSize = AsmJSMappedSize + AsmJSPageSize;
 static_assert(sizeof(SharedArrayRawBuffer) < AsmJSPageSize, "Page size not big enough");
 
 // If there are too many 4GB buffers live we run up against system resource
@@ -92,17 +92,17 @@ SharedArrayRawBuffer::New(JSContext *cx,
     // The value (uint32_t)-1 is used as a signal in various places,
     // so guard against it on principle.
     MOZ_ASSERT(length != (uint32_t)-1);
 
     // Add a page for the header and round to a page boundary.
     uint32_t allocSize = (length + 2*AsmJSPageSize - 1) & ~(AsmJSPageSize - 1);
     if (allocSize <= length)
         return nullptr;
-#ifdef JS_CODEGEN_X64
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
     // Test >= to guard against the case where multiple extant runtimes
     // race to allocate.
     if (++numLive >= maxLive) {
         JSRuntime *rt = cx->runtime();
         if (rt->largeAllocationFailureCallback)
             rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
         if (numLive >= maxLive) {
             numLive--;
@@ -148,17 +148,17 @@ SharedArrayRawBuffer::dropReference()
 {
     // Drop the reference to the buffer.
     uint32_t refcount = --this->refcount; // Atomic.
 
     // If this was the final reference, release the buffer.
     if (refcount == 0) {
         uint8_t *p = this->dataPointer() - AsmJSPageSize;
         MOZ_ASSERT(uintptr_t(p) % AsmJSPageSize == 0);
-#ifdef JS_CODEGEN_X64
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
         numLive--;
         UnmapMemory(p, SharedArrayMappedSize);
 #       if defined(MOZ_VALGRIND) \
            && defined(VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE)
         // Tell Valgrind/Memcheck to recommence reporting accesses in the
         // previously-inaccessible region.
         VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(p, SharedArrayMappedSize);
 #       endif
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -31,16 +31,17 @@
 #include "nsIJARURI.h"
 #include "nsNetUtil.h"
 #include "jsprf.h"
 #include "nsJSPrincipals.h"
 #include "nsJSUtils.h"
 #include "xpcprivate.h"
 #include "xpcpublic.h"
 #include "nsContentUtils.h"
+#include "nsXULAppAPI.h"
 #include "WrapperFactory.h"
 
 #include "mozilla/AddonPathService.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 #include "mozilla/MacroForEach.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/ScriptSettings.h"
@@ -367,45 +368,17 @@ mozJSComponentLoader::LoadModule(FileLoc
         return nullptr;
 
     nsCOMPtr<nsIComponentManager> cm;
     rv = NS_GetComponentManager(getter_AddRefs(cm));
     if (NS_FAILED(rv))
         return nullptr;
 
     JSAutoCompartment ac(cx, entry->obj);
-
-    nsCOMPtr<nsIXPConnectJSObjectHolder> cm_holder;
-    rv = xpc->WrapNative(cx, entry->obj, cm,
-                         NS_GET_IID(nsIComponentManager),
-                         getter_AddRefs(cm_holder));
-
-    if (NS_FAILED(rv)) {
-        return nullptr;
-    }
-
-    JSObject* cm_jsobj = cm_holder->GetJSObject();
-    if (!cm_jsobj) {
-        return nullptr;
-    }
-
-    nsCOMPtr<nsIXPConnectJSObjectHolder> file_holder;
     RootedObject entryObj(cx, entry->obj);
-    rv = xpc->WrapNative(cx, entryObj, file,
-                         NS_GET_IID(nsIFile),
-                         getter_AddRefs(file_holder));
-
-    if (NS_FAILED(rv)) {
-        return nullptr;
-    }
-
-    JSObject* file_jsobj = file_holder->GetJSObject();
-    if (!file_jsobj) {
-        return nullptr;
-    }
 
     RootedValue NSGetFactory_val(cx);
     if (!JS_GetProperty(cx, entryObj, "NSGetFactory", &NSGetFactory_val) ||
         NSGetFactory_val.isUndefined()) {
         return nullptr;
     }
 
     if (JS_TypeOfValue(cx, NSGetFactory_val) != JSTYPE_FUNCTION) {
@@ -609,27 +582,29 @@ mozJSComponentLoader::PrepareObjectForLo
     nsCOMPtr<nsIFile> testFile;
     if (NS_SUCCEEDED(rv)) {
         fileURL->GetFile(getter_AddRefs(testFile));
     }
 
     if (testFile) {
         *aRealFile = true;
 
-        nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder;
-        rv = xpc->WrapNative(aCx, obj, aComponentFile,
-                             NS_GET_IID(nsIFile),
-                             getter_AddRefs(locationHolder));
-        NS_ENSURE_SUCCESS(rv, nullptr);
+        if (XRE_GetProcessType() == GeckoProcessType_Default) {
+            nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder;
+            rv = xpc->WrapNative(aCx, obj, aComponentFile,
+                                 NS_GET_IID(nsIFile),
+                                 getter_AddRefs(locationHolder));
+            NS_ENSURE_SUCCESS(rv, nullptr);
 
-        RootedObject locationObj(aCx, locationHolder->GetJSObject());
-        NS_ENSURE_TRUE(locationObj, nullptr);
+            RootedObject locationObj(aCx, locationHolder->GetJSObject());
+            NS_ENSURE_TRUE(locationObj, nullptr);
 
-        if (!JS_DefineProperty(aCx, obj, "__LOCATION__", locationObj, 0))
-            return nullptr;
+            if (!JS_DefineProperty(aCx, obj, "__LOCATION__", locationObj, 0))
+                return nullptr;
+        }
     }
 
     nsAutoCString nativePath;
     rv = aURI->GetSpec(nativePath);
     NS_ENSURE_SUCCESS(rv, nullptr);
 
     // Expose the URI from which the script was imported through a special
     // variable that we insert into the JSM.
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -592,16 +592,23 @@ AddonWindowOrNull(JSObject *aObj)
     MOZ_RELEASE_ASSERT(js::IsCrossCompartmentWrapper(proto) ||
                        xpc::IsSandboxPrototypeProxy(proto));
     JSObject *mainGlobal = js::UncheckedUnwrap(proto, /* stopAtOuter = */ false);
     MOZ_RELEASE_ASSERT(JS_IsGlobalObject(mainGlobal));
 
     return WindowOrNull(mainGlobal);
 }
 
+nsGlobalWindow*
+CurrentWindowOrNull(JSContext *cx)
+{
+    JSObject *glob = JS::CurrentGlobalOrNull(cx);
+    return glob ? WindowOrNull(glob) : nullptr;
+}
+
 }
 
 static void
 CompartmentDestroyedCallback(JSFreeOp *fop, JSCompartment *compartment)
 {
     // NB - This callback may be called in JS_DestroyRuntime, which happens
     // after the XPCJSRuntime has been torn down.
 
--- a/js/xpconnect/src/XPCWrappedNativeInfo.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeInfo.cpp
@@ -6,16 +6,17 @@
 
 /* Manage the shared info about interfaces for use by wrappedNatives. */
 
 #include "xpcprivate.h"
 #include "jswrapper.h"
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
+#include "nsPrintfCString.h"
 
 using namespace JS;
 using namespace mozilla;
 
 /***************************************************************************/
 
 // XPCNativeMember
 
@@ -227,16 +228,37 @@ XPCNativeInterface::NewInstance(nsIInter
     // then make our object, but avoid init'ing *any* members until asked?
     // Find out how often we create these objects w/o really looking at
     // (or using) the members.
 
     bool canScript;
     if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
         return nullptr;
 
+    bool mainProcessScriptableOnly;
+    if (NS_FAILED(aInfo->IsMainProcessScriptableOnly(&mainProcessScriptableOnly)))
+        return nullptr;
+    if (mainProcessScriptableOnly && XRE_GetProcessType() != GeckoProcessType_Default) {
+        nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
+        if (console) {
+            char *intfNameChars;
+            aInfo->GetName(&intfNameChars);
+            nsPrintfCString errorMsg("Use of %s in content process is deprecated.", intfNameChars);
+
+            nsAutoString filename;
+            uint32_t lineno = 0;
+            nsJSUtils::GetCallingLocation(cx, filename, &lineno);
+            nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
+            error->Init(NS_ConvertUTF8toUTF16(errorMsg),
+                        filename, EmptyString(),
+                        lineno, 0, nsIScriptError::warningFlag, "chrome javascript");
+            console->LogMessage(error);
+        }
+    }
+
     if (NS_FAILED(aInfo->GetMethodCount(&methodCount)) ||
         NS_FAILED(aInfo->GetConstantCount(&constCount)))
         return nullptr;
 
     // If the interface does not have nsISupports in its inheritance chain
     // then we know we can't reflect its methods. However, some interfaces that
     // are used just to reflect constants are declared this way. We need to
     // go ahead and build the thing. But, we'll ignore whatever methods it may
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -464,16 +464,23 @@ WindowGlobalOrNull(JSObject *aObj);
 /**
  * If |aObj| is in an addon scope and that addon scope is associated with a
  * live DOM Window, returns the associated nsGlobalWindow. Otherwise, returns
  * null.
  */
 nsGlobalWindow*
 AddonWindowOrNull(JSObject *aObj);
 
+/**
+ * If |cx| is in a compartment whose global is a window, returns the associated
+ * nsGlobalWindow. Otherwise, returns null.
+ */
+nsGlobalWindow*
+CurrentWindowOrNull(JSContext *cx);
+
 // Error reporter used when there is no associated DOM window on to which to
 // report errors and warnings.
 //
 // Note - This is temporarily implemented in nsJSEnvironment.cpp.
 void
 SystemErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep);
 
 void
--- a/layout/base/DisplayItemClip.cpp
+++ b/layout/base/DisplayItemClip.cpp
@@ -322,17 +322,17 @@ DisplayItemClip::ApplyNonRoundedIntersec
 {
   if (!mHaveClipRect) {
     return aRect;
   }
 
   nsRect result = aRect.Intersect(mClipRect);
   for (uint32_t i = 0, iEnd = mRoundedClipRects.Length();
        i < iEnd; ++i) {
-    result.Intersect(mRoundedClipRects[i].mRect);
+    result = result.Intersect(mRoundedClipRects[i].mRect);
   }
   return result;
 }
 
 void
 DisplayItemClip::RemoveRoundedCorners()
 {
   if (mRoundedClipRects.IsEmpty())
--- a/layout/base/nsCounterManager.cpp
+++ b/layout/base/nsCounterManager.cpp
@@ -2,22 +2,23 @@
 // vim:cindent:ai:sw=4:ts=4:et:
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* implementation of CSS counters (for numbering things) */
 
 #include "nsCounterManager.h"
+
+#include "mozilla/Likely.h"
+#include "mozilla/WritingModes.h"
 #include "nsBulletFrame.h" // legacy location for list style type to text code
 #include "nsContentUtils.h"
+#include "nsIContent.h"
 #include "nsTArray.h"
-#include "mozilla/Likely.h"
-#include "nsIContent.h"
-#include "WritingModes.h"
 
 using namespace mozilla;
 
 bool
 nsCounterUseNode::InitTextFrame(nsGenConList* aList,
         nsIFrame* aPseudoFrame, nsIFrame* aTextFrame)
 {
   nsCounterNode::InitTextFrame(aList, aPseudoFrame, aTextFrame);
@@ -49,17 +50,17 @@ nsCounterUseNode::GetCounterStyle()
     if (!mCounterStyle) {
         const nsCSSValue& style = mCounterFunction->Item(mAllCounters ? 2 : 1);
         CounterStyleManager* manager = mPresContext->CounterStyleManager();
         if (style.GetUnit() == eCSSUnit_Ident) {
             nsString ident;
             style.GetStringValue(ident);
             mCounterStyle = manager->BuildCounterStyle(ident);
         } else if (style.GetUnit() == eCSSUnit_Symbols) {
-            mCounterStyle = manager->BuildCounterStyle(style.GetArrayValue());
+            mCounterStyle = new AnonymousCounterStyle(style.GetArrayValue());
         } else {
             NS_NOTREACHED("Unknown counter style");
             mCounterStyle = CounterStyleManager::GetDecimalStyle();
         }
     }
     return mCounterStyle;
 }
 
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -886,16 +886,17 @@ nsDisplayScrollLayer::ComputeFrameMetric
       nsIWidget* widget = rootFrame->GetNearestWidget();
 #else
       nsView* view = rootFrame->GetView();
       nsIWidget* widget = view ? view->GetWidget() : nullptr;
 #endif
       if (widget) {
         nsIntRect widgetBounds;
         widget->GetBounds(widgetBounds);
+        widgetBounds.MoveTo(0,0);
         metrics.mCompositionBounds = ParentLayerRect(ViewAs<ParentLayerPixel>(widgetBounds));
 #ifdef MOZ_WIDGET_ANDROID
         if (frameBounds.height < metrics.mCompositionBounds.height) {
           metrics.mCompositionBounds.height = frameBounds.height;
         }
 #endif
       } else {
         LayoutDeviceIntSize contentSize;
@@ -1542,41 +1543,41 @@ nsDisplayList::ComputeVisibilityForSubli
     AppendToBottom(item);
   }
 
   mIsOpaque = !aVisibleRegion->Intersects(aListVisibleBounds);
   return anyVisible;
 }
 
 static bool
-StartPendingAnimationsOnSubDocuments(nsIDocument* aDocument, void* aReadyTime)
+TriggerPendingAnimationsOnSubDocuments(nsIDocument* aDocument, void* aReadyTime)
 {
   PendingPlayerTracker* tracker = aDocument->GetPendingPlayerTracker();
   if (tracker) {
     nsIPresShell* shell = aDocument->GetShell();
     // If paint-suppression is in effect then we haven't finished painting
     // this document yet so we shouldn't start animations
     if (!shell || !shell->IsPaintingSuppressed()) {
       const TimeStamp& readyTime = *static_cast<TimeStamp*>(aReadyTime);
-      tracker->StartPendingPlayersOnNextTick(readyTime);
+      tracker->TriggerPendingPlayersOnNextTick(readyTime);
     }
   }
-  aDocument->EnumerateSubDocuments(StartPendingAnimationsOnSubDocuments,
+  aDocument->EnumerateSubDocuments(TriggerPendingAnimationsOnSubDocuments,
                                    aReadyTime);
   return true;
 }
 
 static void