Merge latest green b2g-inbound changeset and mozilla-central
authorEd Morley <emorley@mozilla.com>
Thu, 12 Sep 2013 12:05:20 +0100
changeset 146775 a9d76ddf0ee2caeee5ccfb7fa4e2f40a11cb6d94
parent 146774 bf9034be6a6480e0e826158c68799c49f9b6fb65 (current diff)
parent 146769 b83f6d80af5fe8fef0a7718eae9741153d4dbfe0 (diff)
child 146780 ca8fd217b83639254d906e0184d68c6efcd79a6a
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone26.0a1
Merge latest green b2g-inbound changeset and mozilla-central
dom/interfaces/events/nsIDOMDeviceProximityEvent.idl
dom/interfaces/events/nsIDOMGamepadAxisMoveEvent.idl
dom/interfaces/events/nsIDOMGamepadButtonEvent.idl
dom/interfaces/events/nsIDOMGamepadEvent.idl
security/manager/ssl/tests/unit/test_ocsp_stapling/Makefile.in
security/manager/ssl/tests/unit/test_ocsp_stapling/OCSPStaplingServer.cpp
security/manager/ssl/tests/unit/test_ocsp_stapling/cert8.db
security/manager/ssl/tests/unit/test_ocsp_stapling/gen_ocsp_certs.sh
security/manager/ssl/tests/unit/test_ocsp_stapling/key3.db
security/manager/ssl/tests/unit/test_ocsp_stapling/moz.build
security/manager/ssl/tests/unit/test_ocsp_stapling/ocsp-ca.der
security/manager/ssl/tests/unit/test_ocsp_stapling/ocsp-other-ca.der
security/manager/ssl/tests/unit/test_ocsp_stapling/secmod.db
toolkit/components/aboutmemory/tests/test_aboutcompartments.xul
--- a/accessible/src/atk/AccessibleWrap.cpp
+++ b/accessible/src/atk/AccessibleWrap.cpp
@@ -22,16 +22,17 @@
 #include "nsStateMap.h"
 #include "Relation.h"
 #include "RootAccessible.h"
 #include "States.h"
 
 #include "mozilla/Util.h"
 #include "nsXPCOMStrings.h"
 #include "nsComponentManagerUtils.h"
+#include "nsIPersistentProperties2.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 AccessibleWrap::EAvailableAtkSignals AccessibleWrap::gAvailableAtkSignals =
   eUnknown;
 
 //defined in ApplicationAccessibleWrap.cpp
--- a/accessible/src/atk/nsMaiInterfaceImage.cpp
+++ b/accessible/src/atk/nsMaiInterfaceImage.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
 #include "AccessibleWrap.h"
 #include "ImageAccessible.h"
 #include "mozilla/Likely.h"
 #include "nsMai.h"
+#include "nsIAccessibleTypes.h"
 #include "nsIURI.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 extern "C" {
 const gchar* getDescriptionCB(AtkObject* aAtkObj);
 
--- a/accessible/src/atk/nsMaiInterfaceText.cpp
+++ b/accessible/src/atk/nsMaiInterfaceText.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
 #include "Accessible-inl.h"
 #include "HyperTextAccessible.h"
 #include "nsMai.h"
 
+#include "nsIAccessibleTypes.h"
 #include "nsIPersistentProperties2.h"
 
 #include "mozilla/Likely.h"
 
 using namespace mozilla::a11y;
 
 AtkAttributeSet* ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes);
 
--- a/accessible/src/base/ARIAMap.cpp
+++ b/accessible/src/base/ARIAMap.cpp
@@ -2,17 +2,16 @@
 /* vim:expandtab:shiftwidth=2:tabstop=2:
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ARIAMap.h"
 
-#include "Accessible.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsAttrName.h"
 #include "nsWhitespaceTokenizer.h"
 
--- a/accessible/src/base/AccEvent.cpp
+++ b/accessible/src/base/AccEvent.cpp
@@ -1,29 +1,22 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AccEvent.h"
 
-#include "ApplicationAccessibleWrap.h"
-#include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "DocAccessible.h"
-#include "nsIAccessibleText.h"
 #include "xpcAccEvents.h"
 #include "States.h"
 
 #include "nsEventStateManager.h"
-#include "nsIServiceManager.h"
-#ifdef MOZ_XUL
-#include "nsIDOMXULMultSelectCntrlEl.h"
-#endif
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccEvent
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/accessible/src/base/AccGroupInfo.cpp
+++ b/accessible/src/base/AccGroupInfo.cpp
@@ -1,13 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AccGroupInfo.h"
+#include "nsAccUtils.h"
 
 #include "Role.h"
 #include "States.h"
 
 using namespace mozilla::a11y;
 
 AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) :
   mPosInSet(0), mSetSize(0), mParent(nullptr)
--- a/accessible/src/base/AccGroupInfo.h
+++ b/accessible/src/base/AccGroupInfo.h
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef AccGroupInfo_h_
 #define AccGroupInfo_h_
 
 #include "Accessible-inl.h"
-#include "nsAccUtils.h"
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * Calculate and store group information.
  */
 class AccGroupInfo
--- a/accessible/src/base/AccIterator.cpp
+++ b/accessible/src/base/AccIterator.cpp
@@ -1,23 +1,20 @@
 /* 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 "AccIterator.h"
 
-#include "nsAccessibilityService.h"
 #include "AccGroupInfo.h"
-#include "Accessible-inl.h"
 #ifdef MOZ_XUL
 #include "XULTreeAccessible.h"
 #endif
 
 #include "mozilla/dom/Element.h"
-#include "nsBindingManager.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccIterator
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/accessible/src/base/AccIterator.h
+++ b/accessible/src/base/AccIterator.h
@@ -4,17 +4,18 @@
  * 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_AccIterator_h__
 #define mozilla_a11y_AccIterator_h__
 
 #include "DocAccessible.h"
 #include "Filters.h"
-#include "nsAccessibilityService.h"
+
+class nsITreeView;
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * AccIterable is a basic interface for iterators over accessibles.
  */
 class AccIterable
--- a/accessible/src/base/AccTypes.h
+++ b/accessible/src/base/AccTypes.h
@@ -24,17 +24,16 @@ enum AccType {
   eHTMLCanvasType,
   eHTMLCaptionType,
   eHTMLCheckboxType,
   eHTMLComboboxType,
   eHTMLFileInputType,
   eHTMLGroupboxType,
   eHTMLHRType,
   eHTMLImageMapType,
-  eHTMLLabelType,
   eHTMLLiType,
   eHTMLSelectListType,
   eHTMLMediaType,
   eHTMLRadioButtonType,
   eHTMLRangeType,
   eHTMLTableType,
   eHTMLTableCellType,
   eHTMLTableRowType,
--- a/accessible/src/base/DocManager.cpp
+++ b/accessible/src/base/DocManager.cpp
@@ -1,39 +1,37 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DocManager.h"
 
-#include "Accessible-inl.h"
 #include "ApplicationAccessible.h"
 #include "ARIAMap.h"
 #include "DocAccessible-inl.h"
 #include "nsAccessibilityService.h"
-#include "nsAccUtils.h"
 #include "RootAccessibleWrap.h"
-#include "States.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 #include "nsCURILoader.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsDOMEvent.h"
 #include "nsIChannel.h"
-#include "nsIContentViewer.h"
 #include "nsIDOMDocument.h"
 #include "nsEventListenerManager.h"
 #include "nsIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIWebNavigation.h"
 #include "nsServiceManagerUtils.h"
+#include "nsIWebProgress.h"
+#include "nsCoreUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using namespace mozilla::dom;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/base/DocManager.h
+++ b/accessible/src/base/DocManager.h
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11_DocManager_h_
 #define mozilla_a11_DocManager_h_
 
 #include "nsIDocument.h"
 #include "nsIDOMEventListener.h"
 #include "nsRefPtrHashtable.h"
-#include "nsIWebProgress.h"
 #include "nsIWebProgressListener.h"
 #include "nsWeakReference.h"
 #include "nsIPresShell.h"
 
 namespace mozilla {
 namespace a11y {
 
 class Accessible;
--- a/accessible/src/base/EventQueue.cpp
+++ b/accessible/src/base/EventQueue.cpp
@@ -1,18 +1,22 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "EventQueue.h"
 
 #include "Accessible-inl.h"
-#include "DocAccessible-inl.h"
 #include "nsEventShell.h"
+#include "DocAccessible.h"
+#include "nsAccessibilityService.h"
+#ifdef A11Y_LOG
+#include "Logging.h"
+#endif
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 // Defines the number of selection add/remove events in the queue when they
 // aren't packed into single selection within event.
 const unsigned int kSelChangeCountToPack = 5;
 
--- a/accessible/src/base/EventQueue.h
+++ b/accessible/src/base/EventQueue.h
@@ -3,18 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_EventQueue_h_
 #define mozilla_a11y_EventQueue_h_
 
 #include "AccEvent.h"
 
-class nsIContent;
-
 namespace mozilla {
 namespace a11y {
 
 class DocAccessible;
 
 /**
  * Used to organize and coalesce pending events.
  */
--- a/accessible/src/base/FocusManager.cpp
+++ b/accessible/src/base/FocusManager.cpp
@@ -5,20 +5,20 @@
 #include "FocusManager.h"
 
 #include "Accessible-inl.h"
 #include "DocAccessible-inl.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsEventShell.h"
 #include "Role.h"
-#include "RootAccessible.h"
 
 #include "nsEventStateManager.h"
 #include "nsFocusManager.h"
+#include "mozilla/dom/Element.h"
 
 namespace dom = mozilla::dom;
 using namespace mozilla::a11y;
 
 FocusManager::FocusManager()
 {
 }
 
--- a/accessible/src/base/FocusManager.h
+++ b/accessible/src/base/FocusManager.h
@@ -1,17 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_FocusManager_h_
 #define mozilla_a11y_FocusManager_h_
 
 #include "nsAutoPtr.h"
-#include "mozilla/dom/Element.h"
+
+class nsINode;
+class nsIDocument;
+class nsISupports;
 
 namespace mozilla {
 namespace a11y {
 
 class AccEvent;
 class Accessible;
 class DocAccessible;
 
--- a/accessible/src/base/Logging.cpp
+++ b/accessible/src/base/Logging.cpp
@@ -17,16 +17,17 @@
 #include "nsIChannel.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsISelectionPrivate.h"
 #include "nsTraceRefcntImpl.h"
 #include "nsIWebProgress.h"
 #include "prenv.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIURI.h"
+#include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Logging helpers
 
 static uint32_t sModules = 0;
--- a/accessible/src/base/Logging.h
+++ b/accessible/src/base/Logging.h
@@ -3,22 +3,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/. */
 
 #ifndef mozilla_a11y_logs_h__
 #define mozilla_a11y_logs_h__
 
 #include "nscore.h"
-#include "nsAString.h"
+#include "nsStringFwd.h"
 
 class nsIDocument;
 class nsINode;
 class nsIRequest;
 class nsISelection;
+class nsISupports;
 class nsIWebProgress;
 
 namespace mozilla {
 namespace a11y {
 
 class AccEvent;
 class Accessible;
 class DocAccessible;
--- a/accessible/src/base/NotificationController.cpp
+++ b/accessible/src/base/NotificationController.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "NotificationController.h"
 
-#include "Accessible-inl.h"
 #include "DocAccessible-inl.h"
 #include "TextLeafAccessible.h"
 #include "TextUpdater.h"
 
 #include "mozilla/dom/Element.h"
 #include "mozilla/Telemetry.h"
 
 using namespace mozilla;
--- a/accessible/src/base/NotificationController.h
+++ b/accessible/src/base/NotificationController.h
@@ -10,22 +10,19 @@
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsRefreshDriver.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
-class nsIContent;
-
 namespace mozilla {
 namespace a11y {
 
-class Accessible;
 class DocAccessible;
 
 /**
  * Notification interface.
  */
 class Notification
 {
 public:
--- a/accessible/src/base/RoleAsserts.cpp
+++ b/accessible/src/base/RoleAsserts.cpp
@@ -2,18 +2,16 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIAccessibleRole.h"
 #include "Role.h"
 
-#include "mozilla/Assertions.h"
-
 using namespace mozilla::a11y;
 
 #define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, nameRule) \
   static_assert(static_cast<uint32_t>(roles::geckoRole) \
                 == static_cast<uint32_t>(nsIAccessibleRole::ROLE_ ## geckoRole), \
                 "internal and xpcom roles differ!");
 #include "RoleMap.h"
 #undef ROLE
--- a/accessible/src/base/SelectionManager.cpp
+++ b/accessible/src/base/SelectionManager.cpp
@@ -5,27 +5,25 @@
 
 #include "mozilla/a11y/SelectionManager.h"
 
 #include "DocAccessible-inl.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsIAccessibleEvent.h"
-#include "RootAccessible.h"
 
 #include "nsCaret.h"
+#include "nsIAccessibleTypes.h"
 #include "nsIDOMDocument.h"
-#include "nsIDOMHTMLAnchorElement.h"
-#include "nsIDOMHTMLTextAreaElement.h"
 #include "nsIFrame.h"
 #include "nsIPresShell.h"
 #include "nsISelectionPrivate.h"
-#include "nsServiceManagerUtils.h"
 #include "mozilla/Selection.h"
+#include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 void
 SelectionManager::Shutdown()
 {
   ClearControlSelectionListener();
--- a/accessible/src/base/TextAttrs.cpp
+++ b/accessible/src/base/TextAttrs.cpp
@@ -1,25 +1,24 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TextAttrs.h"
 
 #include "Accessible-inl.h"
-#include "HyperTextAccessibleWrap.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "StyleInfo.h"
 
 #include "gfxFont.h"
-#include "gfxUserFontSet.h"
 #include "nsFontMetrics.h"
 #include "nsLayoutUtils.h"
+#include "HyperTextAccessible.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // TextAttrsMgr
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/accessible/src/base/TreeWalker.h
+++ b/accessible/src/base/TreeWalker.h
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_TreeWalker_h_
 #define mozilla_a11y_TreeWalker_h_
 
-#include "nsAutoPtr.h"
+#include <stdint.h>
 
 class nsIContent;
 
 namespace mozilla {
 namespace a11y {
 
 class Accessible;
 class DocAccessible;
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -10,23 +10,20 @@
 #include "nsAccessibilityService.h"
 #include "nsCoreUtils.h"
 #include "DocAccessible.h"
 #include "HyperTextAccessible.h"
 #include "nsIAccessibleTypes.h"
 #include "Role.h"
 #include "States.h"
 #include "TextLeafAccessible.h"
-#include "nsIMutableArray.h"
 
 #include "nsIDOMXULContainerElement.h"
-#include "nsIDOMXULSelectCntrlEl.h"
-#include "nsIDOMXULSelectCntrlItemEl.h"
-#include "nsWhitespaceTokenizer.h"
-#include "nsComponentManagerUtils.h"
+#include "nsIPersistentProperties2.h"
+#include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 void
 nsAccUtils::GetAccAttr(nsIPersistentProperties *aAttributes,
                        nsIAtom *aAttrName, nsAString& aAttrValue)
 {
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -2,33 +2,31 @@
 /* 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 nsAccUtils_h_
 #define nsAccUtils_h_
 
 #include "mozilla/a11y/Accessible.h"
-#include "nsIAccessibleText.h"
 
 #include "nsAccessibilityService.h"
 #include "nsCoreUtils.h"
 
-#include "mozilla/dom/Element.h"
 #include "nsIDocShell.h"
-#include "nsIPersistentProperties2.h"
-#include "nsIPresShell.h"
 #include "nsPoint.h"
 
-struct nsRoleMapEntry;
+namespace mozilla {
 
-namespace mozilla {
+namespace dom {
+class Element;
+}
+
 namespace a11y {
 
-class Accessible;
 class HyperTextAccessible;
 class DocAccessible;
 
 class nsAccUtils
 {
 public:
   /**
    * Returns value of attribute from the given attributes container.
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -1,29 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAccessNode.h"
 
-#include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "RootAccessible.h"
 
 #include "nsIDocShell.h"
-#include "nsIDOMWindow.h"
-#include "nsIFrame.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "nsIPresShell.h"
-#include "nsIServiceManager.h"
-#include "nsFocusManager.h"
-#include "nsPresContext.h"
-#include "mozilla/Services.h"
 
 using namespace mozilla::a11y;
 
 /* For documentation of the accessibility architecture,
  * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
  */
 
 /*
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -5,24 +5,20 @@
 
 /* For documentation of the accessibility architecture, 
  * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
  */
 
 #ifndef _nsAccessNode_H_
 #define _nsAccessNode_H_
 
-#include "nsIAccessibleTypes.h"
 #include "nsINode.h"
 
 class nsIContent;
-class nsIDocShellTreeItem;
 class nsIFrame;
-class nsIPresShell;
-class nsPresContext;
 
 namespace mozilla {
 namespace a11y {
 
 class DocAccessible;
 class RootAccessible;
 
 class nsAccessNode : public nsISupports
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1,93 +1,95 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAccessibilityService.h"
 
 // NOTE: alphabetically ordered
-#include "Accessible-inl.h"
 #include "ApplicationAccessibleWrap.h"
 #include "ARIAGridAccessibleWrap.h"
 #include "ARIAMap.h"
 #include "DocAccessible-inl.h"
 #include "FocusManager.h"
 #include "HTMLCanvasAccessible.h"
 #include "HTMLElementAccessibles.h"
 #include "HTMLImageMapAccessible.h"
 #include "HTMLLinkAccessible.h"
 #include "HTMLListAccessible.h"
 #include "HTMLSelectAccessible.h"
 #include "HTMLTableAccessibleWrap.h"
 #include "HyperTextAccessibleWrap.h"
+#include "RootAccessible.h"
 #include "nsAccessiblePivot.h"
 #include "nsAccUtils.h"
+#include "nsAttrName.h"
 #include "nsEventShell.h"
+#include "nsIURI.h"
 #include "OuterDocAccessible.h"
 #include "Platform.h"
 #include "Role.h"
+#ifdef MOZ_ACCESSIBILITY_ATK
 #include "RootAccessibleWrap.h"
+#endif
 #include "States.h"
 #include "Statistics.h"
 #include "TextLeafAccessibleWrap.h"
 
 #ifdef MOZ_ACCESSIBILITY_ATK
 #include "AtkSocketAccessible.h"
 #endif
 
 #ifdef XP_WIN
 #include "mozilla/a11y/Compatibility.h"
 #include "HTMLWin32ObjectAccessible.h"
+#include "mozilla/StaticPtr.h"
 #endif
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
-#include "nsIDOMDocument.h"
-#include "nsIDOMHTMLObjectElement.h"
-#include "nsIDOMXULElement.h"
 #include "nsImageFrame.h"
 #include "nsIObserverService.h"
 #include "nsLayoutUtils.h"
-#include "nsNPAPIPluginInstance.h"
 #include "nsObjectFrame.h"
 #include "nsSVGPathGeometryFrame.h"
 #include "nsTreeBodyFrame.h"
 #include "nsTreeColumns.h"
 #include "nsTreeUtils.h"
-#include "nsBindingManager.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsXBLBinding.h"
-#include "mozilla/dom/Element.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
-#include "mozilla/StaticPtr.h"
 #include "mozilla/Util.h"
 #include "nsDeckFrame.h"
 
 #ifdef MOZ_XUL
 #include "XULAlertAccessible.h"
 #include "XULColorPickerAccessible.h"
 #include "XULComboboxAccessible.h"
 #include "XULElementAccessibles.h"
 #include "XULFormControlAccessible.h"
 #include "XULListboxAccessibleWrap.h"
 #include "XULMenuAccessibleWrap.h"
 #include "XULSliderAccessible.h"
 #include "XULTabAccessible.h"
 #include "XULTreeGridAccessibleWrap.h"
 #endif
 
+#if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
+#include "nsNPAPIPluginInstance.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Statics
 ////////////////////////////////////////////////////////////////////////////////
 
 /**
@@ -1428,16 +1430,22 @@ nsAccessibilityService::CreateHTMLAccess
       tag == nsGkAtoms::h5 ||
       tag == nsGkAtoms::h6 ||
       tag == nsGkAtoms::q) {
     nsRefPtr<Accessible> accessible =
       new HyperTextAccessibleWrap(aContent, document);
     return accessible.forget();
   }
 
+  if (tag == nsGkAtoms::label) {
+    nsRefPtr<Accessible> accessible =
+      new HTMLLabelAccessible(aContent, document);
+    return accessible.forget();
+  }
+
   if (tag == nsGkAtoms::output) {
     nsRefPtr<Accessible> accessible =
       new HTMLOutputAccessible(aContent, document);
     return accessible.forget();
   }
 
   if (tag == nsGkAtoms::progress) {
     nsRefPtr<Accessible> accessible =
@@ -1487,19 +1495,16 @@ nsAccessibilityService::CreateAccessible
       newAcc = new HTMLGroupboxAccessible(aContent, document);
       break;
     case eHTMLHRType:
       newAcc = new HTMLHRAccessible(aContent, document);
       break;
     case eHTMLImageMapType:
       newAcc = new HTMLImageMapAccessible(aContent, document);
       break;
-    case eHTMLLabelType:
-      newAcc = new HTMLLabelAccessible(aContent, document);
-      break;
     case eHTMLLiType:
       if (aContext->IsList() &&
           aContext->GetContent() == aContent->GetParent()) {
         newAcc = new HTMLLIAccessible(aContent, document);
       }
       break;
     case eHTMLSelectListType:
       newAcc = new HTMLSelectListAccessible(aContent, document);
--- a/accessible/src/base/nsAccessiblePivot.cpp
+++ b/accessible/src/base/nsAccessiblePivot.cpp
@@ -1,25 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAccessiblePivot.h"
 
-#include "DocAccessible.h"
 #include "HyperTextAccessible.h"
 #include "nsAccUtils.h"
 #include "States.h"
 
-#include "nsArrayUtils.h"
-#include "nsComponentManagerUtils.h"
-#include "nsISupportsPrimitives.h"
-
 using namespace mozilla::a11y;
 
 
 /**
  * An object that stores a given traversal rule during 
  */
 class RuleCache
 {
--- a/accessible/src/base/nsAccessiblePivot.h
+++ b/accessible/src/base/nsAccessiblePivot.h
@@ -10,17 +10,16 @@
 #include "nsIAccessiblePivot.h"
 
 #include "Accessible-inl.h"
 #include "nsAutoPtr.h"
 #include "nsTObserverArray.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 
-class nsIAccessibleTraversalRule;
 class RuleCache;
 
 /**
  * Class represents an accessible pivot.
  */
 class nsAccessiblePivot MOZ_FINAL : public nsIAccessiblePivot
 {
 public:
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -2,46 +2,39 @@
 /* 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 "nsCoreUtils.h"
 
 #include "nsIAccessibleTypes.h"
 
-#include "nsAccessNode.h"
-
 #include "nsIBaseWindow.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsRange.h"
-#include "nsIDOMWindow.h"
+#include "nsIBoxObject.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDocShell.h"
-#include "nsIContentViewer.h"
 #include "nsEventListenerManager.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIScrollableFrame.h"
 #include "nsEventStateManager.h"
 #include "nsISelectionPrivate.h"
 #include "nsISelectionController.h"
-#include "nsPIDOMWindow.h"
 #include "nsGUIEvent.h"
 #include "nsView.h"
-#include "nsLayoutUtils.h"
 #include "nsGkAtoms.h"
 #include "nsDOMTouchEvent.h"
 
 #include "nsComponentManagerUtils.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "mozilla/dom/Element.h"
 
 #include "nsITreeBoxObject.h"
 #include "nsITreeColumns.h"
 
 using namespace mozilla;
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsCoreUtils
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -2,24 +2,24 @@
 /* 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 nsCoreUtils_h_
 #define nsCoreUtils_h_
 
 #include "nsIContent.h"
-#include "nsIBoxObject.h"
 #include "nsIPresShell.h"
 
 #include "nsIDOMDOMStringList.h"
 #include "nsPoint.h"
 #include "nsTArray.h"
 
 class nsRange;
+class nsIBoxObject;
 class nsIFrame;
 class nsIDocShell;
 class nsITreeColumn;
 class nsITreeBoxObject;
 class nsIWidget;
 
 /**
  * Core utils.
--- a/accessible/src/base/nsTextEquivUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -4,24 +4,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsTextEquivUtils.h"
 
 #include "Accessible-inl.h"
 #include "AccIterator.h"
-#include "nsAccessibilityService.h"
-#include "nsAccUtils.h"
-#include "nsStyleStructInlines.h"
-
+#include "nsCoreUtils.h"
 #include "nsIDOMXULLabeledControlEl.h"
 
-#include "nsArrayUtils.h"
-
 using namespace mozilla::a11y;
 
 /**
  * The accessible for which we are computing a text equivalent. It is useful
  * for bailing out during recursive text computation, or for special cases
  * like step f. of the ARIA implementation guide.
  */
 static Accessible* sInitiatorAcc = nullptr;
--- a/accessible/src/base/nsTextEquivUtils.h
+++ b/accessible/src/base/nsTextEquivUtils.h
@@ -4,17 +4,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _nsTextEquivUtils_H_
 #define _nsTextEquivUtils_H_
 
 #include "Accessible.h"
-#include "nsIStringBundle.h"
 #include "Role.h"
 
 class nsIContent;
 
 /**
  * Text equivalent computation rules (see nsTextEquivUtils::gRoleToNameRulesMap)
  */
 enum ETextEquivRule
--- a/accessible/src/generic/ARIAGridAccessible.cpp
+++ b/accessible/src/generic/ARIAGridAccessible.cpp
@@ -7,16 +7,17 @@
 
 #include "Accessible-inl.h"
 #include "AccIterator.h"
 #include "nsAccUtils.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsIMutableArray.h"
+#include "nsIPersistentProperties2.h"
 #include "nsComponentManagerUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // ARIAGridAccessible
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/generic/DocAccessible-inl.h
+++ b/accessible/src/generic/DocAccessible-inl.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_a11y_DocAccessible_inl_h_
 #define mozilla_a11y_DocAccessible_inl_h_
 
 #include "DocAccessible.h"
 #include "nsAccessibilityService.h"
 #include "NotificationController.h"
 #include "States.h"
+#include "nsIScrollableFrame.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 namespace mozilla {
 namespace a11y {
 
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -27,16 +27,17 @@
 #include "nsIDOMMutationEvent.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMXULPopupElement.h"
 #include "nsIEditingSession.h"
 #include "nsEventStateManager.h"
 #include "nsIFrame.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsINameSpaceManager.h"
+#include "nsIPersistentProperties2.h"
 #include "nsIPresShell.h"
 #include "nsIServiceManager.h"
 #include "nsViewManager.h"
 #include "nsIScrollableFrame.h"
 #include "nsUnicharUtils.h"
 #include "nsIURI.h"
 #include "nsIWebNavigation.h"
 #include "nsFocusManager.h"
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -20,16 +20,17 @@
 #include "nsFocusManager.h"
 #include "nsIDOMRange.h"
 #include "nsIEditingSession.h"
 #include "nsIEditor.h"
 #include "nsIFrame.h"
 #include "nsFrameSelection.h"
 #include "nsILineIterator.h"
 #include "nsIInterfaceRequestorUtils.h"
+#include "nsIPersistentProperties2.h"
 #include "nsIPlaintextEditor.h"
 #include "nsIScrollableFrame.h"
 #include "nsIServiceManager.h"
 #include "nsTextFragment.h"
 #include "mozilla/Selection.h"
 #include "gfxSkipChars.h"
 #include <algorithm>
 
--- a/accessible/src/generic/ImageAccessible.cpp
+++ b/accessible/src/generic/ImageAccessible.cpp
@@ -13,16 +13,17 @@
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDocument.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIPresShell.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMHTMLImageElement.h"
+#include "nsIPersistentProperties2.h"
 #include "nsPIDOMWindow.h"
 #include "nsIURI.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // ImageAccessible
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/html/HTMLElementAccessibles.cpp
+++ b/accessible/src/html/HTMLElementAccessibles.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "HTMLElementAccessibles.h"
 
 #include "DocAccessible.h"
 #include "nsAccUtils.h"
 #include "nsIAccessibleRelation.h"
+#include "nsIPersistentProperties2.h"
 #include "nsTextEquivUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/html/HTMLFormControlAccessible.cpp
+++ b/accessible/src/html/HTMLFormControlAccessible.cpp
@@ -18,16 +18,17 @@
 #include "nsCxPusher.h"
 #include "mozilla/dom/HTMLInputElement.h"
 #include "nsIAccessibleRelation.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsIEditor.h"
 #include "nsIFormControl.h"
 #include "nsINameSpaceManager.h"
+#include "nsIPersistentProperties2.h"
 #include "nsISelectionController.h"
 #include "jsapi.h"
 #include "nsIServiceManager.h"
 #include "nsITextControlFrame.h"
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
--- a/accessible/src/html/HTMLTableAccessible.cpp
+++ b/accessible/src/html/HTMLTableAccessible.cpp
@@ -23,16 +23,17 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMRange.h"
 #include "nsISelectionPrivate.h"
 #include "nsINameSpaceManager.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMHTMLCollection.h"
 #include "nsIDocument.h"
 #include "nsIMutableArray.h"
+#include "nsIPersistentProperties2.h"
 #include "nsIPresShell.h"
 #include "nsITableCellLayout.h"
 #include "nsFrameSelection.h"
 #include "nsError.h"
 #include "nsArrayUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsTableCellFrame.h"
 #include "nsTableOuterFrame.h"
--- a/accessible/src/mac/mozAccessible.mm
+++ b/accessible/src/mac/mozAccessible.mm
@@ -8,16 +8,17 @@
 #import "MacUtils.h"
 #import "mozView.h"
 
 #include "Accessible-inl.h"
 #include "nsAccUtils.h"
 #include "nsIAccessibleRelation.h"
 #include "nsIAccessibleText.h"
 #include "nsIAccessibleEditableText.h"
+#include "nsIPersistentProperties2.h"
 #include "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 
 #include "mozilla/Services.h"
 #include "nsRect.h"
 #include "nsCocoaUtils.h"
 #include "nsCoord.h"
--- a/accessible/src/mac/mozTextAccessible.mm
+++ b/accessible/src/mac/mozTextAccessible.mm
@@ -1,16 +1,17 @@
 /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Accessible-inl.h"
 #include "AccessibleWrap.h"
 #include "TextLeafAccessible.h"
+#include "nsIAccessibleTypes.h"
 
 #include "nsCocoaUtils.h"
 #include "nsObjCExceptions.h"
 
 #import "mozTextAccessible.h"
 
 using namespace mozilla::a11y;
 
--- a/accessible/src/windows/ia2/ia2AccessibleText.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleText.cpp
@@ -8,16 +8,17 @@
 #include "ia2AccessibleText.h"
 
 #include "Accessible2.h"
 #include "AccessibleText_i.c"
 
 #include "HyperTextAccessibleWrap.h"
 
 #include "nsIPersistentProperties2.h"
+#include "nsIAccessibleTypes.h"
 
 using namespace mozilla::a11y;
 
 // IAccessibleText
 
 STDMETHODIMP
 ia2AccessibleText::addSelection(long aStartOffset, long aEndOffset)
 {
--- a/accessible/src/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/src/windows/msaa/AccessibleWrap.cpp
@@ -37,16 +37,18 @@
 #include "nsEventMap.h"
 #include "nsArrayUtils.h"
 #include "mozilla/Preferences.h"
 
 #include "Accessible2_i.c"
 #include "AccessibleRole.h"
 #include "AccessibleStates.h"
 #include "oleacc.h"
+#include "nsIAccessibleTypes.h"
+#include "nsIPersistentProperties2.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 const uint32_t USE_ROLE_STRING = 0;
 
 /* For documentation of the accessibility architecture,
  * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
--- a/accessible/src/windows/sdn/sdnAccessible.cpp
+++ b/accessible/src/windows/sdn/sdnAccessible.cpp
@@ -6,16 +6,17 @@
 
 #include "sdnAccessible-inl.h"
 #include "ISimpleDOMNode_i.c"
 
 #include "DocAccessibleWrap.h"
 
 #include "nsAttrName.h"
 #include "nsCoreUtils.h"
+#include "nsIAccessibleTypes.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsServiceManagerUtils.h"
 #include "nsWinUtils.h"
 
 #include "nsAutoPtr.h"
 
 #include "mozilla/dom/Element.h"
--- a/accessible/src/windows/sdn/sdnTextAccessible.cpp
+++ b/accessible/src/windows/sdn/sdnTextAccessible.cpp
@@ -11,16 +11,17 @@
 #include "nsCoreUtils.h"
 #include "DocAccessible.h"
 
 #include "nsIFrame.h"
 #include "nsFontMetrics.h"
 #include "nsPresContext.h"
 #include "nsLayoutUtils.h"
 #include "gfxFont.h"
+#include "nsIAccessibleTypes.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // sdnTextAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 IMPL_IUNKNOWN_QUERY_HEAD(sdnTextAccessible)
--- a/accessible/src/xul/XULFormControlAccessible.cpp
+++ b/accessible/src/xul/XULFormControlAccessible.cpp
@@ -23,16 +23,17 @@
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULTextboxElement.h"
 #include "nsIEditor.h"
 #include "nsIFrame.h"
 #include "nsINameSpaceManager.h"
 #include "nsITextControlFrame.h"
 #include "nsMenuPopupFrame.h"
+#include "mozilla/dom/Element.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULButtonAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULButtonAccessible::
--- a/accessible/src/xul/XULListboxAccessible.cpp
+++ b/accessible/src/xul/XULListboxAccessible.cpp
@@ -16,16 +16,17 @@
 #include "nsIAutoCompleteInput.h"
 #include "nsIAutoCompletePopup.h"
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMXULPopupElement.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIMutableArray.h"
+#include "nsIPersistentProperties2.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULColumAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULColumAccessible::
--- a/accessible/src/xul/XULSliderAccessible.cpp
+++ b/accessible/src/xul/XULSliderAccessible.cpp
@@ -5,16 +5,17 @@
 
 #include "XULSliderAccessible.h"
 
 #include "nsAccessibilityService.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsIFrame.h"
+#include "mozilla/dom/Element.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULSliderAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULSliderAccessible::
--- a/accessible/src/xul/XULTreeAccessible.cpp
+++ b/accessible/src/xul/XULTreeAccessible.cpp
@@ -16,16 +16,17 @@
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsComponentManagerUtils.h"
 #include "nsIAccessibleRelation.h"
 #include "nsIAutoCompleteInput.h"
 #include "nsIAutoCompletePopup.h"
+#include "nsIBoxObject.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMXULTreeElement.h"
 #include "nsITreeSelection.h"
 #include "nsIMutableArray.h"
 #include "nsTreeBodyFrame.h"
 #include "nsTreeColumns.h"
--- a/accessible/src/xul/XULTreeGridAccessible.cpp
+++ b/accessible/src/xul/XULTreeGridAccessible.cpp
@@ -9,17 +9,19 @@
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "DocAccessible.h"
 #include "nsEventShell.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
 
+#include "nsIBoxObject.h"
 #include "nsIMutableArray.h"
+#include "nsIPersistentProperties2.h"
 #include "nsITreeSelection.h"
 #include "nsComponentManagerUtils.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeGridAccessible: nsISupports implementation
 
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -68,17 +68,17 @@ pref("browser.sessionstore.resume_from_c
 pref("browser.sessionstore.interval", 10000); // milliseconds
 pref("browser.sessionstore.max_tabs_undo", 1);
 
 /* these should help performance */
 pref("mozilla.widget.force-24bpp", true);
 pref("mozilla.widget.use-buffer-pixmap", true);
 pref("mozilla.widget.disable-native-theme", true);
 pref("layout.reflow.synthMouseMove", false);
-pref("layers.force-tiles", false);
+pref("layers.force-tiles", true);
 
 /* download manager (don't show the window or alert) */
 pref("browser.download.useDownloadDir", true);
 pref("browser.download.folderList", 1); // Default to ~/Downloads
 pref("browser.download.manager.showAlertOnComplete", false);
 pref("browser.download.manager.showAlertInterval", 2000);
 pref("browser.download.manager.retention", 2);
 pref("browser.download.manager.showWhenStarting", false);
--- a/browser/base/content/test/browser_tabopen_reflows.js
+++ b/browser/base/content/test/browser_tabopen_reflows.js
@@ -33,18 +33,17 @@ const EXPECTED_REFLOWS = [
     "GroupItem_getContentBounds@chrome://browser/content/tabview.js|" +
     "GroupItem_shouldStack@chrome://browser/content/tabview.js|" +
     "GroupItem_arrange@chrome://browser/content/tabview.js|" +
     "GroupItem_add@chrome://browser/content/tabview.js|" +
     "GroupItems_newTab@chrome://browser/content/tabview.js|" +
     "TabItem__reconnect@chrome://browser/content/tabview.js|" +
     "TabItem@chrome://browser/content/tabview.js|" +
     "TabItems_link@chrome://browser/content/tabview.js|" +
-    "@chrome://browser/content/tabview.js|" +
-    "addTab@chrome://browser/content/tabbrowser.xml|",
+    "@chrome://browser/content/tabview.js|",
 
   // SessionStore.getWindowDimensions()
   "ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm|" +
     "@resource:///modules/sessionstore/SessionStore.jsm|" +
     "ssi_updateWindowFeatures@resource:///modules/sessionstore/SessionStore.jsm|" +
     "ssi_collectWindowData@resource:///modules/sessionstore/SessionStore.jsm|",
 
   // tabPreviews.capture()
@@ -83,31 +82,32 @@ function test() {
 }
 
 let observer = {
   reflow: function (start, end) {
     // Gather information about the current code path.
     let path = (new Error().stack).split("\n").slice(1).map(line => {
       return line.replace(/:\d+$/, "");
     }).join("|");
+    let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|");
 
     // Stack trace is empty. Reflow was triggered by native code.
     if (path === "") {
       return;
     }
 
     // Check if this is an expected reflow.
     for (let stack of EXPECTED_REFLOWS) {
       if (path.startsWith(stack)) {
         ok(true, "expected uninterruptible reflow '" + stack + "'");
         return;
       }
     }
 
-    ok(false, "unexpected uninterruptible reflow '" + path + "'");
+    ok(false, "unexpected uninterruptible reflow '" + pathWithLineNumbers + "'");
   },
 
   reflowInterruptible: function (start, end) {
     // We're not interested in interruptible reflows.
   },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
                                          Ci.nsISupportsWeakReference])
--- a/browser/components/feeds/src/WebContentConverter.js
+++ b/browser/components/feeds/src/WebContentConverter.js
@@ -364,16 +364,23 @@ WebContentConverterRegistrar.prototype =
 
   /**
    * See nsIWebContentHandlerRegistrar
    */
   registerProtocolHandler: 
   function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aContentWindow) {
     LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
 
+    var uri = this._checkAndGetURI(aURIString, aContentWindow);
+
+    // If the protocol handler is already registered, just return early.
+    if (this._protocolHandlerRegistered(aProtocol, uri.spec)) {
+      return;
+    }
+
     var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);    
     if (PrivateBrowsingUtils.isWindowPrivate(browserWindow)) {
       // Inside the private browsing mode, we don't want to alert the user to save
       // a protocol handler.  We log it to the error console so that web developers
       // would have some way to tell what's going wrong.
       Cc["@mozilla.org/consoleservice;1"].
       getService(Ci.nsIConsoleService).
       logStringMessage("Web page denied access to register a protocol handler inside private browsing mode");
@@ -401,35 +408,28 @@ WebContentConverterRegistrar.prototype =
     catch (e) {
       allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default");
     }
     if (!allowed) {
       // XXX this should be a "security exception" according to spec
       throw("Not allowed to register a protocol handler for " + aProtocol);
     }
 
-    var uri = this._checkAndGetURI(aURIString, aContentWindow);
+    // Now Ask the user and provide the proper callback
+    var message = this._getFormattedString("addProtocolHandler",
+                                           [aTitle, uri.host, aProtocol]);
 
-    var buttons, message;
-    if (this._protocolHandlerRegistered(aProtocol, uri.spec))
-      message = this._getFormattedString("protocolHandlerRegistered",
-                                         [aTitle, aProtocol]);
-    else {
-      // Now Ask the user and provide the proper callback
-      message = this._getFormattedString("addProtocolHandler",
-                                         [aTitle, uri.host, aProtocol]);
+    var notificationIcon = uri.prePath + "/favicon.ico";
+    var notificationValue = "Protocol Registration: " + aProtocol;
+    var addButton = {
+      label: this._getString("addProtocolHandlerAddButton"),
+      accessKey: this._getString("addHandlerAddButtonAccesskey"),
+      protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
 
-      var notificationIcon = uri.prePath + "/favicon.ico";
-      var notificationValue = "Protocol Registration: " + aProtocol;
-      var addButton = {
-        label: this._getString("addProtocolHandlerAddButton"),
-        accessKey: this._getString("addHandlerAddButtonAccesskey"),
-        protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
-
-        callback:
+      callback:
         function WCCR_addProtocolHandlerButtonCallback(aNotification, aButtonInfo) {
           var protocol = aButtonInfo.protocolInfo.protocol;
           var uri      = aButtonInfo.protocolInfo.uri;
           var name     = aButtonInfo.protocolInfo.name;
 
           var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
                         createInstance(Ci.nsIWebHandlerApp);
           handler.name = name;
@@ -445,21 +445,18 @@ WebContentConverterRegistrar.prototype =
           // to want to use it.  Reset the handlerInfo to ask before the next
           // use.
           handlerInfo.alwaysAskBeforeHandling = true;
 
           var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
                    getService(Ci.nsIHandlerService);
           hs.store(handlerInfo);
         }
-      };
-      buttons = [addButton];
-    }
-
-
+    };
+    var buttons;
     var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
     var notificationBox = browserWindow.getBrowser().getNotificationBox(browserElement);
     notificationBox.appendNotification(message,
                                        notificationValue,
                                        notificationIcon,
                                        notificationBox.PRIORITY_INFO_LOW,
                                        buttons);
   },
--- a/browser/components/sessionstore/test/browser_483330.js
+++ b/browser/components/sessionstore/test/browser_483330.js
@@ -23,15 +23,18 @@ function test() {
 
       let newBrowser = newTab.linkedBrowser;
 
       // check that the scroll position was restored
       is(newBrowser.contentWindow.scrollX, 1100, "still scrolled horizontally");
       is(newBrowser.contentWindow.scrollY, 1200, "still scrolled vertically");
 
       gBrowser.removeTab(newTab);
+      // Call stopPropagation on the event so we won't fire the
+      // tabbrowser's SSTabRestored listeners.
+      e.stopPropagation();
 
       finish();
     }, true);
   }, true);
 
   browser.loadURI("data:text/html;charset=utf-8,<body style='width: 100000px; height: 100000px;'><p>top</p></body>");
 }
--- a/browser/components/sessionstore/test/browser_491168.js
+++ b/browser/components/sessionstore/test/browser_491168.js
@@ -19,27 +19,34 @@ function test() {
 
     let tabState = JSON.parse(ss.getTabState(tab));
     is(tabState.entries[0].referrer,  REFERRER1,
        "Referrer retrieved via getTabState matches referrer set via loadURI.");
 
     tabState.entries[0].referrer = REFERRER2;
     ss.setTabState(tab, JSON.stringify(tabState));
 
-    tab.addEventListener("SSTabRestored", function() {
+    tab.addEventListener("SSTabRestored", function(e) {
       tab.removeEventListener("SSTabRestored", arguments.callee, true);
       is(window.content.document.referrer, REFERRER2, "document.referrer matches referrer set via setTabState.");
 
       gBrowser.removeTab(tab);
+      // Call stopPropagation on the event so we won't fire the
+      // tabbrowser's SSTabRestored listeners.
+      e.stopPropagation();
+
       let newTab = ss.undoCloseTab(window, 0);
-      newTab.addEventListener("SSTabRestored", function() {
+      newTab.addEventListener("SSTabRestored", function(e) {
         newTab.removeEventListener("SSTabRestored", arguments.callee, true);
 
         is(window.content.document.referrer, REFERRER2, "document.referrer is still correct after closing and reopening the tab.");
         gBrowser.removeTab(newTab);
+        // Call stopPropagation on the event so we won't fire the
+        // tabbrowser's SSTabRestored listeners.
+        e.stopPropagation();
 
         finish();
       }, true);
     }, true);
   },true);
 
   let referrerURI = Services.io.newURI(REFERRER1, null, null);
   browser.loadURI("http://example.org", referrerURI, null);
--- a/browser/components/sessionstore/test/browser_662743.js
+++ b/browser/components/sessionstore/test/browser_662743.js
@@ -93,16 +93,19 @@ function testTabRestoreData(aFormData, a
       let value = select.options[select.selectedIndex].value;
 
       // test select options values
       is(value, aExpectedValues[0],
         "Select Option by selectedIndex &/or value has been restored correctly");
 
       // clean up
       gBrowser.removeTab(tab);
+      // Call stopPropagation on the event so we won't fire the
+      // tabbrowser's SSTabRestored listeners.
+      aEvent.stopPropagation();
       aCallback();
     });
 
     tab.addEventListener("TabClose", function(aEvent) {
       tab.removeEventListener("TabClose", arguments.callee);
       let restoredTabState = JSON.parse(ss.getTabState(tab));
       let restoredFormData = restoredTabState.entries[0].formdata;
       let selectIdFormData = restoredFormData.id.select_id;
--- a/browser/locales/en-US/chrome/browser/feeds/subscribe.properties
+++ b/browser/locales/en-US/chrome/browser/feeds/subscribe.properties
@@ -44,10 +44,8 @@ feedSubscriptionVideoPodcast1=This is a 
 feedSubscriptionFeed2=You can subscribe to this feed to receive updates when this content changes.
 feedSubscriptionAudioPodcast2=You can subscribe to this podcast to receive updates when this content changes.
 feedSubscriptionVideoPodcast2=You can subscribe to this video podcast to receive updates when this content changes.
 
 # Protocol Handling
 # "Add %appName (%appDomain) as an application for %protocolType links?"
 addProtocolHandler=Add %S (%S) as an application for %S links?
 addProtocolHandlerAddButton=Add Application
-# "%appName has already been added as an application for %protocolType links."
-protocolHandlerRegistered=%S has already been added as an application for %S links.
--- a/build/pymake/pymake/parser.py
+++ b/build/pymake/pymake/parser.py
@@ -367,16 +367,19 @@ def parsefile(pathname):
     """
     Parse a filename into a parserdata.StatementList. A cache is used to avoid re-parsing
     makefiles that have already been parsed and have not changed.
     """
 
     pathname = os.path.realpath(pathname)
     return _parsecache.get(pathname)
 
+# colon followed by anything except a slash (Windows path detection)
+_depfilesplitter = re.compile(r':(?![\\/])')
+
 def parsedepfile(pathname):
     """
     Parse a filename listing only depencencies into a parserdata.StatementList.
     """
     def continuation_iter(lines):
         current_line = []
         for line in lines:
             line = line.rstrip()
@@ -389,17 +392,17 @@ def parsedepfile(pathname):
             yield ''.join(current_line)
             current_line = []
         if current_line:
             yield ''.join(current_line)
 
     pathname = os.path.realpath(pathname)
     stmts = parserdata.StatementList()
     for line in continuation_iter(open(pathname).readlines()):
-        target, deps = line.split(":", 1)
+        target, deps = _depfilesplitter.split(line, 1)
         stmts.append(parserdata.Rule(data.StringExpansion(target, None),
                                      data.StringExpansion(deps, None), False))
     return stmts
 
 def parsestring(s, filename):
     """
     Parse a string containing makefile data into a parserdata.StatementList.
     """
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -49,21 +49,21 @@ INCLUDED_RULES_MK = 1
   XPIDL_FLAGS \
   $(NULL)
 
 ifndef EXTERNALLY_MANAGED_MAKE_FILE
 # Using $(firstword) may not be perfect. But it should be good enough for most
 # scenarios.
 _current_makefile = $(CURDIR)/$(firstword $(MAKEFILE_LIST))
 
-$(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES),$(if $($(var)),\
+$(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES),$(if $(filter file override,$(subst $(NULL) ,_,$(origin $(var)))),\
     $(error Variable $(var) is defined in $(_current_makefile). It should only be defined in moz.build files),\
     ))
 
-$(foreach var,$(_DEPRECATED_VARIABLES),$(if $($(var)),\
+$(foreach var,$(_DEPRECATED_VARIABLES),$(if $(filter file override,$(subst $(NULL) ,_,$(origin $(var)))),\
     $(error Variable $(var) is defined in $(_current_makefile). This variable has been deprecated. It does nothing. It must be removed in order to build)\
     ))
 
 ifneq (,$(XPIDLSRCS)$(SDK_XPIDLSRCS))
     $(error XPIDLSRCS and SDK_XPIDLSRCS have been merged and moved to moz.build files as the XPIDL_SOURCES variable. You must move these variables out of $(_current_makefile))
 endif
 
 # Import the automatically generated backend file. If this file doesn't exist,
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -41,16 +41,17 @@ class nsIFrame;
 class nsIMutationObserver;
 class nsINodeList;
 class nsIPresShell;
 class nsIPrincipal;
 class nsIURI;
 class nsNodeSupportsWeakRefTearoff;
 class nsNodeWeakReference;
 class nsXPCClassInfo;
+class nsDOMMutationObserver;
 
 namespace mozilla {
 namespace dom {
 /**
  * @return true if aChar is what the DOM spec defines as 'space character'.
  * http://dom.spec.whatwg.org/#space-character
  */
 inline bool IsSpaceCharacter(PRUnichar aChar) {
@@ -1469,16 +1470,18 @@ protected:
 
 public:
   // Makes nsINode object to keep aObject alive.
   void BindObject(nsISupports* aObject);
   // After calling UnbindObject nsINode object doesn't keep
   // aObject alive anymore.
   void UnbindObject(nsISupports* aObject);
 
+  void GetBoundMutationObservers(nsTArray<nsRefPtr<nsDOMMutationObserver> >& aResult);
+
   /**
    * Returns the length of this node, as specified at
    * <http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length>
    */
   uint32_t Length() const;
 
   void GetNodeName(nsAString& aNodeName) const
   {
--- a/content/base/src/nsDOMMutationObserver.cpp
+++ b/content/base/src/nsDOMMutationObserver.cpp
@@ -61,17 +61,16 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_6(
 // Observer
 
 NS_IMPL_ADDREF(nsMutationReceiver)
 NS_IMPL_RELEASE(nsMutationReceiver)
 
 NS_INTERFACE_MAP_BEGIN(nsMutationReceiver)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
-  NS_INTERFACE_MAP_ENTRY(nsMutationReceiver)
 NS_INTERFACE_MAP_END
 
 nsMutationReceiver::nsMutationReceiver(nsINode* aTarget,
                                        nsDOMMutationObserver* aObserver)
 : nsMutationReceiverBase(aTarget, aObserver)
 {
   mTarget->BindObject(aObserver);
 }
@@ -316,16 +315,17 @@ void nsMutationReceiver::NodeWillBeDestr
   Disconnect(true);
 }
 
 // Observer
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationObserver)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsDOMMutationObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationObserver)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationObserver)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMutationObserver)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMMutationObserver)
@@ -520,16 +520,42 @@ nsDOMMutationObserver::Disconnect()
 void
 nsDOMMutationObserver::TakeRecords(
                          nsTArray<nsRefPtr<nsDOMMutationRecord> >& aRetVal)
 {
   aRetVal.Clear();
   mPendingMutations.SwapElements(aRetVal);
 }
 
+void
+nsDOMMutationObserver::GetObservingInfo(nsTArray<Nullable<MutationObservingInfoInitializer> >& aResult)
+{
+  aResult.SetCapacity(mReceivers.Count());
+  for (int32_t i = 0; i < mReceivers.Count(); ++i) {
+    MutationObservingInfoInitializer& info = aResult.AppendElement()->SetValue();
+    nsMutationReceiver* mr = mReceivers[i];
+    info.mChildList = mr->ChildList();
+    info.mAttributes = mr->Attributes();
+    info.mCharacterData = mr->CharacterData();
+    info.mSubtree = mr->Subtree();
+    info.mAttributeOldValue = mr->AttributeOldValue();
+    info.mCharacterDataOldValue = mr->CharacterDataOldValue();
+    nsCOMArray<nsIAtom>& filters = mr->AttributeFilter();
+    if (filters.Count()) {
+      info.mAttributeFilter.Construct();
+      mozilla::dom::Sequence<nsString>& filtersAsStrings =
+        info.mAttributeFilter.Value();
+      for (int32_t j = 0; j < filters.Count(); ++j) {
+        filtersAsStrings.AppendElement(nsDependentAtomString(filters[j]));
+      }
+    }
+    info.mObservedNode = mr->Target();
+  }
+}
+
 // static
 already_AddRefed<nsDOMMutationObserver>
 nsDOMMutationObserver::Constructor(const mozilla::dom::GlobalObject& aGlobal,
                                    mozilla::dom::MutationCallback& aCb,
                                    mozilla::ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
--- a/content/base/src/nsDOMMutationObserver.h
+++ b/content/base/src/nsDOMMutationObserver.h
@@ -20,16 +20,17 @@
 #include "mozilla/dom/Element.h"
 #include "nsClassHashtable.h"
 #include "nsNodeUtils.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsWrapperCache.h"
 #include "mozilla/dom/MutationObserverBinding.h"
 
 class nsDOMMutationObserver;
+using mozilla::dom::MutationObservingInfoInitializer;
 
 class nsDOMMutationRecord : public nsISupports,
                             public nsWrapperCache
 {
 public:
   nsDOMMutationRecord(const nsAString& aType, nsISupports* aOwner)
   : mType(aType), mOwner(aOwner)
   {
@@ -262,20 +263,16 @@ private:
   bool                               mCharacterDataOldValue;
   bool                               mAttributes;
   bool                               mAllAttributes;
   bool                               mAttributeOldValue;
   nsCOMArray<nsIAtom>                mAttributeFilter;
 };
 
 
-#define NS_MUTATION_OBSERVER_IID \
-{ 0xe628f313, 0x8129, 0x4f90, \
-  { 0x8e, 0xc3, 0x85, 0xe8, 0x28, 0x22, 0xe7, 0xab } }
-
 class nsMutationReceiver : public nsMutationReceiverBase
 {
 public:
   nsMutationReceiver(nsINode* aTarget, nsDOMMutationObserver* aObserver);
 
   nsMutationReceiver(nsINode* aRegisterTarget, nsMutationReceiverBase* aParent)
   : nsMutationReceiverBase(aRegisterTarget, aParent)
   {
@@ -310,17 +307,16 @@ public:
 
     mParent = nullptr;
     NS_ASSERTION(!mTarget, "Should not have mTarget");
     NS_ASSERTION(!mObserver, "Should not have mObserver");
   }
 
   void Disconnect(bool aRemoveFromObserver);
 
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMUTATION_OBSERVER_IID)
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
   NS_DECL_ISUPPORTS
 
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
@@ -332,31 +328,34 @@ public:
                                           nsIAtom* aAttribute) MOZ_OVERRIDE
   {
     // We can reuse AttributeWillChange implementation.
     AttributeWillChange(aDocument, aElement, aNameSpaceID, aAttribute,
                         nsIDOMMutationEvent::MODIFICATION);
   }
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(nsMutationReceiver, NS_MUTATION_OBSERVER_IID)
+#define NS_DOM_MUTATION_OBSERVER_IID \
+{ 0x0c3b91f8, 0xcc3b, 0x4b08, \
+  { 0x9e, 0xab, 0x07, 0x47, 0xa9, 0xe4, 0x65, 0xb4 } }
 
 class nsDOMMutationObserver : public nsISupports,
                               public nsWrapperCache
 {
 public:
   nsDOMMutationObserver(already_AddRefed<nsPIDOMWindow> aOwner,
                         mozilla::dom::MutationCallback& aCb)
   : mOwner(aOwner), mCallback(&aCb), mWaitingForRun(false), mId(++sCount)
   {
     SetIsDOMBinding();
   }
   virtual ~nsDOMMutationObserver();
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMMutationObserver)
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_MUTATION_OBSERVER_IID)
 
   static already_AddRefed<nsDOMMutationObserver>
   Constructor(const mozilla::dom::GlobalObject& aGlobal,
               mozilla::dom::MutationCallback& aCb,
               mozilla::ErrorResult& aRv);
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
@@ -374,16 +373,20 @@ public:
                mozilla::ErrorResult& aRv);
 
   void Disconnect();
 
   void TakeRecords(nsTArray<nsRefPtr<nsDOMMutationRecord> >& aRetVal);
 
   void HandleMutation();
 
+  void GetObservingInfo(nsTArray<Nullable<MutationObservingInfoInitializer> >& aResult);
+
+  mozilla::dom::MutationCallback* MutationCallback() { return mCallback; }
+
   // static methods
   static void HandleMutations()
   {
     if (sScheduledMutationObservers) {
       HandleMutationsInternal();
     }
   }
 
@@ -440,16 +443,18 @@ protected:
   static nsTArray<nsRefPtr<nsDOMMutationObserver> >* sScheduledMutationObservers;
   static nsDOMMutationObserver*                      sCurrentObserver;
 
   static uint32_t                                    sMutationLevel;
   static nsAutoTArray<nsTArray<nsRefPtr<nsDOMMutationObserver> >, 4>*
                                                      sCurrentlyHandlingObservers;
 };
 
+NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMMutationObserver, NS_DOM_MUTATION_OBSERVER_IID)
+
 class nsAutoMutationBatch
 {
 public:
   nsAutoMutationBatch()
   : mPreviousBatch(nullptr), mBatchTarget(nullptr), mRemovalDone(false),
     mFromFirstToLast(false), mAllowNestedBatches(false)    
   {
   }
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -98,16 +98,17 @@
 #include "nsCSSParser.h"
 #include "HTMLLegendElement.h"
 #include "nsWrapperCacheInlines.h"
 #include "WrapperFactory.h"
 #include "DocumentType.h"
 #include <algorithm>
 #include "nsDOMEvent.h"
 #include "nsGlobalWindow.h"
+#include "nsDOMMutationObserver.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsINode::nsSlots::~nsSlots()
 {
   if (mChildNodes) {
     mChildNodes->DropReference();
@@ -2139,16 +2140,32 @@ nsINode::UnbindObject(nsISupports* aObje
 {
   nsCOMArray<nsISupports>* objects =
     static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
   if (objects) {
     objects->RemoveObject(aObject);
   }
 }
 
+void
+nsINode::GetBoundMutationObservers(nsTArray<nsRefPtr<nsDOMMutationObserver> >& aResult)
+{
+  nsCOMArray<nsISupports>* objects =
+    static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
+  if (objects) {
+    for (int32_t i = 0; i < objects->Count(); ++i) {
+      nsCOMPtr<nsDOMMutationObserver> mo = do_QueryInterface(objects->ObjectAt(i));
+      if (mo) {
+        MOZ_ASSERT(!aResult.Contains(mo));
+        aResult.AppendElement(mo.forget());
+      }
+    }
+  }
+}
+
 size_t
 nsINode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t n = 0;
   nsEventListenerManager* elm =
     const_cast<nsINode*>(this)->GetListenerManager(false);
   if (elm) {
     n += elm->SizeOfIncludingThis(aMallocSizeOf);
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -12,16 +12,17 @@
 #include "jsfriendapi.h"
 #include "nsScriptLoader.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsIContent.h"
 #include "mozilla/dom/Element.h"
 #include "nsGkAtoms.h"
 #include "nsNetUtil.h"
+#include "nsIJSRuntimeService.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsJSPrincipals.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
@@ -93,16 +94,17 @@ public:
 
   nsCOMPtr<nsIScriptElement> mElement;
   bool mLoading;             // Are we still waiting for a load to complete?
   bool mIsInline;            // Is the script inline or loaded?
   nsString mScriptText;              // Holds script for loaded scripts
   uint32_t mJSVersion;
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIPrincipal> mOriginPrincipal;
+  nsAutoCString mURL;   // Keep the URI's filename alive during off thread parsing.
   int32_t mLineNo;
   const CORSMode mCORSMode;
 };
 
 // The nsScriptLoadRequest is passed as the context to necko, and thus
 // it needs to be threadsafe. Necko won't do anything with this
 // context, but it will AddRef and Release it on other threads.
 NS_IMPL_ISUPPORTS0(nsScriptLoadRequest)
@@ -686,22 +688,132 @@ nsScriptLoader::ProcessScriptElement(nsI
   // there's no document.write currently on the call stack. However,
   // this way matches IE more closely than checking if document.write
   // is on the call stack.
   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
       "Not safe to run a parser-inserted script?");
   return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
 }
 
+namespace {
+
+class NotifyOffThreadScriptLoadCompletedRunnable : public nsRunnable
+{
+    nsRefPtr<nsScriptLoader> mLoader;
+    void *mToken;
+
+public:
+    NotifyOffThreadScriptLoadCompletedRunnable(already_AddRefed<nsScriptLoader> aLoader,
+                                               void *aToken)
+      : mLoader(aLoader), mToken(aToken)
+    {}
+
+    NS_DECL_NSIRUNNABLE
+};
+
+} /* anonymous namespace */
+
 nsresult
-nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest)
+nsScriptLoader::ProcessOffThreadRequest(void **aOffThreadToken)
+{
+    nsCOMPtr<nsScriptLoadRequest> request = mOffThreadScriptRequest;
+    mOffThreadScriptRequest = nullptr;
+    mDocument->UnblockOnload(false);
+
+    return ProcessRequest(request, aOffThreadToken);
+}
+
+NS_IMETHODIMP
+NotifyOffThreadScriptLoadCompletedRunnable::Run()
+{
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsresult rv = mLoader->ProcessOffThreadRequest(&mToken);
+
+    if (mToken) {
+      // The result of the off thread parse was not actually needed to process
+      // the request (disappearing window, some other error, ...). Finish the
+      // request to avoid leaks in the JS engine.
+      nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
+      NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
+      JSRuntime *rt;
+      svc->GetRuntime(&rt);
+      NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE);
+      JS::FinishOffThreadScript(nullptr, rt, mToken);
+    }
+
+    return rv;
+}
+
+static void
+OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData)
+{
+    // Be careful not to adjust the refcount on the loader, as this callback
+    // may be invoked off the main thread.
+    nsScriptLoader* aLoader = static_cast<nsScriptLoader*>(aCallbackData);
+    nsRefPtr<NotifyOffThreadScriptLoadCompletedRunnable> notify =
+        new NotifyOffThreadScriptLoadCompletedRunnable(
+            already_AddRefed<nsScriptLoader>(aLoader), aToken);
+    NS_DispatchToMainThread(notify);
+}
+
+nsresult
+nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
+{
+  if (!aRequest->mElement->GetScriptAsync() || aRequest->mIsInline) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (mOffThreadScriptRequest) {
+    return NS_ERROR_FAILURE;
+  }
+
+  JSObject *unrootedGlobal;
+  nsCOMPtr<nsIScriptContext> context = GetScriptContext(&unrootedGlobal);
+  if (!context) {
+    return NS_ERROR_FAILURE;
+  }
+  AutoPushJSContext cx(context->GetNativeContext());
+  JS::Rooted<JSObject*> global(cx, unrootedGlobal);
+
+  JS::CompileOptions options(cx);
+  FillCompileOptionsForRequest(aRequest, &options);
+
+  if (!JS::CanCompileOffThread(cx, options)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mOffThreadScriptRequest = aRequest;
+  if (!JS::CompileOffThread(cx, global, options,
+                            aRequest->mScriptText.get(), aRequest->mScriptText.Length(),
+                            OffThreadScriptLoaderCallback,
+                            static_cast<void*>(this))) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  // This reference will be consumed by the NotifyOffThreadScriptLoadCompletedRunnable.
+  NS_ADDREF(this);
+
+  mDocument->BlockOnload();
+
+  return NS_OK;
+}
+
+nsresult
+nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest, void **aOffThreadToken)
 {
   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
                "Processing requests when running scripts is unsafe.");
 
+  if (!aOffThreadToken) {
+    nsresult rv = AttemptAsyncScriptParse(aRequest);
+    if (rv != NS_ERROR_FAILURE)
+      return rv;
+  }
+
   NS_ENSURE_ARG(aRequest);
   nsAFlatString* script;
   nsAutoString textData;
 
   nsCOMPtr<nsIDocument> doc;
 
   nsCOMPtr<nsINode> scriptElem = do_QueryInterface(aRequest->mElement);
 
@@ -746,17 +858,17 @@ nsScriptLoader::ProcessRequest(nsScriptL
   }
 
   nsresult rv = NS_OK;
   if (runScript) {
     if (doc) {
       doc->BeginEvaluatingExternalScript();
     }
     aRequest->mElement->BeginEvaluating();
-    rv = EvaluateScript(aRequest, *script);
+    rv = EvaluateScript(aRequest, *script, aOffThreadToken);
     aRequest->mElement->EndEvaluating();
     if (doc) {
       doc->EndEvaluatingExternalScript();
     }
 
     nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(),
                                          scriptElem,
                                          NS_LITERAL_STRING("afterscriptexecute"),
@@ -794,80 +906,97 @@ nsScriptLoader::FireScriptEvaluated(nsre
     nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i];
     obs->ScriptEvaluated(aResult, aRequest->mElement,
                          aRequest->mIsInline);
   }
 
   aRequest->FireScriptEvaluated(aResult);
 }
 
+nsIScriptContext *
+nsScriptLoader::GetScriptContext(JSObject **aGlobal)
+{
+  nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
+  NS_ASSERTION(pwin, "shouldn't be called with a null inner window");
+
+  nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
+  NS_ASSERTION(globalObject, "windows must be global objects");
+
+  // and make sure we are setup for this type of script.
+  nsresult rv = globalObject->EnsureScriptEnvironment();
+  if (NS_FAILED(rv)) {
+    return nullptr;
+  }
+
+  *aGlobal = globalObject->GetGlobalJSObject();
+  return globalObject->GetScriptContext();
+}
+
+void
+nsScriptLoader::FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
+                                             JS::CompileOptions *aOptions)
+{
+  // It's very important to use aRequest->mURI, not the final URI of the channel
+  // aRequest ended up getting script data from, as the script filename.
+  nsContentUtils::GetWrapperSafeScriptFilename(mDocument, aRequest->mURI, aRequest->mURL);
+
+  aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo);
+  aOptions->setVersion(JSVersion(aRequest->mJSVersion));
+  if (aRequest->mOriginPrincipal) {
+    aOptions->setOriginPrincipals(nsJSPrincipals::get(aRequest->mOriginPrincipal));
+  }
+}
+
 nsresult
 nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
-                               const nsAFlatString& aScript)
+                               const nsAFlatString& aScript,
+                               void** aOffThreadToken)
 {
   nsresult rv = NS_OK;
 
   // We need a document to evaluate scripts.
   if (!mDocument) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
   nsIDocument* ownerDoc = scriptContent->OwnerDoc();
   if (ownerDoc != mDocument) {
     // Willful violation of HTML5 as of 2010-12-01
     return NS_ERROR_FAILURE;
   }
 
-  nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
-  NS_ASSERTION(pwin, "shouldn't be called with a null inner window");
-
-  nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
-  NS_ASSERTION(globalObject, "windows must be global objects");
-
   // Get the script-type to be used by this element.
   NS_ASSERTION(scriptContent, "no content - what is default script-type?");
 
-  // and make sure we are setup for this type of script.
-  rv = globalObject->EnsureScriptEnvironment();
-  if (NS_FAILED(rv))
-    return rv;
-
   // Make sure context is a strong reference since we access it after
   // we've executed a script, which may cause all other references to
   // the context to go away.
-  nsCOMPtr<nsIScriptContext> context = globalObject->GetScriptContext();
+  JSObject *unrootedGlobal;
+  nsCOMPtr<nsIScriptContext> context = GetScriptContext(&unrootedGlobal);
   if (!context) {
     return NS_ERROR_FAILURE;
   }
   AutoPushJSContext cx(context->GetNativeContext());
+  JS::Rooted<JSObject*> global(cx, unrootedGlobal);
 
   bool oldProcessingScriptTag = context->GetProcessingScriptTag();
   context->SetProcessingScriptTag(true);
 
   // Update our current script.
   nsCOMPtr<nsIScriptElement> oldCurrent = mCurrentScript;
   mCurrentScript = aRequest->mElement;
 
-  // It's very important to use aRequest->mURI, not the final URI of the channel
-  // aRequest ended up getting script data from, as the script filename.
-  nsAutoCString url;
-  nsContentUtils::GetWrapperSafeScriptFilename(mDocument, aRequest->mURI, url);
-
   JSVersion version = JSVersion(aRequest->mJSVersion);
   if (version != JSVERSION_UNKNOWN) {
     JS::CompileOptions options(cx);
-    options.setFileAndLine(url.get(), aRequest->mLineNo)
-           .setVersion(JSVersion(aRequest->mJSVersion));
-    if (aRequest->mOriginPrincipal) {
-      options.setOriginPrincipals(nsJSPrincipals::get(aRequest->mOriginPrincipal));
-    }
-    JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
+    FillCompileOptionsForRequest(aRequest, &options);
     rv = context->EvaluateString(aScript, global,
-                                 options, /* aCoerceToString = */ false, nullptr);
+                                 options, /* aCoerceToString = */ false, nullptr,
+                                 aOffThreadToken);
   }
 
   // Put the old script back in case it wants to do anything else.
   mCurrentScript = oldCurrent;
 
   context->SetProcessingScriptTag(oldProcessingScriptTag);
   return rv;
 }
--- a/content/base/src/nsScriptLoader.h
+++ b/content/base/src/nsScriptLoader.h
@@ -202,16 +202,22 @@ public:
    *                     Void if not present.
    * @param aScriptFromHead Whether or not the script was a child of head
    */
   virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
                           const nsAString &aType,
                           const nsAString &aCrossOrigin,
                           bool aScriptFromHead);
 
+  /**
+   * Process a request that was deferred so that the script could be compiled
+   * off thread.
+   */
+  nsresult ProcessOffThreadRequest(void **aOffThreadToken);
+
 private:
   /**
    * Unblocks the creator parser of the parser-blocking scripts.
    */
   void UnblockParser(nsScriptLoadRequest* aParserBlockingRequest);
 
   /**
    * Asynchronously resumes the creator parser of the parser-blocking scripts.
@@ -256,24 +262,31 @@ private:
   bool SelfReadyToExecuteScripts()
   {
     return mEnabled && !mBlockerCount;
   }
 
   bool AddPendingChildLoader(nsScriptLoader* aChild) {
     return mPendingChildLoaders.AppendElement(aChild) != nullptr;
   }
-  
-  nsresult ProcessRequest(nsScriptLoadRequest* aRequest);
+
+  nsresult AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest);
+  nsresult ProcessRequest(nsScriptLoadRequest* aRequest,
+                          void **aOffThreadToken = nullptr);
   void FireScriptAvailable(nsresult aResult,
                            nsScriptLoadRequest* aRequest);
   void FireScriptEvaluated(nsresult aResult,
                            nsScriptLoadRequest* aRequest);
   nsresult EvaluateScript(nsScriptLoadRequest* aRequest,
-                          const nsAFlatString& aScript);
+                          const nsAFlatString& aScript,
+                          void **aOffThreadToken);
+
+  nsIScriptContext *GetScriptContext(JSObject **aGlobal);
+  void FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
+                                    JS::CompileOptions *aOptions);
 
   nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
                                 nsIStreamLoader* aLoader,
                                 nsresult aStatus,
                                 uint32_t aStringLen,
                                 const uint8_t* aString);
 
   nsIDocument* mDocument;                   // [WEAK]
@@ -297,16 +310,17 @@ private:
       return aRequest == aPi.mRequest;
     }
   };
   struct PreloadURIComparator {
     bool Equals(const PreloadInfo &aPi, nsIURI * const &aURI) const;
   };
   nsTArray<PreloadInfo> mPreloads;
 
+  nsCOMPtr<nsScriptLoadRequest> mOffThreadScriptRequest;
   nsCOMPtr<nsIScriptElement> mCurrentScript;
   nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript;
   // XXXbz do we want to cycle-collect these or something?  Not sure.
   nsTArray< nsRefPtr<nsScriptLoader> > mPendingChildLoaders;
   uint32_t mBlockerCount;
   bool mEnabled;
   bool mDeferEnabled;
   bool mDocumentParsingDone;
--- a/content/base/test/test_mutationobservers.html
+++ b/content/base/test/test_mutationobservers.html
@@ -148,17 +148,20 @@ function runTest() {
       is(records.length, 1, "Should have one record.");
       is(records[0].type, "attributes", "Should have got attributes record");
       is(records[0].target, div, "Should have got div as target");
       is(records[0].attributeName, "foo", "Should have got record about foo attribute");
       observer.disconnect();
       then(testThisBind);
       m = null;
     });
-  m.observe(div, { attributes: true});
+  m.observe(div, { attributes: true, attributeFilter: ["foo"] });
+  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributes, true);
+  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributeFilter.length, 1)
+  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributeFilter[0], "foo")
   div.setAttribute("foo", "bar");
 }
 
 // 'this' handling when fn.bind() is used.
 function testThisBind() {
   var child = div.appendChild(document.createElement("div"));
   var gchild = child.appendChild(document.createElement("div"));
   m = new M((function(records, observer) {
@@ -177,16 +180,19 @@ function testThisBind() {
       is(records[2].target, gchild, "Should have got div as target");
       is(records[2].attributeName, "foo", "Should have got record about foo attribute");
       is(records[2].oldValue, null, "oldValue should be bar2");
       observer.disconnect();
       then(testCharacterData);
       m = null;
     }).bind(window));
   m.observe(div, { attributes: true, attributeOldValue: true, subtree: true });
+  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributes, true)
+  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributeOldValue, true)
+  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].subtree, true)
   div.setAttribute("foo", "bar2");
   div.removeAttribute("foo");
   div.removeChild(child);
   child.removeChild(gchild);
   div.appendChild(gchild);
   div.removeChild(gchild);
   gchild.setAttribute("foo", "bar");
 }
@@ -220,16 +226,21 @@ function testCharacterData() {
 
   div.appendChild(document.createTextNode("foo"));
   m.observe(div, { characterData: true, subtree: true });
   m2.observe(div, { characterData: true, characterDataOldValue: true, subtree: true});
   // If observing the same node twice, only the latter option should apply.
   m3.observe(div, { characterData: true, subtree: true });
   m3.observe(div, { characterData: true, subtree: false });
   m4.observe(div.firstChild, { characterData: true, subtree: false });
+  
+  is(SpecialPowers.wrap(div).getBoundMutationObservers().length, 3)
+  is(SpecialPowers.wrap(div).getBoundMutationObservers()[2].getObservingInfo()[0].characterData, true)
+  is(SpecialPowers.wrap(div).getBoundMutationObservers()[2].getObservingInfo()[0].subtree, false)
+
   div.firstChild.data = "bar";
 }
 
 function testChildList() {
   var fc = div.firstChild;
   m = new M(function(records, observer) {
       is(records[0].type, "childList", "Should have got childList");
       is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
@@ -273,35 +284,42 @@ function testChildList3() {
 function testChildList4() {
   div.textContent = null;
   var df = document.createDocumentFragment();
   var t1 = df.appendChild(document.createTextNode("Hello "));
   var t2 = df.appendChild(document.createTextNode("world!"));
   var s1 = div.appendChild(document.createElement("span"));
   s1.textContent = "foo";
   var s2 = div.appendChild(document.createElement("span"));
-  m = new M(function(records, observer) {
+  function callback(records, observer) {
       is(records.length, 3, "Should have got one record for removing nodes from document fragment and one record for adding them to div");
       is(records[0].removedNodes.length, 2, "Should have got removedNodes");
       is(records[0].removedNodes[0], t1, "Should be the 1st textnode");
       is(records[0].removedNodes[1], t2, "Should be the 2nd textnode");
       is(records[1].addedNodes.length, 2, "Should have got addedNodes");
       is(records[1].addedNodes[0], t1, "Should be the 1st textnode");
       is(records[1].addedNodes[1], t2, "Should be the 2nd textnode");
       is(records[1].previousSibling, s1, "Should have previousSibling");
       is(records[1].nextSibling, s2, "Should have nextSibling");
       is(records[2].type, "characterData", "3rd record should be characterData");
       is(records[2].target, t1, "target should be the textnode");
       is(records[2].oldValue, "Hello ", "oldValue was 'Hello '");
       observer.disconnect();
       then(testChildList5);
       m = null;
-    });
+    };
+  m = new M(callback);
   m.observe(df, { childList: true, characterData: true, characterDataOldValue: true, subtree: true });
+  is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].childList, true)
+  is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].characterData, true)
+  is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].characterDataOldValue, true)
+  is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].subtree, true)
+  ok(SpecialPowers.compare(SpecialPowers.wrap(df).getBoundMutationObservers()[0].mutationCallback, callback))
   m.observe(div, { childList: true });
+  is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo().length, 2)
   
   // Make sure transient observers aren't leaked.
   var leakTest = new M(function(){});
   leakTest.observe(div, { characterData: true, subtree: true });
   
   div.insertBefore(df, s2);
   s1.firstChild.data = "bar"; // This should *not* create a record.
   t1.data = "Hello the whole "; // This should create a record.
@@ -549,16 +567,18 @@ function testTakeRecords() {
       is(records[1].attributeName, "foo", "");
       is(records[1].oldValue, "bar", "");
       observer.disconnect();
       div.removeEventListener("DOMAttrModified", mutationListener);
       then(testExpandos);
       m = null;
     });
   m.observe(div, { attributes: true, attributeOldValue: true });
+  // Note, [0] points to a mutation observer which is there for a leak test!
+  ok(SpecialPowers.compare(SpecialPowers.wrap(div).getBoundMutationObservers()[1], m));
   var mutationEventCount = 0;
   div.addEventListener("DOMAttrModified", mutationListener);
   div.setAttribute("foo", "bar");
   div.setAttribute("foo", "bar");
   is(mutationEventCount, 1, "Should have got only one mutation event!");
 }
 
 function testExpandos() {
--- a/content/html/content/public/HTMLCanvasElement.h
+++ b/content/html/content/public/HTMLCanvasElement.h
@@ -26,17 +26,19 @@ namespace mozilla {
 
 namespace layers {
 class CanvasLayer;
 class LayerManager;
 }
 
 namespace dom {
 
+class FileCallback;
 class HTMLCanvasPrintState;
+class PrintCallback;
 
 class HTMLCanvasElement MOZ_FINAL : public nsGenericHTMLElement,
                                     public nsICanvasElementExternal,
                                     public nsIDOMHTMLCanvasElement
 {
   enum {
     DEFAULT_CANVAS_WIDTH = 300,
     DEFAULT_CANVAS_HEIGHT = 150
@@ -87,26 +89,20 @@ public:
                  nsAString& aDataURL, ErrorResult& aRv)
   {
     JS::Value params = aParams.WasPassed()
                      ? aParams.Value()
                      : JS::UndefinedValue();
     aRv = ToDataURL(aType, params, aCx, aDataURL);
   }
   void ToBlob(JSContext* aCx,
-              nsIFileCallback* aCallback,
+              FileCallback& aCallback,
               const nsAString& aType,
               const Optional<JS::Handle<JS::Value> >& aParams,
-              ErrorResult& aRv)
-  {
-    JS::Value params = aParams.WasPassed()
-                     ? aParams.Value()
-                     : JS::UndefinedValue();
-    aRv = ToBlob(aCallback, aType, params, aCx);
-  }
+              ErrorResult& aRv);
 
   bool MozOpaque() const
   {
     return GetBoolAttr(nsGkAtoms::moz_opaque);
   }
   void SetMozOpaque(bool aValue, ErrorResult& aRv)
   {
     SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv);
@@ -121,18 +117,18 @@ public:
     aRv = MozGetIPCContext(aContextId, getter_AddRefs(context));
     return context.forget();
   }
   void MozFetchAsStream(nsIInputStreamCallback* aCallback,
                         const nsAString& aType, ErrorResult& aRv)
   {
     aRv = MozFetchAsStream(aCallback, aType);
   }
-  nsIPrintCallback* GetMozPrintCallback() const;
-  // Using XPCOM SetMozPrintCallback.
+  PrintCallback* GetMozPrintCallback() const;
+  void SetMozPrintCallback(PrintCallback* aCallback);
 
   /**
    * Get the size in pixels of this canvas element
    */
   nsIntSize GetSize();
 
   /**
    * Determine whether the canvas is write-only.
@@ -239,19 +235,19 @@ protected:
                             const nsAString& aType,
                             nsIDOMFile** aResult);
   nsresult GetContextHelper(const nsAString& aContextId,
                             nsICanvasRenderingContextInternal **aContext);
   void CallPrintCallback();
 
   nsString mCurrentContextId;
   nsRefPtr<HTMLCanvasElement> mOriginalCanvas;
-  nsCOMPtr<nsIPrintCallback> mPrintCallback;
+  nsRefPtr<PrintCallback> mPrintCallback;
   nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
-  nsCOMPtr<HTMLCanvasPrintState> mPrintState;
+  nsRefPtr<HTMLCanvasPrintState> mPrintState;
 
 public:
   // Record whether this canvas should be write-only or not.
   // We set this when script paints an image from a different origin.
   // We also transitively set it when script paints a canvas which
   // is itself write-only.
   bool                     mWriteOnly;
 
@@ -261,12 +257,47 @@ public:
 
   nsresult DispatchPrintCallback(nsITimerCallback* aCallback);
 
   void ResetPrintCallback();
 
   HTMLCanvasElement* GetOriginalCanvas();
 };
 
+class HTMLCanvasPrintState MOZ_FINAL : public nsWrapperCache
+{
+public:
+  HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
+                       nsICanvasRenderingContextInternal* aContext,
+                       nsITimerCallback* aCallback);
+
+  nsISupports* Context() const;
+
+  void Done();
+
+  void NotifyDone();
+
+  bool mIsDone;
+
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(HTMLCanvasPrintState)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(HTMLCanvasPrintState)
+
+  virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
+
+  HTMLCanvasElement* GetParentObject()
+  {
+    return mCanvas;
+  }
+
+private:
+  ~HTMLCanvasPrintState();
+  bool mPendingNotify;
+
+protected:
+  nsRefPtr<HTMLCanvasElement> mCanvas;
+  nsCOMPtr<nsICanvasRenderingContextInternal> mContext;
+  nsCOMPtr<nsITimerCallback> mCallback;
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLCanvasElement_h */
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -43,110 +43,98 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas)
 namespace {
 
 typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
 HTMLImageOrCanvasOrVideoElement;
 
 class ToBlobRunnable : public nsRunnable
 {
 public:
-  ToBlobRunnable(nsIFileCallback* aCallback,
+  ToBlobRunnable(mozilla::dom::FileCallback& aCallback,
                  nsIDOMBlob* aBlob)
-    : mCallback(aCallback),
+    : mCallback(&aCallback),
       mBlob(aBlob)
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   }
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-    mCallback->Receive(mBlob);
-    return NS_OK;
+    mozilla::ErrorResult rv;
+    mCallback->Call(mBlob, rv);
+    return rv.ErrorCode();
   }
 private:
-  nsCOMPtr<nsIFileCallback> mCallback;
+  nsRefPtr<mozilla::dom::FileCallback> mCallback;
   nsCOMPtr<nsIDOMBlob> mBlob;
 };
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 
-class HTMLCanvasPrintState : public nsIDOMMozCanvasPrintState
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(HTMLCanvasPrintState, mCanvas,
+                                        mContext, mCallback)
+
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(HTMLCanvasPrintState, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(HTMLCanvasPrintState, Release)
+
+HTMLCanvasPrintState::HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
+                                           nsICanvasRenderingContextInternal* aContext,
+                                           nsITimerCallback* aCallback)
+  : mIsDone(false), mPendingNotify(false), mCanvas(aCanvas),
+    mContext(aContext), mCallback(aCallback)
 {
-public:
-  HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
-                       nsICanvasRenderingContextInternal* aContext,
-                       nsITimerCallback* aCallback)
-    : mIsDone(false), mPendingNotify(false), mCanvas(aCanvas),
-      mContext(aContext), mCallback(aCallback)
-  {
-  }
+  SetIsDOMBinding();
+}
 
-  NS_IMETHOD GetContext(nsISupports** aContext)
-  {
-    NS_ADDREF(*aContext = mContext);
-    return NS_OK;
-  }
+HTMLCanvasPrintState::~HTMLCanvasPrintState()
+{
+}
 
-  NS_IMETHOD Done()
-  {
-    if (!mPendingNotify && !mIsDone) {
-      // The canvas needs to be invalidated for printing reftests on linux to
-      // work.
-      if (mCanvas) {
-        mCanvas->InvalidateCanvas();
-      }
-      nsRefPtr<nsRunnableMethod<HTMLCanvasPrintState> > doneEvent =
-        NS_NewRunnableMethod(this, &HTMLCanvasPrintState::NotifyDone);
-      if (NS_SUCCEEDED(NS_DispatchToCurrentThread(doneEvent))) {
-        mPendingNotify = true;
-      }
+/* virtual */ JSObject*
+HTMLCanvasPrintState::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return MozCanvasPrintStateBinding::Wrap(aCx, aScope, this);
+}
+
+nsISupports*
+HTMLCanvasPrintState::Context() const
+{
+  return mContext;
+}
+
+void
+HTMLCanvasPrintState::Done()
+{
+  if (!mPendingNotify && !mIsDone) {
+    // The canvas needs to be invalidated for printing reftests on linux to
+    // work.
+    if (mCanvas) {
+      mCanvas->InvalidateCanvas();
     }
-    return NS_OK;
-  }
-
-  void NotifyDone()
-  {
-    mIsDone = true;
-    mPendingNotify = false;
-    if (mCallback) {
-      mCallback->Notify(nullptr);
+    nsRefPtr<nsRunnableMethod<HTMLCanvasPrintState> > doneEvent =
+      NS_NewRunnableMethod(this, &HTMLCanvasPrintState::NotifyDone);
+    if (NS_SUCCEEDED(NS_DispatchToCurrentThread(doneEvent))) {
+      mPendingNotify = true;
     }
   }
-
-  bool mIsDone;
-
-  // CC
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(HTMLCanvasPrintState)
-private:
-  virtual ~HTMLCanvasPrintState()
-  {
-  }
-  bool mPendingNotify;
+}
 
-protected:
-  nsRefPtr<HTMLCanvasElement> mCanvas;
-  nsCOMPtr<nsICanvasRenderingContextInternal> mContext;
-  nsCOMPtr<nsITimerCallback> mCallback;
-};
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLCanvasPrintState)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLCanvasPrintState)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLCanvasPrintState)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMozCanvasPrintState)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozCanvasPrintState)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION_3(HTMLCanvasPrintState, mCanvas, mContext, mCallback)
+void
+HTMLCanvasPrintState::NotifyDone()
+{
+  mIsDone = true;
+  mPendingNotify = false;
+  if (mCallback) {
+    mCallback->Notify(nullptr);
+  }
+}
 
 // ---------------------------------------------------------------------------
 
 HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo),
     mWriteOnly(false)
 {
 }
@@ -221,21 +209,19 @@ HTMLCanvasElement::SetAttr(int32_t aName
 
 void
 HTMLCanvasElement::HandlePrintCallback(nsPresContext::nsPresContextType aType)
 {
   // Only call the print callback here if 1) we're in a print testing mode or
   // print preview mode, 2) the canvas has a print callback and 3) the callback
   // hasn't already been called. For real printing the callback is handled in
   // nsSimplePageSequenceFrame::PrePrintNextPage.
-  nsCOMPtr<nsIPrintCallback> printCallback;
   if ((aType == nsPresContext::eContext_PageLayout ||
        aType == nsPresContext::eContext_PrintPreview) &&
-      !mPrintState &&
-      NS_SUCCEEDED(GetMozPrintCallback(getter_AddRefs(printCallback))) && printCallback) {
+      !mPrintState && GetMozPrintCallback()) {
     DispatchPrintCallback(nullptr);
   }
 }
 
 nsresult
 HTMLCanvasElement::DispatchPrintCallback(nsITimerCallback* aCallback)
 {
   // For print reftests the context may not be initialized yet, so get a context
@@ -251,19 +237,18 @@ HTMLCanvasElement::DispatchPrintCallback
   nsRefPtr<nsRunnableMethod<HTMLCanvasElement> > renderEvent =
         NS_NewRunnableMethod(this, &HTMLCanvasElement::CallPrintCallback);
   return NS_DispatchToCurrentThread(renderEvent);
 }
 
 void
 HTMLCanvasElement::CallPrintCallback()
 {
-  nsCOMPtr<nsIPrintCallback> printCallback;
-  GetMozPrintCallback(getter_AddRefs(printCallback));
-  printCallback->Render(mPrintState);
+  ErrorResult rv;
+  GetMozPrintCallback()->Call(*mPrintState, rv);
 }
 
 void
 HTMLCanvasElement::ResetPrintCallback()
 {
   if (mPrintState) {
     mPrintState = nullptr;
   }
@@ -381,39 +366,31 @@ HTMLCanvasElement::MozFetchAsStream(nsII
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIInputStreamCallback> asyncCallback =
     NS_NewInputStreamReadyEvent(aCallback, mainThread);
 
   return asyncCallback->OnInputStreamReady(asyncData);
 }
 
-NS_IMETHODIMP
-HTMLCanvasElement::SetMozPrintCallback(nsIPrintCallback *aCallback)
+void
+HTMLCanvasElement::SetMozPrintCallback(PrintCallback* aCallback)
 {
   mPrintCallback = aCallback;
-  return NS_OK;
 }
 
-nsIPrintCallback*
+PrintCallback*
 HTMLCanvasElement::GetMozPrintCallback() const
 {
   if (mOriginalCanvas) {
     return mOriginalCanvas->GetMozPrintCallback();
   }
   return mPrintCallback;
 }
 
-NS_IMETHODIMP
-HTMLCanvasElement::GetMozPrintCallback(nsIPrintCallback** aCallback)
-{
-  NS_IF_ADDREF(*aCallback = GetMozPrintCallback());
-  return NS_OK;
-}
-
 nsresult
 HTMLCanvasElement::ExtractData(const nsAString& aType,
                                const nsAString& aOptions,
                                nsIInputStream** aStream,
                                bool& aFellBackToPNG)
 {
   // note that if we don't have a current context, the spec says we're
   // supposed to just return transparent black pixels of the canvas
@@ -566,81 +543,92 @@ HTMLCanvasElement::ToDataURLImpl(JSConte
   rv = stream->Available(&count);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(count <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
 
   return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
 }
 
 // XXXkhuey the encoding should be off the main thread, but we're lazy.
-NS_IMETHODIMP
-HTMLCanvasElement::ToBlob(nsIFileCallback* aCallback,
+void
+HTMLCanvasElement::ToBlob(JSContext* aCx,
+                          FileCallback& aCallback,
                           const nsAString& aType,
-                          const JS::Value& aEncoderOptions,
-                          JSContext* aCx)
+                          const Optional<JS::Handle<JS::Value> >& aParams,
+                          ErrorResult& aRv)
 {
   // do a trust check if this is a write-only canvas
   if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
-    return NS_ERROR_DOM_SECURITY_ERR;
-  }
-
-  if (!aCallback) {
-    return NS_ERROR_UNEXPECTED;
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
   }
 
   nsAutoString type;
-  nsresult rv = nsContentUtils::ASCIIToLower(aType, type);
-  if (NS_FAILED(rv)) {
-    return rv;
+  aRv = nsContentUtils::ASCIIToLower(aType, type);
+  if (aRv.Failed()) {
+    return;
   }
 
+  JS::Value encoderOptions = aParams.WasPassed()
+                             ? aParams.Value()
+                             : JS::UndefinedValue();
+
   nsAutoString params;
   bool usingCustomParseOptions;
-  rv = ParseParams(aCx, type, aEncoderOptions, params, &usingCustomParseOptions);
-  if (NS_FAILED(rv)) {
-    return rv;
+  aRv = ParseParams(aCx, type, encoderOptions, params, &usingCustomParseOptions);
+  if (aRv.Failed()) {
+    return;
   }
 
   bool fallbackToPNG = false;
 
   nsCOMPtr<nsIInputStream> stream;
-  rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
+  aRv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
   // If there are unrecognized custom parse options, we should fall back to
   // the default values for the encoder without any options at all.
-  if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
+  if (aRv.ErrorCode() == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
     fallbackToPNG = false;
-    rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
+    aRv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
   }
 
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (aRv.Failed()) {
+    return;
+  }
 
   if (fallbackToPNG) {
     type.AssignLiteral("image/png");
   }
 
   uint64_t imgSize;
-  rv = stream->Available(&imgSize);
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(imgSize <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
+  aRv = stream->Available(&imgSize);
+  if (aRv.Failed()) {
+    return;
+  }
+  if (imgSize > UINT32_MAX) {
+    aRv.Throw(NS_ERROR_FILE_TOO_BIG);
+    return;
+  }
 
   void* imgData = nullptr;
-  rv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
-  NS_ENSURE_SUCCESS(rv, rv);
+  aRv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
+  if (aRv.Failed()) {
+    return;
+  }
 
   // The DOMFile takes ownership of the buffer
   nsRefPtr<nsDOMMemoryFile> blob =
     new nsDOMMemoryFile(imgData, imgSize, type);
 
   JSContext* cx = nsContentUtils::GetCurrentJSContext();
   if (cx) {
     JS_updateMallocCounter(cx, imgSize);
   }
 
   nsRefPtr<ToBlobRunnable> runnable = new ToBlobRunnable(aCallback, blob);
-  return NS_DispatchToCurrentThread(runnable);
+  aRv = NS_DispatchToCurrentThread(runnable);
 }
 
 already_AddRefed<nsIDOMFile>
 HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
                                 const nsAString& aType,
                                 ErrorResult& aRv)
 {
   nsCOMPtr<nsIDOMFile> file;
@@ -1047,10 +1035,8 @@ HTMLCanvasElement::RenderContextsExterna
   if (!mCurrentContext)
     return NS_OK;
 
   return mCurrentContext->Render(aContext, aFilter, aFlags);
 }
 
 } // namespace dom
 } // namespace mozilla
-
-DOMCI_DATA(MozCanvasPrintState, mozilla::dom::HTMLCanvasPrintState)
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2347,19 +2347,22 @@ MediaStreamGraph::CreateNonRealtimeInsta
   MediaStreamGraphImpl* graph = new MediaStreamGraphImpl(false);
   return graph;
 }
 
 void
 MediaStreamGraph::DestroyNonRealtimeInstance(MediaStreamGraph* aGraph)
 {
   NS_ASSERTION(NS_IsMainThread(), "Main thread only");
-  MOZ_ASSERT(aGraph != gGraph, "Should not destroy the global graph here");
+  MOZ_ASSERT(aGraph->IsNonRealtime(), "Should not destroy the global graph here");
 
   MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(aGraph);
+  if (graph->mForceShutDown)
+    return; // already done
+
   if (!graph->mNonRealtimeProcessing) {
     // Start the graph, but don't produce anything
     graph->StartNonRealtimeProcessing(0);
   }
   graph->ForceShutDown();
 }
 
 SourceMediaStream*
@@ -2416,16 +2419,22 @@ MediaStreamGraph::CreateAudioNodeStream(
     stream->SetChannelMixingParametersImpl(aEngine->NodeMainThread()->ChannelCount(),
                                            aEngine->NodeMainThread()->ChannelCountModeValue(),
                                            aEngine->NodeMainThread()->ChannelInterpretationValue());
   }
   graph->AppendMessage(new CreateMessage(stream));
   return stream;
 }
 
+bool
+MediaStreamGraph::IsNonRealtime() const
+{
+  return this != gGraph;
+}
+
 void
 MediaStreamGraph::StartNonRealtimeProcessing(uint32_t aTicksToProcess)
 {
   NS_ASSERTION(NS_IsMainThread(), "main thread only");
 
   MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(this);
   NS_ASSERTION(!graph->mRealtime, "non-realtime only");
 
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -970,16 +970,17 @@ public:
   // We ensure that the graph current time advances in multiples of
   // IdealAudioBlockSize()/IdealAudioRate(). A stream that never blocks
   // and has a track with the ideal audio rate will produce audio in
   // multiples of the block size.
 
   // Main thread only
   static MediaStreamGraph* GetInstance();
   static MediaStreamGraph* CreateNonRealtimeInstance();
+  // Idempotent
   static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
 
   // Control API.
   /**
    * Create a stream that a media decoder (or some other source of
    * media data, such as a camera) can write to.
    */
   SourceMediaStream* CreateSourceStream(DOMMediaStream* aWrapper);
@@ -1017,16 +1018,18 @@ public:
                                      TrackRate aSampleRate = 0);
 
   /**
    * Returns the number of graph updates sent. This can be used to track
    * whether a given update has been processed by the graph thread and reflected
    * in main-thread stream state.
    */
   int64_t GetCurrentGraphUpdateIndex() { return mGraphUpdatesSent; }
+
+  bool IsNonRealtime() const;
   /**
    * Start processing non-realtime for a specific number of ticks.
    */
   void StartNonRealtimeProcessing(uint32_t aTicksToProcess);
 
   /**
    * Media graph thread only.
    * Dispatches a runnable that will run on the main thread after all
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -84,17 +84,16 @@ MOCHITEST_FILES = \
 		test_metadata.html \
 		test_no_load_event.html \
 		test_networkState.html \
 		test_new_audio.html \
 		test_paused.html \
 		test_paused_after_ended.html \
 		test_play_events.html \
 		test_play_events_2.html \
-		$(filter disabled-temporarily--bug-751539, test_played.html) \
 		test_playback_errors.html \
 		test_seekable1.html \
 		test_preload_actions.html \
 		test_preload_attribute.html \
 		test_progress.html \
 		test_reactivate.html \
 		test_readyState.html \
 		test_replay_metadata.html \
@@ -160,26 +159,38 @@ endif
 #   test_videoDocumentTitle.html
 # Bug 493692:
 #   test_preload_suspend.html
 # Bug 567954 and Bug 574586:
 #   test_mixed_principals.html
 # Disabled since we don't play Wave files standalone, for now
 #		test_audioDocumentTitle.html
 
-# The below tests are disabled due to frequent timeouts.
+# The below tests are disabled on Windows due to frequent timeouts.
 # Bug 832768 and Bug 864682:
 #		test_buffered.html
 #		test_bug465498.html
 # Bug 707777:
 #		test_bug493187.html
 # Bug 832678, bug 795271, and bug 857424
 #		test_seek.html
 # Bug 832768, bug 814533, bug 840742
 #		test_playback_rate.html
+# Bug 751539
+#		test_played.html
+ifneq ($(OS_ARCH), WINNT)
+MOCHITEST_FILES += \
+		test_buffered.html \
+		test_bug465498.html \
+		test_bug493187.html \
+		test_seek.html \
+		test_playback_rate.html \
+		test_played.html \
+		$(NULL)
+endif
 
 # sample files
 MOCHITEST_FILES += \
 		320x240.ogv \
 		448636.ogv \
 		audio-overhang.ogg \
 		audio-gaps.ogg \
 		badtags.ogg \
--- a/content/media/test/test_playback_rate.html
+++ b/content/media/test/test_playback_rate.html
@@ -5,16 +5,18 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type='application/javascript;version=1.8'>
 
+SimpleTest.expectAssertions(0, 2);
+
 if (navigator.platform.startsWith("Win")) {
   SimpleTest.expectAssertions(0, 1);
 } else if (navigator.platform.startsWith("Mac")) {
   SimpleTest.expectAssertions(0, 2);
 }
 
 let manager = new MediaTestManager;
 
--- a/content/media/test/test_played.html
+++ b/content/media/test/test_played.html
@@ -8,16 +8,18 @@
 <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id='test'>
 <script class="testbody" type='application/javascript;version=1.8'>
 
 let manager = new MediaTestManager;
 
+SimpleTest.expectAssertions(0, 2);
+
 function finish_test(element) {
   if (element.parentNode)
     element.parentNode.removeChild(element);
   element.src="";
   manager.finished(element.token);
 }
 
 // Check that a file has been played in its entirety.
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -408,17 +408,17 @@ public:
           FillWithZeroes(aOutput, channels, &written, &currentPosition, TRACK_TICKS_MAX);
         }
       }
     }
 
     // We've finished if we've gone past mStop, or if we're past mDuration when
     // looping is disabled.
     if (currentPosition >= mStop ||
-        (!mLoop && currentPosition - mStart + mOffset > mDuration)) {
+        (!mLoop && currentPosition - mStart + mOffset >= mDuration)) {
       *aFinished = true;
     }
   }
 
   TrackTicks mStart;
   TrackTicks mStop;
   nsRefPtr<ThreadSharedFloatArrayBufferList> mBuffer;
   SpeexResamplerState* mResampler;
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -58,21 +58,26 @@ AudioContext::AudioContext(nsPIDOMWindow
                                           aIsOffline, aNumberOfChannels,
                                           aLength, aSampleRate))
   , mNumberOfChannels(aNumberOfChannels)
   , mIsOffline(aIsOffline)
 {
   // Actually play audio
   mDestination->Stream()->AddAudioOutput(&gWebAudioOutputKey);
   nsDOMEventTargetHelper::BindToOwner(aWindow);
+  aWindow->AddAudioContext(this);
   SetIsDOMBinding();
 }
 
 AudioContext::~AudioContext()
 {
+  nsPIDOMWindow* window = GetOwner();
+  if (window) {
+    window->RemoveAudioContext(this);
+  }
 }
 
 JSObject*
 AudioContext::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   if (mIsOffline) {
     return OfflineAudioContextBinding::Wrap(aCx, aScope, this);
   } else {
@@ -86,17 +91,16 @@ AudioContext::Constructor(const GlobalOb
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<AudioContext> object = new AudioContext(window, false);
-  window->AddAudioContext(object);
   return object.forget();
 }
 
 /* static */ already_AddRefed<AudioContext>
 AudioContext::Constructor(const GlobalObject& aGlobal,
                           uint32_t aNumberOfChannels,
                           uint32_t aLength,
                           float aSampleRate,
@@ -118,17 +122,16 @@ AudioContext::Constructor(const GlobalOb
     return nullptr;
   }
 
   nsRefPtr<AudioContext> object = new AudioContext(window,
                                                    true,
                                                    aNumberOfChannels,
                                                    aLength,
                                                    aSampleRate);
-  window->AddAudioContext(object);
   return object.forget();
 }
 
 already_AddRefed<AudioBufferSourceNode>
 AudioContext::CreateBufferSource()
 {
   nsRefPtr<AudioBufferSourceNode> bufferNode =
     new AudioBufferSourceNode(this);
@@ -513,35 +516,20 @@ GetHashtableEntry(nsPtrHashKey<T>* aEntr
 template <class T>
 static void
 GetHashtableElements(nsTHashtable<nsPtrHashKey<T> >& aHashtable, nsTArray<T*>& aArray)
 {
   aHashtable.EnumerateEntries(&GetHashtableEntry<T>, &aArray);
 }
 
 void
-AudioContext::ShutdownDecoder()
-{
-  mDecoder.Shutdown();
-}
-
-void
 AudioContext::Shutdown()
 {
   Suspend();
 
-  // We need to hold the AudioContext object alive here to make sure that
-  // it doesn't get destroyed before our decoder shutdown runnable has had
-  // a chance to run.
-  nsCOMPtr<nsIRunnable> threadShutdownEvent =
-    NS_NewRunnableMethod(this, &AudioContext::ShutdownDecoder);
-  if (threadShutdownEvent) {
-    NS_DispatchToCurrentThread(threadShutdownEvent);
-  }
-
   // Stop all audio buffer source nodes, to make sure that they release
   // their self-references.
   // We first gather an array of the nodes and then call Stop on each one,
   // since Stop may delete the object and therefore trigger a re-entrant
   // hashtable call to remove the pointer from the hashtable, which is
   // not safe.
   nsTArray<AudioBufferSourceNode*> sourceNodes;
   GetHashtableElements(mAudioBufferSourceNodes, sourceNodes);
@@ -562,17 +550,17 @@ AudioContext::Shutdown()
   nsTArray<ScriptProcessorNode*> spNodes;
   GetHashtableElements(mScriptProcessorNodes, spNodes);
   for (uint32_t i = 0; i < spNodes.Length(); ++i) {
     spNodes[i]->Stop();
   }
 
   // For offline contexts, we can destroy the MediaStreamGraph at this point.
   if (mIsOffline) {
-    mDestination->DestroyGraph();
+    mDestination->OfflineShutdown();
   }
 }
 
 void
 AudioContext::Suspend()
 {
   MediaStream* ds = DestinationStream();
   if (ds) {
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -74,17 +74,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioContext,
                                            nsDOMEventTargetHelper)
 
   nsPIDOMWindow* GetParentObject() const
   {
     return GetOwner();
   }
 
-  void Shutdown();
+  void Shutdown(); // idempotent
   void Suspend();
   void Resume();
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   using nsDOMEventTargetHelper::DispatchTrustedEvent;
 
--- a/content/media/webaudio/AudioDestinationNode.cpp
+++ b/content/media/webaudio/AudioDestinationNode.cpp
@@ -120,21 +120,23 @@ public:
         }
 
         nsRefPtr<AudioContext> context;
         {
           MutexAutoLock lock(mStream->Engine()->NodeMutex());
           AudioNode* node = mStream->Engine()->Node();
           if (node) {
             context = node->Context();
+            MOZ_ASSERT(context, "node hasn't kept context alive");
           }
         }
         if (!context) {
           return NS_OK;
         }
+        context->Shutdown(); // drops self reference
 
         AutoPushJSContext cx(context->GetJSContext());
         if (cx) {
           JSAutoRequest ar(cx);
 
           // Create the input buffer
           nsRefPtr<AudioBuffer> renderedBuffer = new AudioBuffer(context,
                                                                  mLength,
@@ -230,16 +232,29 @@ AudioDestinationNode::AudioDestinationNo
   AudioNodeEngine* engine = aIsOffline ?
                             new OfflineDestinationNodeEngine(this, aNumberOfChannels,
                                                              aLength, aSampleRate) :
                             static_cast<AudioNodeEngine*>(new DestinationNodeEngine(this));
 
   mStream = graph->CreateAudioNodeStream(engine, MediaStreamGraph::EXTERNAL_STREAM);
 }
 
+void
+AudioDestinationNode::DestroyMediaStream()
+{
+  if (!mStream)
+    return;
+
+  MediaStreamGraph* graph = mStream->Graph();
+  if (graph->IsNonRealtime()) {
+    MediaStreamGraph::DestroyNonRealtimeInstance(graph);
+  }
+  AudioNode::DestroyMediaStream();
+}
+
 uint32_t
 AudioDestinationNode::MaxChannelCount() const
 {
   return Context()->MaxChannelCount();
 }
 
 void
 AudioDestinationNode::SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv)
@@ -262,29 +277,32 @@ AudioDestinationNode::Mute()
 void
 AudioDestinationNode::Unmute()
 {
   MOZ_ASSERT(Context() && !Context()->IsOffline());
   SendDoubleParameterToStream(DestinationNodeEngine::VOLUME, 1.0f);
 }
 
 void
-AudioDestinationNode::DestroyGraph()
+AudioDestinationNode::OfflineShutdown()
 {
   MOZ_ASSERT(Context() && Context()->IsOffline(),
              "Should only be called on a valid OfflineAudioContext");
+
   MediaStreamGraph::DestroyNonRealtimeInstance(mStream->Graph());
+  mOfflineRenderingRef.Drop(this);
 }
 
 JSObject*
 AudioDestinationNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return AudioDestinationNodeBinding::Wrap(aCx, aScope, this);
 }
 
 void
 AudioDestinationNode::StartRendering()
 {
+  mOfflineRenderingRef.Take(this);
   mStream->Graph()->StartNonRealtimeProcessing(mFramesToProduce);
 }
 
 }
 }
--- a/content/media/webaudio/AudioDestinationNode.h
+++ b/content/media/webaudio/AudioDestinationNode.h
@@ -20,16 +20,18 @@ public:
   // This node type knows what MediaStreamGraph to use based on
   // whether it's in offline mode.
   AudioDestinationNode(AudioContext* aContext,
                        bool aIsOffline,
                        uint32_t aNumberOfChannels = 0,
                        uint32_t aLength = 0,
                        float aSampleRate = 0.0f);
 
+  virtual void DestroyMediaStream() MOZ_OVERRIDE;
+
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   virtual uint16_t NumberOfOutputs() const MOZ_FINAL MOZ_OVERRIDE
   {
     return 0;
@@ -39,19 +41,20 @@ public:
   virtual void SetChannelCount(uint32_t aChannelCount,
                                ErrorResult& aRv) MOZ_OVERRIDE;
 
   void Mute();
   void Unmute();
 
   void StartRendering();
 
-  void DestroyGraph();
+  void OfflineShutdown();
 
 private:
+  SelfReference<AudioDestinationNode> mOfflineRenderingRef;
   uint32_t mFramesToProduce;
 };
 
 }
 }
 
 #endif
 
--- a/content/media/webaudio/AudioNode.h
+++ b/content/media/webaudio/AudioNode.h
@@ -97,21 +97,19 @@ private:
 
 /**
  * The DOM object representing a Web Audio AudioNode.
  *
  * Each AudioNode has a MediaStream representing the actual
  * real-time processing and output of this AudioNode.
  *
  * We track the incoming and outgoing connections to other AudioNodes.
- * All connections are strong and thus rely on cycle collection to break them.
- * However, we also track whether an AudioNode is capable of producing output
- * in the future. If it isn't, then we break its connections to its inputs
- * and outputs, allowing nodes to be immediately disconnected. This
- * disconnection is done internally, invisible to DOM users.
+ * Outgoing connections have strong ownership.  Also, AudioNodes add self
+ * references if they produce sound on their output even when they have silent
+ * or no input.
  */
 class AudioNode : public nsDOMEventTargetHelper,
                   public EnableWebAudioCheck
 {
 protected:
   // You can only use refcounting to delete this object
   virtual ~AudioNode();
 
--- a/content/media/webaudio/MediaBufferDecoder.cpp
+++ b/content/media/webaudio/MediaBufferDecoder.cpp
@@ -567,25 +567,16 @@ MediaBufferDecoder::EnsureThreadPoolInit
     if (!mThreadPool) {
       return false;
     }
     mThreadPool->SetName(NS_LITERAL_CSTRING("MediaBufferDecoder"));
   }
   return true;
 }
 
-void
-MediaBufferDecoder::Shutdown() {
-  if (mThreadPool) {
-    mThreadPool->Shutdown();
-    mThreadPool = nullptr;
-  }
-  MOZ_ASSERT(!mThreadPool);
-}
-
 WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
                                      AudioContext* aContext,
                                      const ArrayBuffer& aBuffer,
                                      DecodeSuccessCallback* aSuccessCallback,
                                      DecodeErrorCallback* aFailureCallback)
   : mContentType(aContentType)
   , mWriteIndex(0)
   , mContext(aContext)
--- a/content/media/webaudio/MediaBufferDecoder.h
+++ b/content/media/webaudio/MediaBufferDecoder.h
@@ -75,18 +75,16 @@ class MediaBufferDecoder
 {
 public:
   void AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
                         uint32_t aLength, WebAudioDecodeJob& aDecodeJob);
 
   bool SyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
                        uint32_t aLength, WebAudioDecodeJob& aDecodeJob);
 
-  void Shutdown();
-
 private:
   bool EnsureThreadPoolInitialized();
 
 private:
   nsCOMPtr<nsIThreadPool> mThreadPool;
 };
 
 }
--- a/content/media/webaudio/test/Makefile.in
+++ b/content/media/webaudio/test/Makefile.in
@@ -44,20 +44,22 @@ MOCHITEST_FILES := \
   test_audioBufferSourceNodeNullBuffer.html \
   test_badConnect.html \
   test_biquadFilterNode.html \
   test_channelMergerNode.html \
   test_channelMergerNodeWithVolume.html \
   test_channelSplitterNode.html \
   test_channelSplitterNodeWithVolume.html \
   test_convolverNode.html \
+  test_convolverNodeChannelCount.html \
   test_convolverNodeWithGain.html \
   test_convolverNode_mono_mono.html \
   test_currentTime.html \
   test_delayNode.html \
+  test_delayNodeAtMax.html \
   test_delayNodeSmallMaxDelay.html \
   test_delayNodeWithGain.html \
   test_dynamicsCompressorNode.html \
   test_gainNode.html \
   test_gainNodeInLoop.html \
   test_maxChannelCount.html \
   test_mediaDecoding.html \
   test_decodeMultichannel.html \
@@ -100,20 +102,13 @@ MOCHITEST_FILES := \
   noaudio.webm \
   audio.ogv \
   audio-expected.wav \
   audio-mono-expected.wav \
   audio-mono-expected-2.wav \
   audio-quad.wav \
   $(NULL)
 
-ifneq ($(MOZ_DEBUG)+$(MOZ_WIDGET_TOOLKIT),+gtk2) # bug 911777
-MOCHITEST_FILES += \
-  test_convolverNodeChannelCount.html \
-  test_delayNodeAtMax.html \
-  $(NULL)
-endif # bug 911777
-
 ifneq ($(OS_TARGET),Android) # bug 912474
 MOCHITEST_FILES += \
   test_pannerNodeChannelCount.html \
   $(NULL)
 endif
--- a/content/media/webaudio/test/test_maxChannelCount.html
+++ b/content/media/webaudio/test/test_maxChannelCount.html
@@ -5,16 +5,20 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="webaudio.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
+// Work around bug 911777
+SpecialPowers.forceGC();
+SpecialPowers.forceCC();
+
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(function() {
   var ac = new AudioContext();
   ok(ac.destination.maxChannelCount > 0, "We can query the maximum number of channels");
 
   var oac = new OfflineAudioContext(2, 1024, 48000);
   ok(oac.destination.maxChannelCount, 2, "This OfflineAudioContext should have 2 max channels.");
 
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -44,18 +44,17 @@ static RedirEntry kRedirMap[] = {
     { "buildconfig", "chrome://global/content/buildconfig.html",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
     { "license", "chrome://global/content/license.html",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
     { "neterror", "chrome://global/content/netError.xhtml",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
       nsIAboutModule::ALLOW_SCRIPT |
       nsIAboutModule::HIDE_FROM_ABOUTABOUT },
-    // aboutMemory.xhtml implements about:compartments
-    { "compartments", "chrome://global/content/aboutMemory.xhtml",
+    { "compartments", "chrome://global/content/aboutCompartments.xhtml",
       nsIAboutModule::ALLOW_SCRIPT },
     { "memory", "chrome://global/content/aboutMemory.xhtml",
       nsIAboutModule::ALLOW_SCRIPT },
     { "addons", "chrome://mozapps/content/extensions/extensions.xul",
       nsIAboutModule::ALLOW_SCRIPT },
     { "newaddon", "chrome://mozapps/content/extensions/newaddon.xul",
       nsIAboutModule::ALLOW_SCRIPT |
       nsIAboutModule::HIDE_FROM_ABOUTABOUT },
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -20,17 +20,17 @@
 #include "nsICookiePermission.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "BatteryManager.h"
-#include "PowerManager.h"
+#include "mozilla/dom/PowerManager.h"
 #include "nsIDOMWakeLock.h"
 #include "nsIPowerManagerService.h"
 #include "mozilla/dom/MobileMessageManager.h"
 #include "mozilla/Hal.h"
 #include "nsISiteSpecificUserAgent.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
@@ -71,18 +71,16 @@
 
 #include "nsIDOMGlobalPropertyInitializer.h"
 #include "nsJSUtils.h"
 
 #include "nsScriptNameSpaceManager.h"
 
 #include "mozilla/dom/NavigatorBinding.h"
 
-using namespace mozilla::dom::power;
-
 // This should not be in the namespace.
 DOMCI_DATA(Navigator, mozilla::dom::Navigator)
 
 namespace mozilla {
 namespace dom {
 
 static bool sDoNotTrackEnabled = false;
 static bool sVibratorEnabled   = false;
@@ -1095,17 +1093,17 @@ Navigator::GetBattery(ErrorResult& aRv)
 
     mBatteryManager = new battery::BatteryManager();
     mBatteryManager->Init(mWindow);
   }
 
   return mBatteryManager;
 }
 
-power::PowerManager*
+PowerManager*
 Navigator::GetMozPower(ErrorResult& aRv)
 {
   if (!mPowerManager) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
     mPowerManager = PowerManager::CreateInstance(mWindow);
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -87,19 +87,17 @@ class BluetoothManager;
 #endif // MOZ_B2G_BT
 
 #ifdef MOZ_B2G_RIL
 class CellBroadcast;
 class Telephony;
 class Voicemail;
 #endif
 
-namespace power {
 class PowerManager;
-} // namespace power
 
 namespace time {
 class TimeManager;
 } // namespace time
 
 namespace system {
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 class AudioChannelManager;
@@ -189,17 +187,17 @@ public:
   // The XPCOM GetVendor is OK
   // The XPCOM GetVendorSub is OK
   // The XPCOM GetProductSub is OK
   bool CookieEnabled();
   void GetBuildID(nsString& aBuildID, ErrorResult& aRv)
   {
     aRv = GetBuildID(aBuildID);
   }
-  power::PowerManager* GetMozPower(ErrorResult& aRv);
+  PowerManager* GetMozPower(ErrorResult& aRv);
   bool JavaEnabled(ErrorResult& aRv);
   bool TaintEnabled()
   {
     return false;
   }
   void AddIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
   void RemoveIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
   already_AddRefed<nsIDOMMozWakeLock> RequestWakeLock(const nsAString &aTopic,
@@ -317,17 +315,17 @@ private:
   nsRefPtr<nsMimeTypeArray> mMimeTypes;
   nsRefPtr<nsPluginArray> mPlugins;
   nsRefPtr<Geolocation> mGeolocation;
   nsRefPtr<DesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
 #ifdef MOZ_B2G_FM
   nsRefPtr<FMRadio> mFMRadio;
 #endif
-  nsRefPtr<power::PowerManager> mPowerManager;
+  nsRefPtr<PowerManager> mPowerManager;
   nsRefPtr<MobileMessageManager> mMobileMessageManager;
 #ifdef MOZ_B2G_RIL
   nsRefPtr<Telephony> mTelephony;
   nsRefPtr<Voicemail> mVoicemail;
 #endif
   nsRefPtr<network::Connection> mConnection;
 #ifdef MOZ_B2G_RIL
   nsRefPtr<network::MobileConnection> mMobileConnection;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -33,17 +33,16 @@
 #include "nsIComponentRegistrar.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIXPConnect.h"
 #include "nsIXPCSecurityManager.h"
 #include "xptcall.h"
 #include "nsTArray.h"
 #include "nsDOMEventTargetHelper.h"
-#include "nsIDOMHTMLCanvasElement.h"
 #include "nsContentList.h"
 #include "nsHTMLDocument.h"
 #include "nsDOMBlobBuilder.h"
 
 // General helper includes
 #include "nsGlobalWindow.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
@@ -418,19 +417,16 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // other SVG classes
   NS_DEFINE_CLASSINFO_DATA(SVGLength, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGNumber, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(MozCanvasPrintState, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
   NS_DEFINE_CLASSINFO_DATA(WindowUtils, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XSLTProcessor, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XPathExpression, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -1228,20 +1224,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(SVGLength, nsIDOMSVGLength)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGLength)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(SVGNumber, nsIDOMSVGNumber)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGNumber)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(MozCanvasPrintState, nsIDOMMozCanvasPrintState)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCanvasPrintState)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(XSLTProcessor, nsIXSLTProcessor)
     DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessor)
     DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(XPathExpression, nsIDOMXPathExpression)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathExpression)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSXPathExpression)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -60,19 +60,16 @@ DOMCI_CLASS(TreeColumn)
 
 DOMCI_CLASS(CSSMozDocumentRule)
 DOMCI_CLASS(CSSSupportsRule)
 
 // other SVG classes
 DOMCI_CLASS(SVGLength)
 DOMCI_CLASS(SVGNumber)
 
-// Canvas
-DOMCI_CLASS(MozCanvasPrintState)
-
 // WindowUtils
 DOMCI_CLASS(WindowUtils)
 
 // XSLTProcessor
 DOMCI_CLASS(XSLTProcessor)
 
 // DOM Level 3 XPath objects
 DOMCI_CLASS(XPathExpression)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1382,16 +1382,21 @@ nsGlobalWindow::CleanUp()
   }
 
   mInnerWindowHolder = nullptr;
   mArguments = nullptr;
   mDialogArguments = nullptr;
 
   CleanupCachedXBLHandlers(this);
 
+  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
+    mAudioContexts[i]->Shutdown();
+  }
+  mAudioContexts.Clear();
+
   if (mIdleTimer) {
     mIdleTimer->Cancel();
     mIdleTimer = nullptr;
   }
 
   DisableTimeChangeNotifications();
 }
 
@@ -1646,17 +1651,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)
 #endif
 
   // Traverse stuff from nsPIDOMWindow
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioContexts)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
@@ -1701,17 +1705,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
 #endif
 
   // Unlink stuff from nsPIDOMWindow
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioContexts)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
@@ -3254,16 +3257,22 @@ nsPIDOMWindow::AddAudioContext(AudioCont
 
   nsIDocShell* docShell = GetDocShell();
   if (docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline()) {
     aAudioContext->Mute();
   }
 }
 
 void
+nsPIDOMWindow::RemoveAudioContext(AudioContext* aAudioContext)
+{
+  mAudioContexts.RemoveElement(aAudioContext);
+}
+
+void
 nsPIDOMWindow::MuteAudioContexts()
 {
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
     if (!mAudioContexts[i]->IsOffline()) {
       mAudioContexts[i]->Mute();
     }
   }
 }
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -53,22 +53,25 @@ public:
    * @param aOptions an options object. You probably want to at least set
    *                 filename and line number. The principal is computed
    *                 internally, though 'originPrincipals' may be passed.
    * @param aCoerceToString if the return value is not JSVAL_VOID, convert it
    *                        to a string before returning.
    * @param aRetValue the result of executing the script.  Pass null if you
    *                  don't care about the result.  Note that asking for a
    *                  result will deoptimize your script somewhat in many cases.
+   * @param aOffThreadToken if specified, the result of compiling the script
+   *                        on another thread.
    */
   virtual nsresult EvaluateString(const nsAString& aScript,
                                   JS::Handle<JSObject*> aScopeObject,
                                   JS::CompileOptions& aOptions,
                                   bool aCoerceToString,
-                                  JS::Value* aRetValue) = 0;
+                                  JS::Value* aRetValue,
+                                  void **aOffThreadToken = nullptr) = 0;
 
   /**
    * Bind an already-compiled event handler function to the given
    * target.  Scripting languages with static scoping must re-bind the
    * scope chain for aHandler to begin (after the activation scope for
    * aHandler itself, typically) with aTarget's scope.
    *
    * The result of the bind operation is a new handler object, with
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -975,28 +975,30 @@ nsJSContext::GetCCRefcnt()
   return refcnt;
 }
 
 nsresult
 nsJSContext::EvaluateString(const nsAString& aScript,
                             JS::Handle<JSObject*> aScopeObject,
                             JS::CompileOptions& aCompileOptions,
                             bool aCoerceToString,
-                            JS::Value* aRetValue)
+                            JS::Value* aRetValue,
+                            void **aOffThreadToken)
 {
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
   if (!mScriptsEnabled) {
     return NS_OK;
   }
 
   AutoCxPusher pusher(mContext);
   nsJSUtils::EvaluateOptions evalOptions;
   evalOptions.setCoerceToString(aCoerceToString);
   return nsJSUtils::EvaluateString(mContext, aScript, aScopeObject,
-                                   aCompileOptions, evalOptions, aRetValue);
+                                   aCompileOptions, evalOptions, aRetValue,
+                                   aOffThreadToken);
 }
 
 #ifdef DEBUG
 bool
 AtomIsEventHandlerName(nsIAtom *aName)
 {
   const PRUnichar *name = aName->GetUTF16String();
 
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -39,17 +39,18 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext,
                                                          nsIScriptContext)
 
   virtual nsresult EvaluateString(const nsAString& aScript,
                                   JS::Handle<JSObject*> aScopeObject,
                                   JS::CompileOptions &aOptions,
                                   bool aCoerceToString,
-                                  JS::Value* aRetValue) MOZ_OVERRIDE;
+                                  JS::Value* aRetValue,
+                                  void **aOffThreadToken = nullptr) MOZ_OVERRIDE;
 
   virtual nsresult BindCompiledEventHandler(nsISupports *aTarget,
                                             JS::Handle<JSObject*> aScope,
                                             JS::Handle<JSObject*> aHandler,
                                             JS::MutableHandle<JSObject*> aBoundHandler) MOZ_OVERRIDE;
 
   virtual nsIScriptGlobalObject *GetGlobalObject() MOZ_OVERRIDE;
   inline nsIScriptGlobalObject *GetGlobalObjectRef() { return mGlobalObjectRef; }
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -218,17 +218,18 @@ public:
 };
 
 nsresult
 nsJSUtils::EvaluateString(JSContext* aCx,
                           const nsAString& aScript,
                           JS::Handle<JSObject*> aScopeObject,
                           JS::CompileOptions& aCompileOptions,
                           EvaluateOptions& aEvaluateOptions,
-                          JS::Value* aRetValue)
+                          JS::Value* aRetValue,
+                          void **aOffThreadToken)
 {
   PROFILER_LABEL("JS", "EvaluateString");
   MOZ_ASSERT_IF(aCompileOptions.versionSet,
                 aCompileOptions.version != JSVERSION_UNKNOWN);
   MOZ_ASSERT_IF(aEvaluateOptions.coerceToString, aRetValue);
   MOZ_ASSERT_IF(!aEvaluateOptions.reportUncaught, aRetValue);
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
 
@@ -260,19 +261,30 @@ nsJSUtils::EvaluateString(JSContext* aCx
   }
 
   // Scope the JSAutoCompartment so that we can later wrap the return value
   // into the caller's cx.
   {
     JSAutoCompartment ac(aCx, aScopeObject);
 
     JS::RootedObject rootedScope(aCx, aScopeObject);
-    ok = JS::Evaluate(aCx, rootedScope, aCompileOptions,
-                      PromiseFlatString(aScript).get(),
-                      aScript.Length(), aRetValue);
+    if (aOffThreadToken) {
+      JSScript *script = JS::FinishOffThreadScript(aCx, JS_GetRuntime(aCx), *aOffThreadToken);
+      *aOffThreadToken = nullptr; // Mark the token as having been finished.
+      if (script) {
+        ok = JS_ExecuteScript(aCx, rootedScope, script, aRetValue);
+      } else {
+        ok = false;
+      }
+    } else {
+      ok = JS::Evaluate(aCx, rootedScope, aCompileOptions,
+                        PromiseFlatString(aScript).get(),
+                        aScript.Length(), aRetValue);
+    }
+
     if (ok && aEvaluateOptions.coerceToString && !aRetValue->isUndefined()) {
       JSString* str = JS_ValueToString(aCx, *aRetValue);
       ok = !!str;
       *aRetValue = ok ? JS::StringValue(str) : JS::UndefinedValue();
     }
   }
 
   if (!ok) {
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -80,17 +80,18 @@ public:
     }
   };
 
   static nsresult EvaluateString(JSContext* aCx,
                                  const nsAString& aScript,
                                  JS::Handle<JSObject*> aScopeObject,
                                  JS::CompileOptions &aCompileOptions,
                                  EvaluateOptions& aEvaluateOptions,
-                                 JS::Value* aRetValue);
+                                 JS::Value* aRetValue,
+                                 void **aOffThreadToken = nullptr);
 
 };
 
 
 class nsDependentJSString : public nsDependentString
 {
 public:
   /**
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -607,16 +607,17 @@ public:
   /**
    * Like nsIDOMWindow::Open, except that we don't navigate to the given URL.
    */
   virtual nsresult
   OpenNoNavigate(const nsAString& aUrl, const nsAString& aName,
                  const nsAString& aOptions, nsIDOMWindow **_retval) = 0;
 
   void AddAudioContext(mozilla::dom::AudioContext* aAudioContext);
+  void RemoveAudioContext(mozilla::dom::AudioContext* aAudioContext);
   void MuteAudioContexts();
   void UnmuteAudioContexts();
 
   // Given an inner window, return its outer if the inner is the current inner.
   // Otherwise (argument null or not an inner or not current) return null.
   static nsPIDOMWindow* GetOuterFromCurrentInner(nsPIDOMWindow* aInner)
   {
     if (!aInner) {
@@ -703,17 +704,17 @@ protected:
   nsPIDOMWindow         *mInnerWindow;
   nsCOMPtr<nsPIDOMWindow> mOuterWindow;
 
   // the element within the document that is currently focused when this
   // window is active
   nsCOMPtr<nsIContent> mFocusedNode;
 
   // The AudioContexts created for the current document, if any.
-  nsTArray<nsRefPtr<mozilla::dom::AudioContext> > mAudioContexts;
+  nsTArray<mozilla::dom::AudioContext*> mAudioContexts; // Weak
 
   // A unique (as long as our 64-bit counter doesn't roll over) id for
   // 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;
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -711,17 +711,17 @@ ReportGhostWindowsEnumerator(nsUint64Has
   AppendWindowURI(window, path);
 
   nsresult rv = data->callback->Callback(
     /* process = */ EmptyCString(),
     path,
     nsIMemoryReporter::KIND_OTHER,
     nsIMemoryReporter::UNITS_COUNT,
     /* amount = */ 1,
-    /* desc = */ EmptyCString(),
+    /* description = */ NS_LITERAL_CSTRING("A ghost window."),
     data->closure);
 
   if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) {
     data->rv = rv;
   }
 
   return PL_DHASH_NEXT;
 }
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -747,16 +747,20 @@ DOMInterfaces = {
 'MouseEvent': {
     'nativeType': 'nsDOMMouseEvent',
 },
 
 'MouseScrollEvent': {
     'nativeType': 'nsDOMMouseScrollEvent',
 },
 
+'MozCanvasPrintState': {
+    'headerFile': 'mozilla/dom/HTMLCanvasElement.h',
+    'nativeType': 'mozilla::dom::HTMLCanvasPrintState',
+},
 
 'MozChannel': [
 {
     'nativeType': 'nsIChannel',
     'notflattened': True
 },
 {
     'workers': True,
@@ -766,17 +770,17 @@ DOMInterfaces = {
     'nativeType': 'mozilla::dom::CellBroadcast',
 },
 
 'MozNamedAttrMap': {
     'nativeType': 'nsDOMAttributeMap',
 },
 
 'MozPowerManager': {
-    'nativeType': 'mozilla::dom::power::PowerManager',
+    'nativeType': 'mozilla::dom::PowerManager',
 },
 
 'MozStkCommandEvent' : {
     'nativeType': 'mozilla::dom::icc::StkCommandEvent',
     'headerFile': 'StkCommandEvent.h',
 },
 
 'MozTimeManager': {
@@ -1765,18 +1769,16 @@ addExternalIface('Counter')
 addExternalIface('CSSRule')
 addExternalIface('DeviceAcceleration', headerFile='nsIDOMDeviceMotionEvent.h', notflattened=True)
 addExternalIface('DeviceRotationRate', headerFile='nsIDOMDeviceMotionEvent.h', notflattened=True)
 addExternalIface('mozIDOMApplication', nativeType='mozIDOMApplication', headerFile='nsIDOMApplicationRegistry.h')
 addExternalIface('CSSRuleList')
 addExternalIface('DOMStringList')
 addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel')
 addExternalIface('File')
-addExternalIface('FileCallback', nativeType='nsIFileCallback',
-                 headerFile='nsIDOMHTMLCanvasElement.h')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
 addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('LockedFile')
 addExternalIface('MediaList')
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozConnection', headerFile='nsIDOMConnection.h')
@@ -1806,18 +1808,16 @@ addExternalIface('nsIInputStreamCallback
 addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True)
 addExternalIface('nsISupports', nativeType='nsISupports')
 addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
 addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
 addExternalIface('OutputStream', nativeType='nsIOutputStream',
                  notflattened=True)
 addExternalIface('Principal', nativeType='nsIPrincipal',
                  headerFile='nsIPrincipal.h', notflattened=True)
-addExternalIface('PrintCallback', nativeType='nsIPrintCallback',
-                 headerFile='nsIDOMHTMLCanvasElement.h')
 addExternalIface('Selection', nativeType='nsISelection')
 addExternalIface('StackFrame', nativeType='nsIStackFrame',
                  headerFile='nsIException.h', notflattened=True)
 addExternalIface('StyleSheetList')
 addExternalIface('SVGLength')
 addExternalIface('SVGNumber')
 addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
                  notflattened=True)
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -99,16 +99,19 @@ private:
   {
     MOZ_ASSERT(aCallback && !mCallback);
     // Set mCallback before we hold, on the off chance that a GC could somehow
     // happen in there... (which would be pretty odd, granted).
     mCallback = aCallback;
     mozilla::HoldJSObjects(this);
   }
 
+  CallbackObject(const CallbackObject&) MOZ_DELETE;
+  CallbackObject& operator =(const CallbackObject&) MOZ_DELETE;
+
 protected:
   void DropCallback()
   {
     if (mCallback) {
       mCallback = nullptr;
       mozilla::DropJSObjects(this);
     }
   }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -10536,16 +10536,17 @@ struct PrototypeTraits;
 
         (includes, implincludes,
          declarations, unions) = UnionTypes(config.getDescriptors(),
                                             config.getDictionaries(),
                                             config.getCallbacks(),
                                             config)
         includes.add("mozilla/dom/OwningNonNull.h")
         includes.add("mozilla/dom/UnionMember.h")
+        includes.add("mozilla/dom/BindingDeclarations.h")
         implincludes.add("mozilla/dom/PrimitiveConversions.h")
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'], unions)
 
         curr = CGWrapper(curr, post='\n')
 
         namespaces = []
@@ -10738,22 +10739,25 @@ class CGEventMethod(CGNativeMember):
         self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
         self.args.append(Argument('ErrorResult&', 'aRv'))
         return constructorForNativeCaller + CGNativeMember.declare(self, cgClass)
 
     def define(self, cgClass):
         self.args = list(self.originalArgs)
         members = ""
         holdJS = ""
-        for m in self.descriptorProvider.interface.members:
-            if m.isAttr():
-                name = CGDictionary.makeMemberName(m.identifier.name)
-                members += "e->%s = %s.%s;\n" % (name, self.args[1].name, name)
-                if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
-                    holdJS = "mozilla::HoldJSObjects(e.get());\n"
+        iface = self.descriptorProvider.interface
+        while iface.identifier.name != "Event":
+            for m in self.descriptorProvider.getDescriptor(iface.identifier.name).interface.members:
+                if m.isAttr():
+                    name = CGDictionary.makeMemberName(m.identifier.name)
+                    members += "e->%s = %s.%s;\n" % (name, self.args[1].name, name)
+                    if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
+                        holdJS = "mozilla::HoldJSObjects(e.get());\n"
+            iface = iface.parent
 
         self.body = (
             "nsRefPtr<${nativeType}> e = new ${nativeType}(aOwner);\n"
             "bool trusted = e->Init(aOwner);\n"
             "e->InitEvent(${eventType}, ${eventInit}.mBubbles, ${eventInit}.mCancelable);\n"
             "${members}"
             "e->SetTrusted(trusted);\n"
             "${holdJS}"
@@ -10819,31 +10823,34 @@ class CGEventClass(CGBindingImplClass):
                     nativeType = "JS::Heap<JS::Value>"
                 elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
                     nativeType = "JS::Heap<JSObject*>"
                 members.append(ClassMember(CGDictionary.makeMemberName(m.identifier.name),
                                nativeType,
                                visibility="private",
                                body="body"))
 
+        parent = self.descriptor.interface.parent
+        self.parentType = self.descriptor.getDescriptor(parent.identifier.name).nativeType.split('::')[-1]
         baseDeclarations=(
             "public:\n"
             "  NS_DECL_ISUPPORTS_INHERITED\n"
-            "  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, nsDOMEvent)\n"
+            "  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, ${parentType})\n"
             "  virtual ~${nativeType}();\n"
             "protected:\n"
             "  ${nativeType}(mozilla::dom::EventTarget* aOwner);\n\n")
 
         baseDeclarations = string.Template(baseDeclarations).substitute(
             {
-              "nativeType": self.descriptor.nativeType.split('::')[-1]
+              "nativeType": self.descriptor.nativeType.split('::')[-1],
+              "parentType": self.parentType
             })
 
         CGClass.__init__(self, descriptor.nativeType.split('::')[-1],
-                         bases=[ClassBase("nsDOMEvent")],
+                         bases=[ClassBase(self.parentType)],
                          methods=self.methodDecls,
                          members=members,
                          extradeclarations=baseDeclarations)
 
     def getWrapObjectBody(self):
         return "return %sBinding::Wrap(aCx, aScope, this);" % self.descriptor.name
 
     def implTraverse(self):
@@ -10886,47 +10893,52 @@ class CGEventClass(CGBindingImplClass):
                 member = CGDictionary.makeMemberName(m.identifier.name);
                 if m.type.isAny():
                     dropJS += "  " + member + " = JS::UndefinedValue();\n"
                 elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
                     dropJS += "  " + member + " = nullptr;\n"
         if dropJS != "":
             dropJS += "  mozilla::DropJSObjects(this);\n"
         # Just override CGClass and do our own thing
+        nativeType = self.descriptor.nativeType.split('::')[-1]
+        ctorParams = ("aOwner, nullptr, nullptr" if self.parentType == "nsDOMEvent"
+                 else "aOwner")
         classImpl = """
 NS_IMPL_CYCLE_COLLECTION_CLASS(${nativeType})
 
-NS_IMPL_ADDREF_INHERITED(${nativeType}, nsDOMEvent)
-NS_IMPL_RELEASE_INHERITED(${nativeType}, nsDOMEvent)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, nsDOMEvent)
+NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
+NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, ${parentType})
 ${traverse}NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, nsDOMEvent)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, ${parentType})
 ${trace}NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, nsDOMEvent)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, ${parentType})
 ${unlink}NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(${nativeType})
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+NS_INTERFACE_MAP_END_INHERITING(${parentType})
 
 ${nativeType}::${nativeType}(mozilla::dom::EventTarget* aOwner)
-  : nsDOMEvent(aOwner, nullptr, nullptr)
+  : ${parentType}(${ctorParams})
 {
 }
 
 ${nativeType}::~${nativeType}()
 {
 ${dropJS}}
 
 """
         return string.Template(classImpl).substitute(
             { "ifaceName": self.descriptor.name,
-              "nativeType": self.descriptor.nativeType.split('::')[-1],
+              "nativeType": nativeType,
+              "ctorParams": ctorParams,
+              "parentType": self.parentType,
               "traverse": self.implTraverse(),
               "unlink": self.implUnlink(),
               "trace": self.implTrace(),
               "dropJS": dropJS}
             ) + CGBindingImplClass.define(self)
 
 
 class CGEventRoot(CGThing):
@@ -10937,19 +10949,21 @@ class CGEventRoot(CGThing):
         self.root = CGWrapper(CGEventClass(descriptor),
                               pre="\n", post="\n")
 
         self.root = CGNamespace.build(["mozilla", "dom"], self.root)
 
         self.root = CGList([CGClassForwardDeclare("JSContext", isStruct=True),
                             self.root], "\n")
 
+        parent = descriptor.interface.parent.identifier.name
+
         # Throw in our #includes
         self.root = CGHeaders([descriptor], [], [], [],
-                              [ "nsDOMEvent.h",
+                              [ config.getDescriptor(parent, False).headerFile,
                                 "mozilla/Attributes.h",
                                 "mozilla/ErrorResult.h" ,
                                 "mozilla/dom/%sBinding.h" % interfaceName,
                                 'mozilla/dom/BindingUtils.h',
                               ],
                               [ "%s.h" % interfaceName,
                                 "js/GCAPI.h",
                                 'mozilla/dom/Nullable.h',
--- a/dom/camera/test/Makefile.in
+++ b/dom/camera/test/Makefile.in
@@ -1,21 +1,8 @@
 #
 # 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/.
 
-DEPTH		= @DEPTH@
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-relativesrcdir  = @relativesrcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-DIRS = \
-  $(NULL)
-
 MOCHITEST_FILES = \
   test_camera.html \
   $(NULL)
-
-include $(topsrcdir)/config/rules.mk
--- a/dom/gamepad/GamepadService.cpp
+++ b/dom/gamepad/GamepadService.cpp
@@ -7,28 +7,29 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 
 #include "GamepadService.h"
 #include "Gamepad.h"
 #include "nsAutoPtr.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMDocument.h"
-#include "nsIDOMGamepadButtonEvent.h"
-#include "nsIDOMGamepadAxisMoveEvent.h"
-#include "nsIDOMGamepadEvent.h"
 #include "GeneratedEvents.h"
 #include "nsIDOMWindow.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsIServiceManager.h"
 #include "nsITimer.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Services.h"
 
+#include "mozilla/dom/GamepadAxisMoveEvent.h"
+#include "mozilla/dom/GamepadButtonEvent.h"
+#include "mozilla/dom/GamepadEvent.h"
+
 #include <cstddef>
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 const char* kGamepadEnabledPref = "dom.gamepad.enabled";
 const char* kGamepadEventsEnabledPref =
@@ -236,28 +237,29 @@ GamepadService::NewButtonEvent(uint32_t 
 }
 
 void
 GamepadService::FireButtonEvent(EventTarget* aTarget,
                                 Gamepad* aGamepad,
                                 uint32_t aButton,
                                 double aValue)
 {
-  nsCOMPtr<nsIDOMEvent> event;
-  bool defaultActionEnabled = true;
-  NS_NewDOMGamepadButtonEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
-  nsCOMPtr<nsIDOMGamepadButtonEvent> je = do_QueryInterface(event);
-  MOZ_ASSERT(je, "QI should not fail");
-
-
   nsString name = aValue == 1.0L ? NS_LITERAL_STRING("gamepadbuttondown") :
                                    NS_LITERAL_STRING("gamepadbuttonup");
-  je->InitGamepadButtonEvent(name, false, false, aGamepad, aButton);
-  je->SetTrusted(true);
+  GamepadButtonEventInitInitializer init;
+  init.mBubbles = false;
+  init.mCancelable = false;
+  init.mGamepad = aGamepad;
+  init.mButton = aButton;
+  nsRefPtr<GamepadButtonEvent> event =
+    GamepadButtonEvent::Constructor(aTarget, name, init);
 
+  event->SetTrusted(true);
+
+  bool defaultActionEnabled = true;
   aTarget->DispatchEvent(event, &defaultActionEnabled);
 }
 
 void
 GamepadService::NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue)
 {
   if (mShuttingDown || aIndex >= mGamepads.Length()) {
     return;
@@ -300,27 +302,30 @@ GamepadService::NewAxisMoveEvent(uint32_
 }
 
 void
 GamepadService::FireAxisMoveEvent(EventTarget* aTarget,
                                   Gamepad* aGamepad,
                                   uint32_t aAxis,
                                   double aValue)
 {
-  nsCOMPtr<nsIDOMEvent> event;
+  GamepadAxisMoveEventInitInitializer init;
+  init.mBubbles = false;
+  init.mCancelable = false;
+  init.mGamepad = aGamepad;
+  init.mAxis = aAxis;
+  init.mValue = aValue;
+  nsRefPtr<GamepadAxisMoveEvent> event =
+    GamepadAxisMoveEvent::Constructor(aTarget,
+                                      NS_LITERAL_STRING("gamepadaxismove"),
+                                      init);
+
+  event->SetTrusted(true);
+
   bool defaultActionEnabled = true;
-  NS_NewDOMGamepadAxisMoveEvent(getter_AddRefs(event), aTarget, nullptr,
-                                nullptr);
-  nsCOMPtr<nsIDOMGamepadAxisMoveEvent> je = do_QueryInterface(event);
-  MOZ_ASSERT(je, "QI should not fail");
-
-  je->InitGamepadAxisMoveEvent(NS_LITERAL_STRING("gamepadaxismove"),
-                               false, false, aGamepad, aAxis, aValue);
-  je->SetTrusted(true);
-
   aTarget->DispatchEvent(event, &defaultActionEnabled);
 }
 
 void
 GamepadService::NewConnectionEvent(uint32_t aIndex, bool aConnected)
 {
   if (mShuttingDown || aIndex >= mGamepads.Length()) {
     return;
@@ -376,27 +381,28 @@ GamepadService::NewConnectionEvent(uint3
   }
 }
 
 void
 GamepadService::FireConnectionEvent(EventTarget* aTarget,
                                     Gamepad* aGamepad,
                                     bool aConnected)
 {
-  nsCOMPtr<nsIDOMEvent> event;
-  bool defaultActionEnabled = true;
-  NS_NewDOMGamepadEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
-  nsCOMPtr<nsIDOMGamepadEvent> je = do_QueryInterface(event);
-  MOZ_ASSERT(je, "QI should not fail");
-
   nsString name = aConnected ? NS_LITERAL_STRING("gamepadconnected") :
                                NS_LITERAL_STRING("gamepaddisconnected");
-  je->InitGamepadEvent(name, false, false, aGamepad);
-  je->SetTrusted(true);
+  GamepadEventInitInitializer init;
+  init.mBubbles = false;
+  init.mCancelable = false;
+  init.mGamepad = aGamepad;
+  nsRefPtr<GamepadEvent> event =
+    GamepadEvent::Constructor(aTarget, name, init);
 
+  event->SetTrusted(true);
+
+  bool defaultActionEnabled = true;
   aTarget->DispatchEvent(event, &defaultActionEnabled);
 }
 
 void
 GamepadService::SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad)
 {
   if (mShuttingDown || !mEnabled || aIndex > mGamepads.Length()) {
     return;
--- a/dom/interfaces/events/moz.build
+++ b/dom/interfaces/events/moz.build
@@ -13,26 +13,22 @@ XPIDL_SOURCES += [
     'nsIDOMCompositionEvent.idl',
     'nsIDOMCustomEvent.idl',
     'nsIDOMDOMTransactionEvent.idl',
     'nsIDOMDataContainerEvent.idl',
     'nsIDOMDataTransfer.idl',
     'nsIDOMDeviceLightEvent.idl',
     'nsIDOMDeviceMotionEvent.idl',
     'nsIDOMDeviceOrientationEvent.idl',
-    'nsIDOMDeviceProximityEvent.idl',
     'nsIDOMDragEvent.idl',
     'nsIDOMElementReplaceEvent.idl',
     'nsIDOMEvent.idl',
     'nsIDOMEventListener.idl',
     'nsIDOMEventTarget.idl',
     'nsIDOMFocusEvent.idl',
-    'nsIDOMGamepadAxisMoveEvent.idl',
-    'nsIDOMGamepadButtonEvent.idl',
-    'nsIDOMGamepadEvent.idl',
     'nsIDOMHashChangeEvent.idl',
     'nsIDOMKeyEvent.idl',
     'nsIDOMMessageEvent.idl',
     'nsIDOMMouseEvent.idl',
     'nsIDOMMouseScrollEvent.idl',
     'nsIDOMMutationEvent.idl',
     'nsIDOMNSEvent.idl',
     'nsIDOMNotifyAudioAvailableEvent.idl',
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMDeviceProximityEvent.idl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMEvent.idl"
-
-[scriptable, builtinclass, uuid(86c7c396-9c2b-4d45-9c7c-b0dcda024105)]
-interface nsIDOMDeviceProximityEvent : nsIDOMEvent
-{
-  [noscript] void initDeviceProximityEvent(in DOMString eventTypeArg,
-                                           in boolean canBubbleArg,
-                                           in boolean cancelableArg,
-                                           in double value,
-                                           in double min,
-                                           in double max);
-  readonly attribute double value;
-  readonly attribute double min;
-  readonly attribute double max;
-};
-
-
-dictionary DeviceProximityEventInit : EventInit
-{
-   double value = Infinity;
-   double min = -Infinity;
-   double max = Infinity;
-};
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMGamepadAxisMoveEvent.idl
+++ /dev/null
@@ -1,33 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMGamepadEvent.idl"
-
-[builtinclass, scriptable, uuid(bd09eef8-8e07-4baf-8d39-4f92003dbca8)]
-interface nsIDOMGamepadAxisMoveEvent : nsIDOMGamepadEvent
-{
-  /**
-   * Index in gamepad.axes of the axis that was moved.
-   */
-  readonly attribute unsigned long axis;
-
-  /**
-   * Position of the axis in the range -1.0...1.0.
-   */
-  readonly attribute double value;
-
-  [noscript]
-  void initGamepadAxisMoveEvent(in DOMString typeArg,
-                                in boolean canBubbleArg,
-                                in boolean cancelableArg,
-                                in nsIDOMGamepad gamepad,
-                                in unsigned long axis,
-                                in double value);
-};
-
-dictionary GamepadAxisMoveEventInit : GamepadEventInit
-{
-  unsigned long axis;
-  double value;
-};
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMGamepadButtonEvent.idl
+++ /dev/null
@@ -1,26 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMGamepadEvent.idl"
-
-[builtinclass, scriptable, uuid(d75d4d2b-e7b4-4b93-ac35-2e70b57d9b28)]
-interface nsIDOMGamepadButtonEvent : nsIDOMGamepadEvent
-{
-  /**
-   * Index in gamepad.buttons of the button that was pressed or released.
-   */
-  readonly attribute unsigned long button;
-
-  [noscript]
-  void initGamepadButtonEvent(in DOMString typeArg,
-                              in boolean canBubbleArg,
-                              in boolean cancelableArg,
-                              in nsIDOMGamepad gamepad,
-                              in unsigned long button);
-};
-
-dictionary GamepadButtonEventInit : GamepadEventInit
-{
-  unsigned long button;
-};
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMGamepadEvent.idl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMEvent.idl"
-
-interface nsIDOMGamepad;
-
-[builtinclass, scriptable, uuid(93b048d6-2aef-46a9-b0f4-06d7f00d8ef2)]
-interface nsIDOMGamepadEvent : nsIDOMEvent
-{
-  /**
-   * The device that generated this event.
-   */
-  readonly attribute nsIDOMGamepad gamepad;
-
-  [noscript]
-  void initGamepadEvent(in DOMString typeArg,
-                        in boolean canBubbleArg,
-                        in boolean cancelableArg,
-                        in nsIDOMGamepad gamepad);
-};
-
-dictionary GamepadEventInit : EventInit
-{
-  nsIDOMGamepad gamepad;
-};
--- a/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl
@@ -15,37 +15,16 @@
  * @status UNDER_DEVELOPMENT
  */
 
 interface nsIDOMBlob;
 interface nsIDOMFile;
 interface nsIVariant;
 interface nsIInputStreamCallback;
 
-[scriptable, builtinclass, uuid(8d5fb8a0-7782-11e1-b0c4-0800200c9a67)]
-interface nsIDOMMozCanvasPrintState : nsISupports
-{
-  // A canvas rendering context.
-  readonly attribute nsISupports context;
-
-  // To be called when rendering to the context is done.
-  void done();
-};
-
-[scriptable, function, uuid(8d5fb8a0-7782-11e1-b0c4-0800200c9a66)]
-interface nsIPrintCallback : nsISupports
-{
-  void render(in nsIDOMMozCanvasPrintState ctx);
-};
-
-[scriptable, function, uuid(6e9ffb59-2067-4aef-a51c-65e65a3e0d81)]
-interface nsIFileCallback : nsISupports {
-  void receive(in nsIDOMBlob file);
-};
-
 [scriptable, uuid(8978d1c5-2981-4678-a1c3-b0b7bae04fbc)]
 interface nsIDOMHTMLCanvasElement : nsISupports
 {
   attribute unsigned long width;
   attribute unsigned long height;
   attribute boolean mozOpaque;
 
   // Valid calls are:
@@ -56,30 +35,18 @@ interface nsIDOMHTMLCanvasElement : nsIS
   DOMString toDataURL([optional] in DOMString type,
                       [optional] in jsval params);
 
   // Valid calls are
   // mozGetAsFile(name);              -- defaults to image/png
   // mozGetAsFile(name, type);        -- uses given type
   nsIDOMFile mozGetAsFile(in DOMString name, [optional] in DOMString type);
 
-  // Valid calls are:
-  //  toBlob();              -- defaults to image/png
-  //  toBlob(type);          -- uses given type
-  //  toBlob(type, params);  -- uses given type, and any valid parameters
-  [implicit_jscontext]
-  void toBlob(in nsIFileCallback callback,
-              [optional] in DOMString type,
-              [optional] in jsval params);
-
   // A Mozilla-only extension to get a canvas context backed by double-buffered
   // shared memory. Only privileged callers can call this.
   nsISupports MozGetIPCContext(in DOMString contextId);
 
   // A Mozilla-only extension that returns the canvas' image data as a data
   // stream in the desired image format.
   void mozFetchAsStream(in nsIInputStreamCallback callback,
                                         [optional] in DOMString type);
-
-  // A Mozilla-only callback that is called during the printing process.
-  attribute nsIPrintCallback mozPrintCallback;
 };
 
--- a/dom/power/PowerManager.cpp
+++ b/dom/power/PowerManager.cpp
@@ -1,30 +1,30 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/dom/PowerManager.h"
+
 #include "mozilla/Hal.h"
-#include "PowerManager.h"
 #include "WakeLock.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMWakeLockListener.h"
 #include "nsIDocument.h"
 #include "nsIPermissionManager.h"
 #include "nsIPowerManagerService.h"
 #include "nsIPrincipal.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsError.h"
 #include "mozilla/dom/MozPowerManagerBinding.h"
 
 namespace mozilla {
 namespace dom {
-namespace power {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PowerManager)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozWakeLockListener)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(PowerManager, mListeners, mWindow)
@@ -200,11 +200,10 @@ PowerManager::CreateInstance(nsPIDOMWind
   nsRefPtr<PowerManager> powerManager = new PowerManager();
   if (NS_FAILED(powerManager->Init(aWindow))) {
     powerManager = nullptr;
   }
 
   return powerManager.forget();
 }
 
-} // power
 } // dom
 } // mozilla
--- a/dom/power/PowerManager.h
+++ b/dom/power/PowerManager.h
@@ -14,17 +14,16 @@
 #include "nsWrapperCache.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 class ErrorResult;
 
 namespace dom {
-namespace power {
 
 class PowerManager MOZ_FINAL : public nsIDOMMozWakeLockListener
                              , public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PowerManager)
   NS_DECL_NSIDOMMOZWAKELOCKLISTENER
@@ -61,13 +60,12 @@ public:
   bool CpuSleepAllowed();
   void SetCpuSleepAllowed(bool aAllowed);
 
 private:
   nsCOMPtr<nsIDOMWindow> mWindow;
   nsTArray<nsCOMPtr<nsIDOMMozWakeLockListener> > mListeners;
 };
 
-} // namespace power
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_power_PowerManager_h
--- a/dom/power/WakeLock.cpp
+++ b/dom/power/WakeLock.cpp
@@ -9,17 +9,16 @@
 #include "mozilla/HalWakeLock.h"
 #include "nsDOMClassInfoID.h"
 #include "nsDOMEvent.h"
 #include "nsError.h"
 #include "nsIDocument.h"
 #include "nsIDOMWindow.h"
 #include "nsIDOMEvent.h"
 #include "nsPIDOMWindow.h"
-#include "PowerManager.h"
 
 DOMCI_DATA(MozWakeLock, mozilla::dom::power::WakeLock)
 
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace dom {
 namespace power {
--- a/dom/power/moz.build
+++ b/dom/power/moz.build
@@ -10,18 +10,21 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
 XPIDL_SOURCES += [
     'nsIDOMWakeLock.idl',
     'nsIDOMWakeLockListener.idl',
     'nsIPowerManagerService.idl',
 ]
 
 XPIDL_MODULE = 'dom_power'
 
+EXPORTS.mozilla.dom += [
+    'PowerManager.h',
+]
+
 EXPORTS.mozilla.dom.power += [
-    'PowerManager.h',
     'PowerManagerService.h',
     'Types.h',
 ]
 
 CPP_SOURCES += [
     'PowerManager.cpp',
     'PowerManagerService.cpp',
     'WakeLock.cpp',
--- a/dom/system/nsDeviceSensors.cpp
+++ b/dom/system/nsDeviceSensors.cpp
@@ -13,16 +13,17 @@
 #include "nsPIDOMWindow.h"
 #include "nsIDOMDocument.h"
 #include "nsIServiceManager.h"
 #include "nsIServiceManager.h"
 #include "GeneratedEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
 #include "nsIPermissionManager.h"
+#include "mozilla/dom/DeviceProximityEvent.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace hal;
 
 #undef near
 
 // also see sDefaultSensorHint in mobile/android/base/GeckoAppShell.java
@@ -252,27 +253,26 @@ nsDeviceSensors::FireDOMLightEvent(mozil
 }
 
 void
 nsDeviceSensors::FireDOMProximityEvent(mozilla::dom::EventTarget* aTarget,
                                        double aValue,
                                        double aMin,
                                        double aMax)
 {
-  nsCOMPtr<nsIDOMEvent> event;
-  NS_NewDOMDeviceProximityEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
-  nsCOMPtr<nsIDOMDeviceProximityEvent> oe = do_QueryInterface(event);
-
-  oe->InitDeviceProximityEvent(NS_LITERAL_STRING("deviceproximity"),
-                               true,
-                               false,
-                               aValue,
-                               aMin,
-                               aMax);
-
+  DeviceProximityEventInitInitializer init;
+  init.mBubbles = true;
+  init.mCancelable = false;
+  init.mValue = aValue;
+  init.mMin = aMin;
+  init.mMax = aMax;
+  nsRefPtr<DeviceProximityEvent> event =
+    DeviceProximityEvent::Constructor(aTarget,
+                                      NS_LITERAL_STRING("deviceproximity"),
+                                      init);
   event->SetTrusted(true);
 
   bool defaultActionEnabled;
   aTarget->DispatchEvent(event, &defaultActionEnabled);
 
   // Some proximity sensors only support a binary near or
   // far measurement. In this case, the sensor should report
   // its maximum range value in the far state and a lesser
--- a/dom/system/nsDeviceSensors.h
+++ b/dom/system/nsDeviceSensors.h
@@ -8,17 +8,16 @@
 #include "nsIDeviceSensors.h"
 #include "nsIDOMDeviceMotionEvent.h"
 #include "nsCOMArray.h"
 #include "nsTArray.h"
 #include "nsCOMPtr.h"
 #include "nsITimer.h"
 #include "nsIDOMDeviceLightEvent.h"
 #include "nsIDOMDeviceOrientationEvent.h"
-#include "nsIDOMDeviceProximityEvent.h"
 #include "nsIDOMUserProximityEvent.h"
 #include "nsIDOMDeviceMotionEvent.h"
 #include "nsDOMDeviceMotionEvent.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/HalSensor.h"
 #include "nsDataHashtable.h"
 
 #define NS_DEVICE_SENSORS_CID \
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -310,17 +310,16 @@ var interfaceNamesInGlobalScope =
     "MessageEvent",
     "MimeType",
     "MimeTypeArray",
     "ModalContentWindow",
     "MouseEvent",
     "MouseScrollEvent",
     {name: "MozActivity", b2g: true},
     "MozApplicationEvent",
-    "MozCanvasPrintState",
     {name: "MozCellBroadcast", b2g: true},
     {name: "MozCellBroadcastEvent", b2g: true},
     "MozConnection",
     "mozContact",
     "MozContactChangeEvent",
     "MozCSSKeyframeRule",
     "MozCSSKeyframesRule",
     {name: "MozEmergencyCbModeEvent", b2g: true},
--- a/dom/webidl/DeviceProximityEvent.webidl
+++ b/dom/webidl/DeviceProximityEvent.webidl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-[Constructor(DOMString type, optional DeviceProximityEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
+[Constructor(DOMString type, optional DeviceProximityEventInit eventInitDict)]
 interface DeviceProximityEvent : Event
 {
   readonly attribute double value;
   readonly attribute double min;
   readonly attribute double max;
 };
 
 dictionary DeviceProximityEventInit : EventInit
--- a/dom/webidl/GamepadAxisMoveEvent.webidl
+++ b/dom/webidl/GamepadAxisMoveEvent.webidl
@@ -1,17 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 [Pref="dom.gamepad.non_standard_events.enabled",
- Constructor(DOMString type, optional GamepadAxisMoveEventInit eventInitDict),
- HeaderFile="GeneratedEventClasses.h"]
+ Constructor(DOMString type, optional GamepadAxisMoveEventInit eventInitDict)]
 interface GamepadAxisMoveEvent : GamepadEvent
 {
   readonly attribute unsigned long axis;
   readonly attribute double value;
 };
 
 dictionary GamepadAxisMoveEventInit : GamepadEventInit
 {
--- a/dom/webidl/GamepadButtonEvent.webidl
+++ b/dom/webidl/GamepadButtonEvent.webidl
@@ -1,17 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 [Pref="dom.gamepad.non_standard_events.enabled",
- Constructor(DOMString type, optional GamepadButtonEventInit eventInitDict),
- HeaderFile="GeneratedEventClasses.h"]
+ Constructor(DOMString type, optional GamepadButtonEventInit eventInitDict)]
 interface GamepadButtonEvent : GamepadEvent
 {
   readonly attribute unsigned long button;
 };
 
 dictionary GamepadButtonEventInit : GamepadEventInit
 {
   unsigned long button = 0;
--- a/dom/webidl/GamepadEvent.webidl
+++ b/dom/webidl/GamepadEvent.webidl
@@ -1,17 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 [Pref="dom.gamepad.enabled",
- Constructor(DOMString type, optional GamepadEventInit eventInitDict),
- HeaderFile="GeneratedEventClasses.h"]
+ Constructor(DOMString type, optional GamepadEventInit eventInitDict)]
 interface GamepadEvent : Event
 {
   readonly attribute Gamepad? gamepad;
 };
 
 dictionary GamepadEventInit : EventInit
 {
   Gamepad? gamepad = null;
--- a/dom/webidl/HTMLCanvasElement.webidl
+++ b/dom/webidl/HTMLCanvasElement.webidl
@@ -6,20 +6,18 @@
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/#the-canvas-element
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
 interface Blob;
-interface FileCallback;
 interface nsIInputStreamCallback;
 interface nsISupports;
-interface PrintCallback;
 interface Variant;
 
 interface HTMLCanvasElement : HTMLElement {
   [Pure, SetterThrows]
            attribute unsigned long width;
   [Pure, SetterThrows]
            attribute unsigned long height;
 
@@ -42,8 +40,22 @@ partial interface HTMLCanvasElement {
   [Throws]
   File mozGetAsFile(DOMString name, optional DOMString? type = null);
   [ChromeOnly, Throws]
   nsISupports? MozGetIPCContext(DOMString contextId);
   [ChromeOnly]
   void mozFetchAsStream(nsIInputStreamCallback callback, optional DOMString? type = null);
            attribute PrintCallback? mozPrintCallback;
 };
+
+[ChromeOnly]
+interface MozCanvasPrintState
+{
+  // A canvas rendering context.
+  readonly attribute nsISupports context;
+
+  // To be called when rendering to the context is done.
+  void done();
+};
+
+callback PrintCallback = void(MozCanvasPrintState ctx);
+
+callback FileCallback = void(Blob file);
--- a/dom/webidl/MutationObserver.webidl
+++ b/dom/webidl/MutationObserver.webidl
@@ -22,21 +22,31 @@ interface MutationRecord {
 };
 
 [Constructor(MutationCallback mutationCallback)]
 interface MutationObserver {
   [Throws]
   void observe(Node target, optional MutationObserverInit options);
   void disconnect();
   sequence<MutationRecord> takeRecords();
+
+  [ChromeOnly]
+  sequence<MutationObservingInfo?> getObservingInfo();
+  [ChromeOnly]
+  readonly attribute MutationCallback mutationCallback;
 };
 
 callback MutationCallback = void (sequence<MutationRecord> mutations, MutationObserver observer);
 
 dictionary MutationObserverInit {
   boolean childList = false;
   boolean attributes = false;
   boolean characterData = false;
   boolean subtree = false;
   boolean attributeOldValue = false;
   boolean characterDataOldValue = false;
   sequence<DOMString> attributeFilter;
 };
+
+dictionary MutationObservingInfo : MutationObserverInit
+{
+  Node? observedNode = null;
+};
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -99,9 +99,11 @@ interface Node : EventTarget {
   [Throws, Func="IsChromeOrXBL"]
   any setUserData(DOMString key, any data, UserDataHandler? handler);
   [Throws, Func="IsChromeOrXBL"]
   any getUserData(DOMString key);
   [ChromeOnly]
   readonly attribute Principal nodePrincipal;
   [ChromeOnly]
   readonly attribute URI? baseURIObject;
+  [ChromeOnly]
+  sequence<MutationObserver> getBoundMutationObservers();
 };
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -455,17 +455,16 @@ if CONFIG['MOZ_B2G_RIL']:
         'MozVoicemail.webidl',
     ]
 
 WEBIDL_FILES += [
     'CloseEvent.webidl',
     'CustomEvent.webidl',
     'DeviceLightEvent.webidl',
     'DeviceOrientationEvent.webidl',
-    'DeviceProximityEvent.webidl',
     'DeviceStorageChangeEvent.webidl',
     'DOMTransactionEvent.webidl',
     'ElementReplaceEvent.webidl',
     'HashChangeEvent.webidl',
     'MozApplicationEvent.webidl',
     'MozContactChangeEvent.webidl',
     'MozMmsEvent.webidl',
     'MozSettingsEvent.webidl',
@@ -502,23 +501,16 @@ if CONFIG['MOZ_B2G_RIL']:
         'MozEmergencyCbModeEvent.webidl',
         'MozOtaStatusEvent.webidl',
         'MozVoicemailEvent.webidl',
         'MozWifiConnectionInfoEvent.webidl',
         'MozWifiStatusChangeEvent.webidl',
         'USSDReceivedEvent.webidl',
     ]
 
-if CONFIG['MOZ_GAMEPAD']:
-    WEBIDL_FILES += [
-        'GamepadAxisMoveEvent.webidl',
-        'GamepadButtonEvent.webidl',
-        'GamepadEvent.webidl',
-    ]
-
 if CONFIG['MOZ_WEBSPEECH']:
     WEBIDL_FILES += [
         'SpeechRecognitionError.webidl',
         'SpeechRecognitionEvent.webidl',
     ]
 
 if CONFIG['MOZ_B2G_FM']:
     WEBIDL_FILES += [
@@ -537,9 +529,19 @@ if CONFIG['ENABLE_TESTS']:
 
 if CONFIG['MOZ_B2G']:
     WEBIDL_FILES += [
         'InputMethod.webidl',
     ]
 
 GENERATED_EVENTS_WEBIDL_FILES = [
     'BlobEvent.webidl',
+    'DeviceProximityEvent.webidl',
 ]
+
+if CONFIG['MOZ_GAMEPAD']:
+    GENERATED_EVENTS_WEBIDL_FILES += [
+        'GamepadAxisMoveEvent.webidl',
+        'GamepadButtonEvent.webidl',
+        'GamepadEvent.webidl',
+    ]
+
+
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -22,16 +22,20 @@
 #include "cairo-quartz.h"
 #include <ApplicationServices/ApplicationServices.h>
 #endif
 
 #ifdef CAIRO_HAS_XLIB_SURFACE
 #include "cairo-xlib.h"
 #endif
 
+#ifdef CAIRO_HAS_WIN32_SURFACE
+#include "cairo-win32.h"
+#endif
+
 #include <algorithm>
 
 namespace mozilla {
 namespace gfx {
 
 namespace {
 
 // An RAII class to prepare to draw a context and optional path. Saves and
@@ -101,16 +105,25 @@ GetCairoSurfaceSize(cairo_surface_t* sur
 
       // It's valid to call these CGBitmapContext functions on non-bitmap
       // contexts; they'll just return 0 in that case.
       size.width = CGBitmapContextGetWidth(cgc);
       size.height = CGBitmapContextGetWidth(cgc);
       return true;
     }
 #endif
+#ifdef CAIRO_HAS_WIN32_SURFACE
+    case CAIRO_SURFACE_TYPE_WIN32:
+    case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
+    {
+      size.width = cairo_win32_surface_get_width(surface);
+      size.height = cairo_win32_surface_get_height(surface);
+      return true;
+    }
+#endif
 
     default:
       return false;
   }
 }
 
 static bool
 PatternIsCompatible(const Pattern& aPattern)
@@ -437,30 +450,38 @@ DrawTargetCairo::DrawSurface(SourceSurfa
   cairo_surface_destroy(surf);
 
   cairo_pattern_set_matrix(pat, &src_mat);
   cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(aSurfOptions.mFilter));
   cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD);
 
   cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode));
 
+  double clipX1, clipY1, clipX2, clipY2;
+  cairo_clip_extents(mContext, &clipX1, &clipY1, &clipX2, &clipY2);
+  Rect clip(clipX1, clipY1, clipX2 - clipX1, clipY2 - clipY1); // Narrowing of doubles to floats
+  // If the destination rect covers the entire clipped area, then unbounded and bounded
+  // operations are identical, and we don't need to push a group.
+  bool needsGroup = !IsOperatorBoundByMask(aOptions.mCompositionOp) &&
+                    !aDest.Contains(clip);
+
   cairo_translate(mContext, aDest.X(), aDest.Y());
 
-  if (IsOperatorBoundByMask(aOptions.mCompositionOp)) {
-    cairo_new_path(mContext);
-    cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height());
-    cairo_clip(mContext);
-    cairo_set_source(mContext, pat);
-  } else {
+  if (needsGroup) {
     cairo_push_group(mContext);
       cairo_new_path(mContext);
       cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height());
       cairo_set_source(mContext, pat);
       cairo_fill(mContext);
     cairo_pop_group_to_source(mContext);
+  } else {
+    cairo_new_path(mContext);
+    cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height());
+    cairo_clip(mContext);
+    cairo_set_source(mContext, pat);
   }
 
   cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp));
 
   cairo_paint_with_alpha(mContext, aOptions.mAlpha);
 
   cairo_pattern_destroy(pat);
 }
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -38,17 +38,17 @@ typedef void *EGLNativeWindowType;
 // We only need to explicitly dlopen egltrace
 // on android as we can use LD_PRELOAD or other tricks
 // on other platforms. We look for it in /data/local
 // as that's writeable by all users
 //
 // This should really go in GLLibraryEGL.cpp but we currently reference
 // APITRACE_LIB in GLContextProviderEGL.cpp. Further refactoring
 // will come in subsequent patches on Bug 732865
-#define APITRACE_LIB "/data/local/egltrace.so"
+#define APITRACE_LIB "/data/local/tmp/egltrace.so"
 
 #ifdef MOZ_WIDGET_ANDROID
 
 #endif // MOZ_WIDGET_ANDROID
 #endif // ANDROID
 #endif
 
 #if defined(MOZ_X11)
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -415,14 +415,22 @@ public:
    * This can only be used from the compositor thread!
    */
   static LayersBackend GetBackend();
 
 protected:
   uint32_t mCompositorID;
   static LayersBackend sBackend;
   DiagnosticTypes mDiagnosticTypes;
+
+  /**
+   * We keep track of the total number of pixels filled as we composite the
+   * current frame. This value is an approximation and is not accurate,
+   * especially in the presence of transforms.
+   */
+  size_t mPixelsPerFrame;
+  size_t mPixelsFilled;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_COMPOSITOR_H */
--- a/gfx/layers/ThebesLayerBuffer.cpp
+++ b/gfx/layers/ThebesLayerBuffer.cpp
@@ -156,16 +156,17 @@ RotatedBuffer::DrawBufferQuadrant(gfxCon
  * the bottom side of the buffer (which is drawn on the top side of
  * mBufferRect).
  */
 void
 RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
                                   XSide aXSide, YSide aYSide,
                                   ContextSource aSource,
                                   float aOpacity,
+                                  gfx::CompositionOp aOperator,
                                   gfx::SourceSurface* aMask,
                                   const gfx::Matrix* aMaskTransform) const
 {
   // The rectangle that we're going to fill. Basically we're going to
   // render the buffer at mBufferRect + quadrantTranslation to get the
   // pixels in the right place, but we're only going to paint within
   // mBufferRect
   nsIntRect quadrantRect = GetQuadrantRectangle(aXSide, aYSide);
@@ -188,24 +189,36 @@ RotatedBuffer::DrawBufferQuadrant(gfx::D
   transform.Translate(quadrantTranslation.x, quadrantTranslation.y);
 
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
   SurfacePattern source(snapshot, EXTEND_CLAMP, transform, FILTER_POINT);
 #else
   SurfacePattern source(snapshot, EXTEND_CLAMP, transform);
 #endif
 
+  if (aOperator == OP_SOURCE) {
+    // OP_SOURCE is unbounded in Azure, and we really don't want that behaviour here.
+    // We also can't do a ClearRect+FillRect since we need the drawing to happen
+    // as an atomic operation (to prevent flickering).
+    aTarget->PushClipRect(gfx::Rect(fillRect.x, fillRect.y,
+                                    fillRect.width, fillRect.height));
+  }
+
   if (aMask) {
     SurfacePattern mask(aMask, EXTEND_CLAMP, *aMaskTransform);
 
-    aTarget->Mask(source, mask, DrawOptions(aOpacity));
+    aTarget->Mask(source, mask, DrawOptions(aOpacity, aOperator));
   } else {
     aTarget->FillRect(gfx::Rect(fillRect.x, fillRect.y,
                                 fillRect.width, fillRect.height),
-                      source, DrawOptions(aOpacity));
+                      source, DrawOptions(aOpacity, aOperator));
+  }
+
+  if (aOperator == OP_SOURCE) {
+    aTarget->PopClip();
   }
 
   aTarget->Flush();
 }
 
 void
 RotatedBuffer::DrawBufferWithRotation(gfxContext* aTarget, ContextSource aSource,
                                       float aOpacity,
@@ -219,27 +232,28 @@ RotatedBuffer::DrawBufferWithRotation(gf
   DrawBufferQuadrant(aTarget, RIGHT, TOP, aSource, aOpacity, aMask, aMaskTransform);
   DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
   DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
 }
 
 void
 RotatedBuffer::DrawBufferWithRotation(gfx::DrawTarget *aTarget, ContextSource aSource,
                                       float aOpacity,
+                                      gfx::CompositionOp aOperator,
                                       gfx::SourceSurface* aMask,
                                       const gfx::Matrix* aMaskTransform) const
 {
   PROFILER_LABEL("RotatedBuffer", "DrawBufferWithRotation");
   // See above, in Azure Repeat should always be a safe, even faster choice
   // though! Particularly on D2D Repeat should be a lot faster, need to look
   // into that. TODO[Bas]
-  DrawBufferQuadrant(aTarget, LEFT, TOP, aSource, aOpacity, aMask, aMaskTransform);
-  DrawBufferQuadrant(aTarget, RIGHT, TOP, aSource, aOpacity, aMask, aMaskTransform);
-  DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
-  DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
+  DrawBufferQuadrant(aTarget, LEFT, TOP, aSource, aOpacity, aOperator, aMask, aMaskTransform);
+  DrawBufferQuadrant(aTarget, RIGHT, TOP, aSource, aOpacity, aOperator, aMask, aMaskTransform);
+  DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aSource, aOpacity, aOperator, aMask, aMaskTransform);
+  DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aOperator,aMask, aMaskTransform);
 }
 
 /* static */ bool
 ThebesLayerBuffer::IsClippingCheap(gfxContext* aTarget, const nsIntRegion& aRegion)
 {
   // Assume clipping is cheap if the context just has an integer
   // translation, and the visible region is simple.
   return !aTarget->CurrentMatrix().HasNonIntegerTranslation() &&
@@ -301,17 +315,18 @@ ThebesLayerBuffer::DrawTo(ThebesLayer* a
       mask = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aMask);
     }
 
     Matrix maskTransform;
     if (aMaskTransform) {
       maskTransform = ToMatrix(*aMaskTransform);
     }
 
-    DrawBufferWithRotation(dt, BUFFER_BLACK, aOpacity, mask, &maskTransform);
+    CompositionOp op = CompositionOpForOp(aTarget->CurrentOperator());
+    DrawBufferWithRotation(dt, BUFFER_BLACK, aOpacity, op, mask, &maskTransform);
     if (clipped) {
       dt->PopClip();
     }
   }
 }
 
 static void
 FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
@@ -419,16 +434,20 @@ ThebesLayerBuffer::IsAzureBuffer()
 {
   MOZ_ASSERT(!(mDTBuffer && mBuffer), "Trying to use Azure and Thebes in the same buffer?");
   if (mDTBuffer) {
     return true;
   }
   if (mBuffer) {
     return false;
   }
+  if (mBufferProvider) {
+    return gfxPlatform::GetPlatform()->SupportsAzureContentForType(
+      mBufferProvider->BackendType());
+  }
   return SupportsAzureContent();
 }
 
 void
 ThebesLayerBuffer::EnsureBuffer()
 {
   if ((!mBuffer && !mDTBuffer) && mBufferProvider) {
     if (IsAzureBuffer()) {
@@ -646,46 +665,38 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
           result.mDidSelfCopy = true;
           // Don't set destBuffer; we special-case self-copies, and
           // just did the necessary work above.
           mBufferRect = destBufferRect;
         } else {
           // We can't do a real self-copy because the buffer is rotated.
           // So allocate a new buffer for the destination.
           destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
-          if (IsAzureBuffer()) {
-            MOZ_ASSERT(!mBuffer);
-            destDTBuffer = CreateDTBuffer(contentType, destBufferRect, bufferFlags, &destDTBufferOnWhite);
-          } else {
-            MOZ_ASSERT(!mDTBuffer);
-            destBuffer = CreateBuffer(contentType, destBufferRect, bufferFlags, getter_AddRefs(destBufferOnWhite));
-          }
+          CreateBuffer(contentType, destBufferRect, bufferFlags,
+                       getter_AddRefs(destBuffer), getter_AddRefs(destBufferOnWhite),
+                       &destDTBuffer, &destDTBufferOnWhite);
           if (!destBuffer && !destDTBuffer)
             return result;
         }
       } else {
         mBufferRect = destBufferRect;
         mBufferRotation = newRotation;
       }
     } else {
       // No pixels are going to be kept. The whole visible region
       // will be redrawn, so we don't need to copy anything, so we don't
       // set destBuffer.
       mBufferRect = destBufferRect;
       mBufferRotation = nsIntPoint(0,0);
     }
   } else {
     // The buffer's not big enough, so allocate a new one
-    if (IsAzureBuffer()) {
-      MOZ_ASSERT(!mBuffer);
-      destDTBuffer = CreateDTBuffer(contentType, destBufferRect, bufferFlags, &destDTBufferOnWhite);
-    } else {
-      MOZ_ASSERT(!mDTBuffer);
-      destBuffer = CreateBuffer(contentType, destBufferRect, bufferFlags, getter_AddRefs(destBufferOnWhite));
-    }
+    CreateBuffer(contentType, destBufferRect, bufferFlags,
+                 getter_AddRefs(destBuffer), getter_AddRefs(destBufferOnWhite),
+                 &destDTBuffer, &destDTBufferOnWhite);
     if (!destBuffer && !destDTBuffer)
       return result;
   }
 
   NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || destBufferRect == neededRegion.GetBounds(),
                "If we're resampling, we need to validate the entire buffer");
 
   // If we have no buffered data already, then destBuffer will be a fresh buffer
@@ -722,25 +733,25 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
     if (!isClear && (mode != Layer::SURFACE_COMPONENT_ALPHA || HaveBufferOnWhite())) {
       // Copy the bits
       nsIntPoint offset = -destBufferRect.TopLeft();
       Matrix mat;
       mat.Translate(offset.x, offset.y);
       destDTBuffer->SetTransform(mat);
       EnsureBuffer();
       MOZ_ASSERT(mDTBuffer, "Have we got a Thebes buffer for some reason?");
-      DrawBufferWithRotation(destDTBuffer, BUFFER_BLACK);
+      DrawBufferWithRotation(destDTBuffer, BUFFER_BLACK, 1.0, OP_SOURCE);
       destDTBuffer->SetTransform(Matrix());
 
       if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
         NS_ASSERTION(destDTBufferOnWhite, "Must have a white buffer!");
         destDTBufferOnWhite->SetTransform(mat);
         EnsureBufferOnWhite();
         MOZ_ASSERT(destDTBufferOnWhite, "Have we got a Thebes buffer for some reason?");
-        DrawBufferWithRotation(destDTBufferOnWhite, BUFFER_WHITE);
+        DrawBufferWithRotation(destDTBufferOnWhite, BUFFER_WHITE, 1.0, OP_SOURCE);
         destDTBufferOnWhite->SetTransform(Matrix());
       }
     }
 
     mDTBuffer = destDTBuffer.forget();
     mBuffer = nullptr;
     mDTBufferOnWhite = destDTBufferOnWhite.forget();
     mBufferOnWhite = nullptr;
--- a/gfx/layers/ThebesLayerBuffer.h
+++ b/gfx/layers/ThebesLayerBuffer.h
@@ -82,16 +82,17 @@ public:
   };
   void DrawBufferWithRotation(gfxContext* aTarget, ContextSource aSource,
                               float aOpacity = 1.0,
                               gfxASurface* aMask = nullptr,
                               const gfxMatrix* aMaskTransform = nullptr) const;
 
   void DrawBufferWithRotation(gfx::DrawTarget* aTarget, ContextSource aSource,
                               float aOpacity = 1.0,
+                              gfx::CompositionOp aOperator = gfx::OP_OVER,
                               gfx::SourceSurface* aMask = nullptr,
                               const gfx::Matrix* aMaskTransform = nullptr) const;
 
   /**
    * |BufferRect()| is the rect of device pixels that this
    * ThebesLayerBuffer covers.  That is what DrawBufferWithRotation()
    * will paint when it's called.
    */
@@ -119,16 +120,17 @@ protected:
   void DrawBufferQuadrant(gfxContext* aTarget, XSide aXSide, YSide aYSide,
                           ContextSource aSource,
                           float aOpacity,
                           gfxASurface* aMask,
                           const gfxMatrix* aMaskTransform) const;
   void DrawBufferQuadrant(gfx::DrawTarget* aTarget, XSide aXSide, YSide aYSide,
                           ContextSource aSource,
                           float aOpacity,
+                          gfx::CompositionOp aOperator,
                           gfx::SourceSurface* aMask,
                           const gfx::Matrix* aMaskTransform) const;
 
   nsRefPtr<gfxASurface> mBuffer;
   nsRefPtr<gfxASurface> mBufferOnWhite;
   RefPtr<gfx::DrawTarget> mDTBuffer;
   RefPtr<gfx::DrawTarget> mDTBufferOnWhite;
   /** The area of the ThebesLayer that is covered by the buffer as a whole */
@@ -240,22 +242,24 @@ public:
     ALLOW_REPEAT = 0x01,
     BUFFER_COMPONENT_ALPHA = 0x02 // Dual buffers should be created for drawing with
                                   // component alpha.
   };
   /**
    * Return a new surface of |aSize| and |aType|.
    * @param aFlags if ALLOW_REPEAT is set, then the buffer should be configured
    * to allow repeat-mode, otherwise it should be in pad (clamp) mode
+   * If the created buffer supports azure content, then the result(s) will
+   * be returned in aBlackDT/aWhiteDT, otherwise aBlackSurface/aWhiteSurface
+   * will be used.
    */
-  virtual already_AddRefed<gfxASurface>
-  CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, gfxASurface** aWhiteSurface) = 0;
-  virtual TemporaryRef<gfx::DrawTarget>
-  CreateDTBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, RefPtr<gfx::DrawTarget>* aWhiteDT)
-  { NS_RUNTIMEABORT("CreateDTBuffer not implemented on this platform!"); return nullptr; }
+  virtual void
+  CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags,
+               gfxASurface** aBlackSurface, gfxASurface** aWhiteSurface,
+               RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) = 0;
   virtual bool SupportsAzureContent() const 
   { return false; }
 
   /**
    * Get the underlying buffer, if any. This is useful because we can pass
    * in the buffer as the default "reference surface" if there is one.
    * Don't use it for anything else!
    */
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -72,52 +72,51 @@ ContentClient::CreateContentClient(Compo
 
 }
 
 ContentClientBasic::ContentClientBasic(CompositableForwarder* aForwarder,
                                        BasicLayerManager* aManager)
 : ContentClient(aForwarder), ThebesLayerBuffer(ContainsVisibleBounds), mManager(aManager)
 {}
 
-already_AddRefed<gfxASurface>
+void
 ContentClientBasic::CreateBuffer(ContentType aType,
                                  const nsIntRect& aRect,
                                  uint32_t aFlags,
-                                 gfxASurface**)
+                                 gfxASurface** aBlackSurface,
+                                 gfxASurface** aWhiteSurface,
+                                 RefPtr<gfx::DrawTarget>* aBlackDT,
+                                 RefPtr<gfx::DrawTarget>* aWhiteDT)
 {
   MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
+  if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
+    gfxASurface::gfxImageFormat format =
+      gfxPlatform::GetPlatform()->OptimalFormatForContent(aType);
+
+    *aBlackDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
+      IntSize(aRect.width, aRect.height),
+      ImageFormatToSurfaceFormat(format));
+    return;
+  }
+
   nsRefPtr<gfxASurface> referenceSurface = GetBuffer();
   if (!referenceSurface) {
     gfxContext* defaultTarget = mManager->GetDefaultTarget();
     if (defaultTarget) {
       referenceSurface = defaultTarget->CurrentSurface();
     } else {
       nsIWidget* widget = mManager->GetRetainerWidget();
       if (!widget || !(referenceSurface = widget->GetThebesSurface())) {
         referenceSurface = mManager->GetTarget()->CurrentSurface();
       }
     }
   }
-  return referenceSurface->CreateSimilarSurface(
+  nsRefPtr<gfxASurface> ret = referenceSurface->CreateSimilarSurface(
     aType, gfxIntSize(aRect.width, aRect.height));
-}
-
-TemporaryRef<DrawTarget>
-ContentClientBasic::CreateDTBuffer(ContentType aType,
-                                   const nsIntRect& aRect,
-                                   uint32_t aFlags,
-                                   RefPtr<DrawTarget>* aWhiteDT)
-{
-  MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
-  gfxASurface::gfxImageFormat format =
-    gfxPlatform::GetPlatform()->OptimalFormatForContent(aType);
-
-  return gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
-    IntSize(aRect.width, aRect.height),
-    ImageFormatToSurfaceFormat(format));
+  *aBlackSurface = ret.forget().get();
 }
 
 void
 ContentClientRemoteBuffer::DestroyBuffers()
 {
   if (!mDeprecatedTextureClient) {
     return;
   }
@@ -220,56 +219,47 @@ bool
 ContentClientBasic::SupportsAzureContent() const
 {
   return gfxPlatform::GetPlatform()->SupportsAzureContent();
 }
  
 bool
 ContentClientRemoteBuffer::SupportsAzureContent() const
 {
-  if (!mDeprecatedTextureClient) {
-    // Hopefully we don't call this method before we have a texture client. But if
-    // we do, then we have no idea if we can support Azure for whatever surface the
-    // texture client might come up with.
-    return false;
-  }
+  MOZ_ASSERT(mDeprecatedTextureClient);
 
   return gfxPlatform::GetPlatform()->SupportsAzureContentForType(
     mDeprecatedTextureClient->BackendType());
 }
 
-TemporaryRef<DrawTarget>
-ContentClientRemoteBuffer::CreateDTBuffer(ContentType aType,
-                                          const nsIntRect& aRect,
-                                          uint32_t aFlags,
-                                          RefPtr<gfx::DrawTarget>* aWhiteDT)
+void
+ContentClientRemoteBuffer::CreateBuffer(ContentType aType,
+                                        const nsIntRect& aRect,
+                                        uint32_t aFlags,
+                                        gfxASurface** aBlackSurface,
+                                        gfxASurface** aWhiteSurface,
+                                        RefPtr<gfx::DrawTarget>* aBlackDT,
+                                        RefPtr<gfx::DrawTarget>* aWhiteDT)
 {
   BuildDeprecatedTextureClients(aType, aRect, aFlags);
 
-  RefPtr<DrawTarget> ret = mDeprecatedTextureClient->LockDrawTarget();
-  if (aFlags & BUFFER_COMPONENT_ALPHA) {
-    *aWhiteDT = mDeprecatedTextureClientOnWhite->LockDrawTarget();
+  if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(
+        mDeprecatedTextureClient->BackendType())) {
+    *aBlackDT = mDeprecatedTextureClient->LockDrawTarget();
+    if (aFlags & BUFFER_COMPONENT_ALPHA) {
+      *aWhiteDT = mDeprecatedTextureClientOnWhite->LockDrawTarget();
+    }
+  } else {
+    nsRefPtr<gfxASurface> ret = mDeprecatedTextureClient->LockSurface();
+    *aBlackSurface = ret.forget().get();
+    if (aFlags & BUFFER_COMPONENT_ALPHA) {
+     nsRefPtr<gfxASurface> retWhite = mDeprecatedTextureClientOnWhite->LockSurface();
+      *aWhiteSurface = retWhite.forget().get();
+    }
   }
-  return ret.forget();
-}
-
-already_AddRefed<gfxASurface>
-ContentClientRemoteBuffer::CreateBuffer(ContentType aType,
-                                        const nsIntRect& aRect,
-                                        uint32_t aFlags,
-                                        gfxASurface** aWhiteSurface)
-{
-  BuildDeprecatedTextureClients(aType, aRect, aFlags);
-
-  nsRefPtr<gfxASurface> ret = mDeprecatedTextureClient->LockSurface();
-  if (aFlags & BUFFER_COMPONENT_ALPHA) {
-    nsRefPtr<gfxASurface> retWhite = mDeprecatedTextureClientOnWhite->LockSurface();
-    *aWhiteSurface = retWhite.forget().get();
-  }
-  return ret.forget();
 }
 
 nsIntRegion
 ContentClientRemoteBuffer::GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
                                             const nsIntRegion& aVisibleRegion,
                                             bool aDidSelfCopy)
 {
   nsIntRegion updatedRegion;
@@ -532,21 +522,17 @@ ContentClientDoubleBuffered::UpdateDesti
 
   bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
   if (isClippingCheap) {
     gfxUtils::ClipToRegion(destCtx, aUpdateRegion);
   }
 
   if (SupportsAzureContent()) {
     MOZ_ASSERT(!destCtx->IsCairo());
-
-    if (destCtx->GetDrawTarget()->GetFormat() == FORMAT_B8G8R8A8) {
-      destCtx->GetDrawTarget()->ClearRect(Rect(0, 0, mFrontBufferRect.width, mFrontBufferRect.height));
-    }
-    aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_BLACK);
+    aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_BLACK, 1.0, OP_SOURCE);
   } else {
     aSource.DrawBufferWithRotation(destCtx, BUFFER_BLACK);
   }
 
   if (aSource.HaveBufferOnWhite()) {
     MOZ_ASSERT(HaveBufferOnWhite());
     nsRefPtr<gfxContext> destCtx =
       GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE);
@@ -554,21 +540,17 @@ ContentClientDoubleBuffered::UpdateDesti
 
     bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
     if (isClippingCheap) {
       gfxUtils::ClipToRegion(destCtx, aUpdateRegion);
     }
 
     if (SupportsAzureContent()) {
       MOZ_ASSERT(!destCtx->IsCairo());
-
-      if (destCtx->GetDrawTarget()->GetFormat() == FORMAT_B8G8R8A8) {
-        destCtx->GetDrawTarget()->ClearRect(Rect(0, 0, mFrontBufferRect.width, mFrontBufferRect.height));
-      }
-      aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_WHITE);
+      aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_WHITE, 1.0, OP_SOURCE);
     } else {
       aSource.DrawBufferWithRotation(destCtx, BUFFER_WHITE);
     }
   }
 }
 
 ContentClientSingleBuffered::~ContentClientSingleBuffered()
 {
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -147,24 +147,19 @@ public:
   }
 
   void DrawTo(ThebesLayer* aLayer, gfxContext* aTarget, float aOpacity,
               gfxASurface* aMask, const gfxMatrix* aMaskTransform)
   {
     ThebesLayerBuffer::DrawTo(aLayer, aTarget, aOpacity, aMask, aMaskTransform);
   }
 
-  virtual already_AddRefed<gfxASurface> CreateBuffer(ContentType aType,
-                                                     const nsIntRect& aRect,
-                                                     uint32_t aFlags,
-                                                     gfxASurface**) MOZ_OVERRIDE;
-  virtual TemporaryRef<gfx::DrawTarget> CreateDTBuffer(ContentType aType,
-                                                       const nsIntRect& aRect,
-                                                       uint32_t aFlags,
-                                                       RefPtr<gfx::DrawTarget>* aWhiteDT);
+  virtual void CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags,
+                            gfxASurface** aBlackSurface, gfxASurface** aWhiteSurface,
+                            RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) MOZ_OVERRIDE;
   virtual bool SupportsAzureContent() const;
 
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
     MOZ_CRASH("Should not be called on non-remote ContentClient");
   }
 
 private:
@@ -233,24 +228,19 @@ public:
   {
     return ThebesLayerBuffer::BufferRect();
   }
   virtual const nsIntPoint& BufferRotation() const
   {
     return ThebesLayerBuffer::BufferRotation();
   }
 
-  virtual already_AddRefed<gfxASurface> CreateBuffer(ContentType aType,
-                                                     const nsIntRect& aRect,
-                                                     uint32_t aFlags,
-                                                     gfxASurface** aWhiteSurface) MOZ_OVERRIDE;
-  virtual TemporaryRef<gfx::DrawTarget> CreateDTBuffer(ContentType aType,
-                                                       const nsIntRect& aRect,
-                                                       uint32_t aFlags,
-                                                       RefPtr<gfx::DrawTarget>* aWhiteDT) MOZ_OVERRIDE;
+  virtual void CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags,
+                            gfxASurface** aBlackSurface, gfxASurface** aWhiteSurface,
+                            RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) MOZ_OVERRIDE;
 
   virtual bool SupportsAzureContent() const MOZ_OVERRIDE;
 
   void DestroyBuffers();
 
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
     return mTextureInfo;
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -101,25 +101,21 @@ DrawWithVertexBuffer2(GLContext *aGLCont
 
   aGLContext->fDisableVertexAttribArray(aAttr1);
   aGLContext->fDisableVertexAttribArray(aAttr2);
 
   aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
 void
-FPSState::DrawFPS(TimeStamp aNow,
-                  GLContext* context, ShaderProgramOGL* copyprog)
+FPSState::DrawCounter(float offset,
+                      unsigned value,
+                      GLContext* context,
+                      ShaderProgramOGL* copyprog)
 {
-  int fps = int(mCompositionFps.AddFrameAndGetFps(aNow));
-  int txnFps = int(mTransactionFps.GetFpsAt(aNow));
-
-  GLint viewport[4];
-  context->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
-
   if (!mTexture) {
     // Bind the number of textures we need, in this case one.
     context->fGenTextures(1, &mTexture);
     context->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
     context->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MIN_FILTER,LOCAL_GL_NEAREST);
     context->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MAG_FILTER,LOCAL_GL_NEAREST);
 
     const char *text =
@@ -139,67 +135,45 @@ FPSState::DrawFPS(TimeStamp aNow,
         uint32_t white  = 0xffffffff;
         buf[i * 64 + j] = (text[i * 41 + j] == ' ') ? purple : white;
       }
     }
     context->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 64, 8, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf);
     free(buf);
   }
 
-  mVBOs.Reset();
+  GLint viewport[4];
+  context->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
 
   struct Vertex2D {
     float x,y;
   };
   float oneOverVP2 = 1.0 / viewport[2];
   float oneOverVP3 = 1.0 / viewport[3];
   const Vertex2D vertices[] = {
-    { -1.0f, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f, 1.0f},
-    { -1.0f + 22.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + 22.f * oneOverVP2, 1.0f },
+    { -1.0f + (offset +  0.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+    { -1.0f + (offset +  0.f) * oneOverVP2, 1.0f},
+    { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+    { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f },
 
-    {  -1.0f + 22.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    {  -1.0f + 22.f * oneOverVP2, 1.0f },
-    {  -1.0f + 44.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    {  -1.0f + 44.f * oneOverVP2, 1.0f },
+    { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+    { -1.0f + (offset + 22.f) * oneOverVP2, 1.0f },
+    { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+    { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f },
 
-    { -1.0f + 44.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + 44.f * oneOverVP2, 1.0f },
-    { -1.0f + 66.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + 66.f * oneOverVP2, 1.0f }
+    { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+    { -1.0f + (offset + 44.f) * oneOverVP2, 1.0f },
+    { -1.0f + (offset + 66.f) * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
+    { -1.0f + (offset + 66.f) * oneOverVP2, 1.0f }
   };
 
-  const Vertex2D vertices2[] = {
-    { -1.0f + 80.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + 80.f * oneOverVP2, 1.0f },
-    { -1.0f + 102.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + 102.f * oneOverVP2, 1.0f },
-
-    { -1.0f + 102.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + 102.f * oneOverVP2, 1.0f },
-    { -1.0f + 124.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + 124.f * oneOverVP2, 1.0f },
+  unsigned v1   = value % 10;
+  unsigned v10  = (value % 100) / 10;
+  unsigned v100 = (value % 1000) / 100;
 
-    { -1.0f + 124.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + 124.f * oneOverVP2, 1.0f },
-    { -1.0f + 146.f * oneOverVP2, 1.0f - 42.f * oneOverVP3 },
-    { -1.0f + 146.f * oneOverVP2, 1.0f },
-  };
-
-  int v1   = fps % 10;
-  int v10  = (fps % 100) / 10;
-  int v100 = (fps % 1000) / 100;
-
-  int txn1 = txnFps % 10;
-  int txn10  = (txnFps % 100) / 10;
-  int txn100 = (txnFps % 1000) / 100;
-
-  // Feel free to comment these texture coordinates out and use one
-  // of the ones below instead, or play around with your own values.
   const GLfloat texCoords[] = {
     (v100 * 4.f) / 64, 7.f / 8,
     (v100 * 4.f) / 64, 0.0f,
     (v100 * 4.f + 4) / 64, 7.f / 8,
     (v100 * 4.f + 4) / 64, 0.0f,
 
     (v10 * 4.f) / 64, 7.f / 8,
     (v10 * 4.f) / 64, 0.0f,
@@ -207,33 +181,16 @@ FPSState::DrawFPS(TimeStamp aNow,
     (v10 * 4.f + 4) / 64, 0.0f,
 
     (v1 * 4.f) / 64, 7.f / 8,
     (v1 * 4.f) / 64, 0.0f,
     (v1 * 4.f + 4) / 64, 7.f / 8,
     (v1 * 4.f + 4) / 64, 0.0f,
   };
 
-  const GLfloat texCoords2[] = {
-    (txn100 * 4.f) / 64, 7.f / 8,
-    (txn100 * 4.f) / 64, 0.0f,
-    (txn100 * 4.f + 4) / 64, 7.f / 8,
-    (txn100 * 4.f + 4) / 64, 0.0f,
-
-    (txn10 * 4.f) / 64, 7.f / 8,
-    (txn10 * 4.f) / 64, 0.0f,
-    (txn10 * 4.f + 4) / 64, 7.f / 8,
-    (txn10 * 4.f + 4) / 64, 0.0f,
-
-    (txn1 * 4.f) / 64, 7.f / 8,
-    (txn1 * 4.f) / 64, 0.0f,
-    (txn1 * 4.f + 4) / 64, 7.f / 8,
-    (txn1 * 4.f + 4) / 64, 0.0f,
-  };
-
   // Turn necessary features on
   context->fEnable(LOCAL_GL_BLEND);
   context->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
 
   context->fActiveTexture(LOCAL_GL_TEXTURE0);
   context->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
 
   copyprog->Activate();
@@ -245,20 +202,31 @@ FPSState::DrawFPS(TimeStamp aNow,
 
   GLint vcattr = copyprog->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
   GLint tcattr = copyprog->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
 
   DrawWithVertexBuffer2(context, mVBOs,
                         LOCAL_GL_TRIANGLE_STRIP, 12,
                         vcattr, (GLfloat *) vertices,
                         tcattr, (GLfloat *) texCoords);
-  DrawWithVertexBuffer2(context, mVBOs,
-                        LOCAL_GL_TRIANGLE_STRIP, 12,
-                        vcattr, (GLfloat *) vertices2,
-                        tcattr, (GLfloat *) texCoords2);
+}
+
+void
+FPSState::DrawFPS(TimeStamp aNow,
+                  unsigned aFillRatio,
+                  GLContext* context, ShaderProgramOGL* copyprog)
+{
+  mVBOs.Reset();
+
+  unsigned fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
+  unsigned txnFps = unsigned(mTransactionFps.GetFpsAt(aNow));
+
+  DrawCounter(0, fps, context, copyprog);
+  DrawCounter(80, txnFps, context, copyprog);
+  DrawCounter(160, aFillRatio, context, copyprog);
 }
 
 #ifdef CHECK_CURRENT_PROGRAM
 int ShaderProgramOGL::sCurrentProgramKey = 0;
 #endif
 
 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
@@ -824,16 +792,19 @@ CompositorOGL::BeginFrame(const Rect *aC
     MakeCurrent(ForceMakeCurrent);
 
     mWidgetSize.width = width;
     mWidgetSize.height = height;
   } else {
     MakeCurrent();
   }
 
+  mPixelsPerFrame = width * height;
+  mPixelsFilled = 0;
+
 #if MOZ_ANDROID_OMTC
   TexturePoolOGL::Fill(gl());
 #endif
 
   mCurrentRenderTarget = CompositingRenderTargetOGL::RenderTargetForWindow(this,
                             IntSize(width, height),
                             aTransform);
   mCurrentRenderTarget->BindRenderTarget();
@@ -1048,16 +1019,18 @@ CompositorOGL::DrawQuad(const Rect& aRec
 
     maskType = effectMask->mIs3D
                  ? Mask3d
                  : Mask2d;
   } else {
     maskType = MaskNone;
   }
 
+  mPixelsFilled += aRect.width * aRect.height;
+
   ShaderProgramType programType = GetProgramTypeForEffect(aEffectChain.mPrimaryEffect);
   ShaderProgramOGL *program = GetProgram(programType, maskType);
   program->Activate();
   if (programType == RGBARectLayerProgramType ||
       programType == RGBXRectLayerProgramType) {
     TexturedEffect* texturedEffect =
         static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
     TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
@@ -1309,17 +1282,23 @@ CompositorOGL::EndFrame()
 
   if (sDrawFPS && !mFPS) {
     mFPS = new FPSState();
   } else if (!sDrawFPS && mFPS) {
     mFPS = nullptr;
   }
 
   if (mFPS) {
-    mFPS->DrawFPS(TimeStamp::Now(), mGLContext, GetProgram(Copy2DProgramType));
+    float fillRatio = 0;
+    if (mPixelsFilled > 0 && mPixelsPerFrame > 0) {
+      fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
+      if (fillRatio > 999.0f)
+        fillRatio = 999.0f;
+    }
+    mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mGLContext, GetProgram(Copy2DProgramType));
   }
 
   mGLContext->SwapBuffers();
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
 void
 CompositorOGL::EndFrameForExternalComposition(const gfxMatrix& aTransform)
--- a/gfx/layers/opengl/FPSCounter.h
+++ b/gfx/layers/opengl/FPSCounter.h
@@ -70,17 +70,18 @@ private:
 struct FPSState {
   GLuint mTexture;
   FPSCounter mCompositionFps;
   FPSCounter mTransactionFps;
   gl::VBOArena mVBOs;
 
   FPSState() : mTexture(0) { }
 
-  void DrawFPS(TimeStamp, gl::GLContext*, ShaderProgramOGL*);
+  void DrawCounter(float, unsigned, gl::GLContext*, ShaderProgramOGL*);
+  void DrawFPS(TimeStamp, unsigned, gl::GLContext*, ShaderProgramOGL*);
 
   void NotifyShadowTreeTransaction() {
     mTransactionFps.AddFrame(TimeStamp::Now());
   }
 };
 
 }
 }
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -891,17 +891,17 @@ LayerManagerOGL::Render()
 
   if (sDrawFPS && !mFPS) {
     mFPS = new FPSState();
   } else if (!sDrawFPS && mFPS) {
     mFPS = nullptr;
   }
 
   if (mFPS) {
-    mFPS->DrawFPS(TimeStamp::Now(), mGLContext, GetProgram(Copy2DProgramType));
+    mFPS->DrawFPS(TimeStamp::Now(), 0, mGLContext, GetProgram(Copy2DProgramType));
   }
 
   if (mGLContext->IsDoubleBuffered()) {
     mGLContext->SwapBuffers();
     LayerManager::PostPresent();
     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
     return;
   }
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -350,23 +350,26 @@ public:
   {
     // Let ThebesLayerBuffer do all the hard work for us! :D
     return ThebesLayerBuffer::BeginPaint(mLayer, 
                                          aContentType, 
                                          aFlags);
   }
 
   // ThebesLayerBuffer interface
-  virtual already_AddRefed<gfxASurface>
-  CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, gfxASurface**)
+  void
+  CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags,
+               gfxASurface** aBlackSurface, gfxASurface** aWhiteSurface,
+               RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) MOZ_OVERRIDE
   {
     NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color");
 
     mTexImage = CreateClampOrRepeatTextureImage(gl(), aRect.Size(), aType, aFlags);
-    return mTexImage ? mTexImage->GetBackingSurface() : nullptr;
+    nsRefPtr<gfxASurface> ret = mTexImage ? mTexImage->GetBackingSurface() : nullptr;
+    *aBlackSurface = ret.forget().get();
   }
 
   virtual nsIntPoint GetOriginOffset() {
     return BufferRect().TopLeft() - BufferRotation();
   }
 };
 
 
--- a/image/src/Image.cpp
+++ b/image/src/Image.cpp
@@ -5,19 +5,25 @@
 
 #include "nsMimeTypes.h"
 
 #include "Image.h"
 
 namespace mozilla {
 namespace image {
 
+#ifdef DEBUG_imagelib
+static const bool allowOMTURIAccess = true;
+#else
+static const bool allowOMTURIAccess = false;
+#endif
+
 // Constructor
 ImageResource::ImageResource(imgStatusTracker* aStatusTracker, nsIURI* aURI) :
-  mURI(aURI),
+  mURI(new nsMainThreadPtrHolder<nsIURI>(aURI, allowOMTURIAccess)),
   mInnerWindowId(0),
   mAnimationConsumers(0),
   mAnimationMode(kNormalAnimMode),
   mInitialized(false),
   mAnimating(false),
   mError(false)
 {
   if (aStatusTracker) {
--- a/image/src/Image.h
+++ b/image/src/Image.h
@@ -5,16 +5,17 @@
 
 #ifndef MOZILLA_IMAGELIB_IMAGE_H_
 #define MOZILLA_IMAGELIB_IMAGE_H_
 
 #include "mozilla/MemoryReporting.h"
 #include "imgIContainer.h"
 #include "imgStatusTracker.h"
 #include "nsIURI.h"
+#include "nsProxyRelease.h" // for nsMainThreadPtrHolder and nsMainThreadPtrHandle
 
 class nsIRequest;
 class nsIInputStream;
 
 namespace mozilla {
 namespace image {
 
 class Image : public imgIContainer
@@ -151,18 +152,19 @@ public:
   }
   virtual uint64_t InnerWindowID() const MOZ_OVERRIDE { return mInnerWindowId; }
 
   virtual bool HasError() MOZ_OVERRIDE    { return mError; }
   virtual void SetHasError() MOZ_OVERRIDE { mError = true; }
 
   /*
    * Returns a non-AddRefed pointer to the URI associated with this image.
+   * Illegal to use off-main-thread.
    */
-  virtual nsIURI* GetURI() MOZ_OVERRIDE { return mURI; }
+  virtual nsIURI* GetURI() MOZ_OVERRIDE { return mURI.get(); }
 
 protected:
   ImageResource(imgStatusTracker* aStatusTracker, nsIURI* aURI);
 
   // Shared functionality for implementors of imgIContainer. Every
   // implementation of attribute animationMode should forward here.
   nsresult GetAnimationModeInternal(uint16_t *aAnimationMode);
   nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
@@ -180,22 +182,22 @@ protected:
   virtual bool ShouldAnimate() {
     return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode;
   }
 
   virtual nsresult StartAnimation() = 0;
   virtual nsresult StopAnimation() = 0;
 
   // Member data shared by all implementations of this abstract class
-  nsRefPtr<imgStatusTracker>  mStatusTracker;
-  nsCOMPtr<nsIURI>            mURI;
-  uint64_t                    mInnerWindowId;
-  uint32_t                    mAnimationConsumers;
-  uint16_t                    mAnimationMode;   // Enum values in imgIContainer
-  bool                        mInitialized:1;   // Have we been initalized?
-  bool                        mAnimating:1;     // Are we currently animating?
-  bool                        mError:1;         // Error handling
+  nsRefPtr<imgStatusTracker>    mStatusTracker;
+  nsMainThreadPtrHandle<nsIURI> mURI;
+  uint64_t                      mInnerWindowId;
+  uint32_t                      mAnimationConsumers;
+  uint16_t                      mAnimationMode; // Enum values in imgIContainer
+  bool                          mInitialized:1; // Have we been initalized?
+  bool                          mAnimating:1;   // Are we currently animating?
+  bool                          mError:1;       // Error handling
 };
 
 } // namespace image
 } // namespace mozilla
 
 #endif // MOZILLA_IMAGELIB_IMAGE_H_
--- a/ipc/glue/AsyncChannel.cpp
+++ b/ipc/glue/AsyncChannel.cpp
@@ -908,16 +908,13 @@ void
 AsyncChannel::ProcessGoodbyeMessage()
 {
     AssertLinkThread();
     mMonitor->AssertCurrentThreadOwns();
 
     // TODO sort out Close() on this side racing with Close() on the
     // other side
     mChannelState = ChannelClosing;
-
-    printf("NOTE: %s process received `Goodbye', closing down\n",
-           mChild ? "child" : "parent");
 }
 
 
 } // namespace ipc
 } // namespace mozilla
--- a/js/public/Id.h
+++ b/js/public/Id.h
@@ -17,16 +17,17 @@
 // entry points expecting a jsid and do not need to handle JSID_VOID in hooks
 // receiving a jsid except when explicitly noted in the API contract.
 //
 // A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or
 // JS_IdToValue must be used instead.
 
 #include "jstypes.h"
 
+#include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 
 #ifdef JS_USE_JSID_STRUCT_TYPES
 struct jsid
 {
     size_t asBits;
     bool operator==(jsid rhs) const { return asBits == rhs.asBits; }
@@ -155,9 +156,35 @@ extern JS_PUBLIC_DATA(const jsid) JSID_E
 #else
 # define JSID_VOID ((jsid)JSID_TYPE_VOID)
 # define JSID_EMPTY ((jsid)JSID_TYPE_OBJECT)
 #endif
 
 extern JS_PUBLIC_DATA(const JS::Handle<jsid>) JSID_VOIDHANDLE;
 extern JS_PUBLIC_DATA(const JS::Handle<jsid>) JSID_EMPTYHANDLE;
 
+namespace js {
+
+inline bool
+IsPoisonedId(jsid iden)
+{
+    if (JSID_IS_STRING(iden))
+        return JS::IsPoisonedPtr(JSID_TO_STRING(iden));
+    if (JSID_IS_OBJECT(iden))
+        return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden));
+    return false;
+}
+
+template <> struct GCMethods<jsid>
+{
+    static jsid initial() { return JSID_VOID; }
+    static ThingRootKind kind() { return THING_ROOT_ID; }
+    static bool poisoned(jsid id) { return IsPoisonedId(id); }
+    static bool needsPostBarrier(jsid id) { return false; }
+#ifdef JSGC_GENERATIONAL
+    static void postBarrier(jsid *idp) {}
+    static void relocate(jsid *idp) {}
+#endif
+};
+
+}
+
 #endif /* js_Id_h */
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -49,21 +49,21 @@ INCLUDED_RULES_MK = 1
   XPIDL_FLAGS \
   $(NULL)
 
 ifndef EXTERNALLY_MANAGED_MAKE_FILE
 # Using $(firstword) may not be perfect. But it should be good enough for most
 # scenarios.
 _current_makefile = $(CURDIR)/$(firstword $(MAKEFILE_LIST))
 
-$(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES),$(if $($(var)),\
+$(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES),$(if $(filter file override,$(subst $(NULL) ,_,$(origin $(var)))),\
     $(error Variable $(var) is defined in $(_current_makefile). It should only be defined in moz.build files),\
     ))
 
-$(foreach var,$(_DEPRECATED_VARIABLES),$(if $($(var)),\
+$(foreach var,$(_DEPRECATED_VARIABLES),$(if $(filter file override,$(subst $(NULL) ,_,$(origin $(var)))),\
     $(error Variable $(var) is defined in $(_current_makefile). This variable has been deprecated. It does nothing. It must be removed in order to build)\
     ))
 
 ifneq (,$(XPIDLSRCS)$(SDK_XPIDLSRCS))
     $(error XPIDLSRCS and SDK_XPIDLSRCS have been merged and moved to moz.build files as the XPIDL_SOURCES variable. You must move these variables out of $(_current_makefile))
 endif
 
 # Import the automatically generated backend file. If this file doesn't exist,
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -13,144 +13,16 @@
 
 #include "gc/Marking.h"
 #include "gc/StoreBuffer.h"
 
 #include "vm/String-inl.h"
 
 namespace js {
 
-/*
- * This is a post barrier for HashTables whose key is a GC pointer. Any
- * insertion into a HashTable not marked as part of the runtime, with a GC
- * pointer as a key, must call this immediately after each insertion.
- */
-template <class Map, class Key>
-inline void
-HashTableWriteBarrierPost(JSRuntime *rt, Map *map, const Key &key)
-{
-#ifdef JSGC_GENERATIONAL
-    if (key && IsInsideNursery(rt, key))
-        rt->gcStoreBuffer.putGeneric(gc::HashKeyRef<Map, Key>(map, key));
-#endif
-}
-
-inline
-EncapsulatedId::~EncapsulatedId()
-{
-    pre();
-}
-
-inline EncapsulatedId &
-EncapsulatedId::operator=(const EncapsulatedId &v)
-{
-    if (v.value != value)
-        pre();
-    JS_ASSERT(!IsPoisonedId(v.value));
-    value = v.value;
-    return *this;
-}
-
-inline void
-EncapsulatedId::pre()
-{
-#ifdef JSGC_INCREMENTAL
-    if (JSID_IS_OBJECT(value)) {
-        JSObject *obj = JSID_TO_OBJECT(value);
-        Zone *zone = obj->zone();
-        if (zone->needsBarrier()) {
-            js::gc::MarkObjectUnbarriered(zone->barrierTracer(), &obj, "write barrier");
-            JS_ASSERT(obj == JSID_TO_OBJECT(value));
-        }
-    } else if (JSID_IS_STRING(value)) {
-        JSString *str = JSID_TO_STRING(value);
-        Zone *zone = str->zone();
-        if (zone->needsBarrier()) {
-            js::gc::MarkStringUnbarriered(zone->barrierTracer(), &str, "write barrier");
-            JS_ASSERT(str == JSID_TO_STRING(value));
-        }
-    }
-#endif
-}
-
-inline
-RelocatableId::~RelocatableId()
-{
-    pre();
-}
-
-inline RelocatableId &
-RelocatableId::operator=(jsid id)
-{
-    if (id != value)
-        pre();
-    JS_ASSERT(!IsPoisonedId(id));
-    value = id;
-    return *this;
-}
-
-inline RelocatableId &
-RelocatableId::operator=(const RelocatableId &v)
-{
-    if (v.value != value)
-        pre();
-    JS_ASSERT(!IsPoisonedId(v.value));
-    value = v.value;
-    return *this;
-}
-
-inline
-HeapId::HeapId(jsid id)
-    : EncapsulatedId(id)
-{
-    JS_ASSERT(!IsPoisonedId(id));
-    post();
-}
-
-inline
-HeapId::~HeapId()
-{
-    pre();
-}
-
-inline void
-HeapId::init(jsid id)
-{
-    JS_ASSERT(!IsPoisonedId(id));
-    value = id;
-    post();
-}
-
-inline void
-HeapId::post()
-{
-}
-
-inline HeapId &
-HeapId::operator=(jsid id)
-{
-    if (id != value)
-        pre();
-    JS_ASSERT(!IsPoisonedId(id));
-    value = id;
-    post();
-    return *this;
-}
-
-inline HeapId &
-HeapId::operator=(const HeapId &v)
-{
-    if (v.value != value)
-        pre();
-    JS_ASSERT(!IsPoisonedId(v.value));
-    value = v.value;
-    post();
-    return *this;
-}
-
 inline const Value &
 ReadBarrieredValue::get() const
 {
     if (value.isObject())
         JSObject::readBarrier(&value.toObject());
     else if (value.isString())
         JSString::readBarrier(value.toString());
     else
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -119,30 +119,69 @@
 namespace js {
 
 class PropertyName;
 
 namespace gc {
 // Direct value access used by the write barriers and the jits.
 void
 MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name);
+
+// These two declarations are also present in gc/Marking.h, via the DeclMarker
+// macro.  Not great, but hard to avoid.
+void
+MarkObjectUnbarriered(JSTracer *trc, JSObject **obj, const char *name);
+void
+MarkStringUnbarriered(JSTracer *trc, JSString **str, const char *name);
 }
 
+// Note: these functions must be equivalent to the zone() functions implemented
+// by all the subclasses of Cell.
+
 JS::Zone *
 ZoneOfObject(const JSObject &obj);
 
+static inline JS::shadow::Zone *
+ShadowZoneOfObject(JSObject *obj)
+{
+    return JS::shadow::Zone::asShadowZone(ZoneOfObject(*obj));
+}
+
+static inline JS::shadow::Zone *
+ShadowZoneOfString(JSString *str)
+{
+    return JS::shadow::Zone::asShadowZone(reinterpret_cast<const js::gc::Cell *>(str)->tenuredZone());
+}
+
 JS_ALWAYS_INLINE JS::Zone *
 ZoneOfValue(const JS::Value &value)
 {
     JS_ASSERT(value.isMarkable());
     if (value.isObject())
         return ZoneOfObject(value.toObject());
     return static_cast<js::gc::Cell *>(value.toGCThing())->tenuredZone();
 }
 
+/*
+ * This is a post barrier for HashTables whose key is a GC pointer. Any
+ * insertion into a HashTable not marked as part of the runtime, with a GC
+ * pointer as a key, must call this immediately after each insertion.
+ */
+template <class Map, class Key>
+inline void
+HashTableWriteBarrierPost(JSRuntime *rt, Map *map, const Key &key)
+{
+#ifdef JSGC_GENERATIONAL
+    if (key && IsInsideNursery(rt, key)) {
+        JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
+        shadowRuntime->gcStoreBufferPtr()->putGeneric(gc::HashKeyRef<Map, Key>(map, key));
+    }
+#endif
+}
+
 template<class T, typename Unioned = uintptr_t>
 class EncapsulatedPtr
 {
   protected:
     union {
         T *value;
         Unioned other;
     };
@@ -818,57 +857,120 @@ class EncapsulatedId
     jsid value;
 
   private:
     EncapsulatedId(const EncapsulatedId &v) MOZ_DELETE;
 
   public:
     explicit EncapsulatedId() : value(JSID_VOID) {}
     explicit EncapsulatedId(jsid id) : value(id) {}
-    ~EncapsulatedId();
+    ~EncapsulatedId() { pre(); }
 
-    inline EncapsulatedId &operator=(const EncapsulatedId &v);
+    EncapsulatedId &operator=(const EncapsulatedId &v) {
+        if (v.value != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(v.value));
+        value = v.value;
+        return *this;
+    }
 
     bool operator==(jsid id) const { return value == id; }
     bool operator!=(jsid id) const { return value != id; }
 
     jsid get() const { return value; }
     jsid *unsafeGet() { return &value; }
     void unsafeSet(jsid newId) { value = newId; }
     operator jsid() const { return value; }
 
   protected:
-    inline void pre();
+    void pre() {
+#ifdef JSGC_INCREMENTAL
+        if (JSID_IS_OBJECT(value)) {
+            JSObject *obj = JSID_TO_OBJECT(value);
+            JS::shadow::Zone *shadowZone = ShadowZoneOfObject(obj);
+            if (shadowZone->needsBarrier()) {
+                js::gc::MarkObjectUnbarriered(shadowZone->barrierTracer(), &obj, "write barrier");
+                JS_ASSERT(obj == JSID_TO_OBJECT(value));
+            }
+        } else if (JSID_IS_STRING(value)) {
+            JSString *str = JSID_TO_STRING(value);
+            JS::shadow::Zone *shadowZone = ShadowZoneOfString(str);
+            if (shadowZone->needsBarrier()) {
+                js::gc::MarkStringUnbarriered(shadowZone->barrierTracer(), &str, "write barrier");
+                JS_ASSERT(str == JSID_TO_STRING(value));
+            }
+        }
+#endif
+    }
 };
 
 class RelocatableId : public EncapsulatedId
 {
   public:
     explicit RelocatableId() : EncapsulatedId() {}
     explicit inline RelocatableId(jsid id) : EncapsulatedId(id) {}
-    inline ~RelocatableId();
+    ~RelocatableId() { pre(); }
 
-    inline RelocatableId &operator=(jsid id);
-    inline RelocatableId &operator=(const RelocatableId &v);
+    RelocatableId &operator=(jsid id) {
+        if (id != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(id));
+        value = id;
+        return *this;
+    }
+
+    RelocatableId &operator=(const RelocatableId &v) {
+        if (v.value != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(v.value));
+        value = v.value;
+        return *this;
+    }
 };
 
 class HeapId : public EncapsulatedId
 {
   public:
     explicit HeapId() : EncapsulatedId() {}
-    explicit inline HeapId(jsid id);
-    inline ~HeapId();
+
+    explicit HeapId(jsid id)
+      : EncapsulatedId(id)
+    {
+        JS_ASSERT(!IsPoisonedId(id));
+        post();
+    }
+
+    ~HeapId() { pre(); }
+
+    void init(jsid id) {
+        JS_ASSERT(!IsPoisonedId(id));
+        value = id;
+        post();
+    }
 
-    inline void init(jsid id);
+    HeapId &operator=(jsid id) {
+        if (id != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(id));
+        value = id;
+        post();
+        return *this;
+    }
 
-    inline HeapId &operator=(jsid id);
-    inline HeapId &operator=(const HeapId &v);
+    HeapId &operator=(const HeapId &v) {
+        if (v.value != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(v.value));
+        value = v.value;
+        post();
+        return *this;
+    }
 
   private:
-    inline void post();
+    void post() {};
 
     HeapId(const HeapId &v) MOZ_DELETE;
 };
 
 /*
  * Incremental GC requires that weak pointers have read barriers. This is mostly
  * an issue for empty shapes stored in JSCompartment. The problem happens when,
  * during an incremental GC, some JS code stores one of the compartment's empty
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -161,30 +161,41 @@ CodeGenerator::visitValueToInt32(LValueT
     MDefinition *input;
     if (lir->mode() == LValueToInt32::NORMAL)
         input = lir->mirNormal()->input();
     else
         input = lir->mirTruncate()->input();
 
     Label fails;
     if (lir->mode() == LValueToInt32::TRUNCATE) {
+        OutOfLineCode *oolDouble = oolTruncateDouble(temp, output);
+        if (!oolDouble)
+            return false;
+
         // We can only handle strings in truncation contexts, like bitwise
         // operations.
+        Label *stringEntry, *stringRejoin;
+        Register stringReg;
         if (input->mightBeType(MIRType_String)) {
-            Register stringReg = ToRegister(lir->temp());
-            OutOfLineCode *ool = oolCallVM(StringToNumberInfo, lir, (ArgList(), stringReg),
-                                           StoreFloatRegisterTo(temp));
-            if (!ool)
+            stringReg = ToRegister(lir->temp());
+            OutOfLineCode *oolString = oolCallVM(StringToNumberInfo, lir, (ArgList(), stringReg),
+                                                 StoreFloatRegisterTo(temp));
+            if (!oolString)
                 return false;
-
-            masm.truncateValueToInt32(operand, input, ool->entry(), ool->rejoin(), stringReg,
-                                      temp, output, &fails);
+            stringEntry = oolString->entry();
+            stringRejoin = oolString->rejoin();
         } else {
-            masm.truncateValueToInt32(operand, input, temp, output, &fails);
+            stringReg = InvalidReg;
+            stringEntry = NULL;
+            stringRejoin = NULL;
         }
+
+        masm.truncateValueToInt32(operand, input, stringEntry, stringRejoin, oolDouble->entry(),
+                                  stringReg, temp, output, &fails);
+        masm.bind(oolDouble->rejoin());
     } else {
         masm.convertValueToInt32(operand, input, temp, output, &fails,
                                  lir->mirNormal()->canBeNegativeZero());
     }
 
     return bailoutFrom(&fails, lir->snapshot());
 }
 
@@ -6774,26 +6785,38 @@ CodeGenerator::visitClampDToUint8(LClamp
 bool
 CodeGenerator::visitClampVToUint8(LClampVToUint8 *lir)
 {
     ValueOperand operand = ToValue(lir, LClampVToUint8::Input);
     FloatRegister tempFloat = ToFloatRegister(lir->tempFloat());
     Register output = ToRegister(lir->output());
     MDefinition *input = lir->mir()->input();
 
-    Label fails;
+    OutOfLineCode *oolDouble = oolTruncateDouble(tempFloat, output);
+    if (!oolDouble)
+        return false;
+
+    Label *stringEntry, *stringRejoin;
     if (input->mightBeType(MIRType_String)) {
-        OutOfLineCode *ool = oolCallVM(StringToNumberInfo, lir, (ArgList(), output),
-                                       StoreFloatRegisterTo(tempFloat));
-        masm.clampValueToUint8(operand, input, ool->entry(), ool->rejoin(), output,
-                               tempFloat, output, &fails);
-
+        OutOfLineCode *oolString = oolCallVM(StringToNumberInfo, lir, (ArgList(), output),
+                                             StoreFloatRegisterTo(tempFloat));
+        if (!oolString)
+            return false;
+        stringEntry = oolString->entry();
+        stringRejoin = oolString->rejoin();
     } else {
-        masm.clampValueToUint8(operand, input, tempFloat, output, &fails);
-    }
+        stringEntry = NULL;
+        stringRejoin = NULL;
+    }
+
+    Label fails;
+    masm.clampValueToUint8(operand, input,
+                           stringEntry, stringRejoin, oolDouble->entry(),
+                           output, tempFloat, output, &fails);
+
     if (!bailoutFrom(&fails, lir->snapshot()))
         return false;
 
     return true;
 }
 
 typedef bool (*OperatorInFn)(JSContext *, HandleValue, HandleObject, bool *);
 static const VMFunction OperatorInInfo = FunctionInfo<OperatorInFn>(OperatorIn);
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -1530,36 +1530,37 @@ MacroAssembler::convertTypedOrValueToDou
         loadStaticDouble(&js_NaN, output);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Bad MIRType");
     }
 }
 
 void
-MacroAssembler::convertDoubleToInt(FloatRegister src, Register output, Label *fail,
-                                   IntConversionBehavior behavior)
+MacroAssembler::convertDoubleToInt(FloatRegister src, Register output, Label *truncateFail,
+                                   Label *fail, IntConversionBehavior behavior)
 {
     switch (behavior) {
       case IntConversion_Normal:
       case IntConversion_NegativeZeroCheck:
         convertDoubleToInt32(src, output, fail, behavior == IntConversion_NegativeZeroCheck);
         break;
       case IntConversion_Truncate:
-        branchTruncateDouble(src, output, fail);
+        branchTruncateDouble(src, output, truncateFail ? truncateFail : fail);
         break;
       case IntConversion_ClampToUint8:
         clampDoubleToUint8(src, output);
         break;
     }
 }
 
 void
 MacroAssembler::convertValueToInt(ValueOperand value, MDefinition *maybeInput,
                                   Label *handleStringEntry, Label *handleStringRejoin,
+                                  Label *truncateDoubleSlow,
                                   Register stringReg, FloatRegister temp, Register output,
                                   Label *fail, IntConversionBehavior behavior)
 {
     Register tag = splitTagForTest(value);
     bool handleStrings = (behavior == IntConversion_Truncate ||
                           behavior == IntConversion_ClampToUint8) &&
                          handleStringEntry &&
                          handleStringRejoin;
@@ -1608,17 +1609,17 @@ MacroAssembler::convertValueToInt(ValueO
         if (isDouble.used()) {
             bind(&isDouble);
             unboxDouble(value, temp);
         }
 
         if (handleStrings)
             bind(handleStringRejoin);
 
-        convertDoubleToInt(temp, output, fail, behavior);
+        convertDoubleToInt(temp, output, truncateDoubleSlow, fail, behavior);
         jump(&done);
     }
 
     // Just unbox a bool, the result is 0 or 1.
     if (isBool.used()) {
         bind(&isBool);
         unboxBoolean(value, output);
         jump(&done);
@@ -1719,17 +1720,17 @@ MacroAssembler::convertTypedOrValueToInt
         move32(Imm32(0), output);
         break;
       case MIRType_Boolean:
       case MIRType_Int32:
         if (src.typedReg().gpr() != output)
             move32(src.typedReg().gpr(), output);
         break;
       case MIRType_Double:
-        convertDoubleToInt(src.typedReg().fpu(), output, fail, behavior);
+        convertDoubleToInt(src.typedReg().fpu(), output, NULL, fail, behavior);
         break;
       case MIRType_String:
       case MIRType_Object:
         jump(fail);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Bad MIRType");
     }
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -1008,31 +1008,32 @@ class MacroAssembler : public MacroAssem
         IntConversion_NegativeZeroCheck,
         IntConversion_Truncate,
         IntConversion_ClampToUint8,
     };
 
     //
     // Functions for converting values to int.
     //
-    void convertDoubleToInt(FloatRegister src, Register output, Label *fail,
+    void convertDoubleToInt(FloatRegister src, Register output, Label *truncateFail, Label *fail,
                             IntConversionBehavior behavior);
 
     // Strings may be handled by providing labels to jump to when the behavior
     // is truncation or clamping. The subroutine, usually an OOL call, is
     // passed the unboxed string in |stringReg| and should convert it to a
     // double store into |temp|.
     void convertValueToInt(ValueOperand value, MDefinition *input,
                            Label *handleStringEntry, Label *handleStringRejoin,
+                           Label *truncateDoubleSlow,
                            Register stringReg, FloatRegister temp, Register output,
                            Label *fail, IntConversionBehavior behavior);
     void convertValueToInt(ValueOperand value, FloatRegister temp, Register output, Label *fail,
                            IntConversionBehavior behavior)
     {
-        convertValueToInt(value, NULL, NULL, NULL, InvalidReg, temp, output, fail, behavior);
+        convertValueToInt(value, NULL, NULL, NULL, NULL, InvalidReg, temp, output, fail, behavior);
     }
     bool convertValueToInt(JSContext *cx, const Value &v, Register output, Label *fail,
                            IntConversionBehavior behavior);
     bool convertConstantOrRegisterToInt(JSContext *cx, ConstantOrRegister src, FloatRegister temp,
                                         Register output, Label *fail, IntConversionBehavior behavior);
     void convertTypedOrValueToInt(TypedOrValueRegister src, FloatRegister temp, Register output,
                                   Label *fail, IntConversionBehavior behavior);
 
@@ -1045,17 +1046,17 @@ class MacroAssembler : public MacroAssem
         convertValueToInt(value, temp, output, fail, negativeZeroCheck
                           ? IntConversion_NegativeZeroCheck
                           : IntConversion_Normal);
     }
     void convertValueToInt32(ValueOperand value, MDefinition *input,
                              FloatRegister temp, Register output, Label *fail,
                              bool negativeZeroCheck)
     {
-        convertValueToInt(value, input, NULL, NULL, InvalidReg, temp, output, fail,
+        convertValueToInt(value, input, NULL, NULL, NULL, InvalidReg, temp, output, fail,
                           negativeZeroCheck
                           ? IntConversion_NegativeZeroCheck
                           : IntConversion_Normal);
     }
     bool convertValueToInt32(JSContext *cx, const Value &v, Register output, Label *fail,
                              bool negativeZeroCheck)
     {
         return convertValueToInt(cx, v, output, fail, negativeZeroCheck
@@ -1080,26 +1081,26 @@ class MacroAssembler : public MacroAssem
     //
     // Convenience functions for truncating values to int32.
     //
     void truncateValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label *fail) {
         convertValueToInt(value, temp, output, fail, IntConversion_Truncate);
     }
     void truncateValueToInt32(ValueOperand value, MDefinition *input,
                               Label *handleStringEntry, Label *handleStringRejoin,
-                              Register stringReg, FloatRegister temp, Register output,
-                              Label *fail)
+                              Label *truncateDoubleSlow,
+                              Register stringReg, FloatRegister temp, Register output, Label *fail)
     {
-        convertValueToInt(value, input, handleStringEntry, handleStringRejoin,
+        convertValueToInt(value, input, handleStringEntry, handleStringRejoin, truncateDoubleSlow,
                           stringReg, temp, output, fail, IntConversion_Truncate);
     }
     void truncateValueToInt32(ValueOperand value, MDefinition *input,
                               FloatRegister temp, Register output, Label *fail)
     {
-        convertValueToInt(value, input, NULL, NULL, InvalidReg, temp, output, fail,
+        convertValueToInt(value, input, NULL, NULL, NULL, InvalidReg, temp, output, fail,
                           IntConversion_Truncate);
     }
     bool truncateValueToInt32(JSContext *cx, const Value &v, Register output, Label *fail) {
         return convertValueToInt(cx, v, output, fail, IntConversion_Truncate);
     }
     bool truncateConstantOrRegisterToInt32(JSContext *cx, ConstantOrRegister src, FloatRegister temp,
                                            Register output, Label *fail)
     {
@@ -1112,26 +1113,26 @@ class MacroAssembler : public MacroAssem
     }
 
     // Convenience functions for clamping values to uint8.
     void clampValueToUint8(ValueOperand value, FloatRegister temp, Register output, Label *fail) {
         convertValueToInt(value, temp, output, fail, IntConversion_ClampToUint8);
     }
     void clampValueToUint8(ValueOperand value, MDefinition *input,
                            Label *handleStringEntry, Label *handleStringRejoin,
-                           Register stringReg, FloatRegister temp, Register output,
-                           Label *fail)
+                           Label *truncateDoubleSlow,
+                           Register stringReg, FloatRegister temp, Register output, Label *fail)
     {
-        convertValueToInt(value, input, handleStringEntry, handleStringRejoin,
+        convertValueToInt(value, input, handleStringEntry, handleStringRejoin, truncateDoubleSlow,
                           stringReg, temp, output, fail, IntConversion_ClampToUint8);
     }
     void clampValueToUint8(ValueOperand value, MDefinition *input,
                            FloatRegister temp, Register output, Label *fail)
     {
-        convertValueToInt(value, input, NULL, NULL, InvalidReg, temp, output, fail,
+        convertValueToInt(value, input, NULL, NULL, NULL, InvalidReg, temp, output, fail,
                           IntConversion_ClampToUint8);
     }
     bool clampValueToUint8(JSContext *cx, const Value &v, Register output, Label *fail) {
         return convertValueToInt(cx, v, output, fail, IntConversion_ClampToUint8);
     }
     bool clampConstantOrRegisterToUint8(JSContext *cx, ConstantOrRegister src, FloatRegister temp,
                                         Register output, Label *fail)
     {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2589,17 +2589,19 @@ class MReturnFromCtor
     }
 };
 
 // Passes an MDefinition to an MCall. Must occur between an MPrepareCall and
 // MCall. Boxes the input and stores it to the correct location on stack.
 //
 // Arguments are *not* simply pushed onto a call stack: they are evaluated
 // left-to-right, but stored in the arg vector in C-style, right-to-left.
-class MPassArg : public MUnaryInstruction
+class MPassArg
+  : public MUnaryInstruction,
+    public NoFloatPolicy<0>
 {
     int32_t argnum_;
 
   private:
     MPassArg(MDefinition *def)
       : MUnaryInstruction(def), argnum_(-1)
     {
         setResultType(def->type());
@@ -2624,16 +2626,20 @@ class MPassArg : public MUnaryInstructio
     uint32_t getArgnum() const {
         JS_ASSERT(argnum_ >= 0);
         return (uint32_t)argnum_;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void printOpcode(FILE *fp) const;
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
 };
 
 // Converts a primitive (either typed or untyped) to a double. If the input is
 // not primitive at runtime, a bailout occurs.
 class MToDouble
   : public MUnaryInstruction,
     public ToDoublePolicy
 {
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -551,28 +551,16 @@ template bool ObjectPolicy<1>::staticAdj
 template bool ObjectPolicy<2>::staticAdjustInputs(MInstruction *ins);
 template bool ObjectPolicy<3>::staticAdjustInputs(MInstruction *ins);
 
 bool
 CallPolicy::adjustInputs(MInstruction *ins)
 {
     MCall *call = ins->toCall();
 
-    // External calls shouldn't have Float32 parameters
-    for (uint32_t i = 0, numArgs = call->numActualArgs(); i < numArgs; i++) {
-        MDefinition *arg = call->getArg(i+1); // arg 0 is |this|
-        if (arg->type() == MIRType_Float32) {
-            JS_ASSERT(arg->isPassArg()); // can't be a type barrier, as Float32 doesn't rely on type inference
-            MPassArg *passArg = arg->toPassArg();
-            MInstruction *replace = MToDouble::New(passArg->getArgument());
-            passArg->replaceOperand(0, replace);
-            call->block()->insertBefore(passArg, replace);
-        }
-    }
-
     MDefinition *func = call->getFunction();
     if (func->type() == MIRType_Object)
         return true;
 
     // If the function is impossible to call,
     // bail out by causing a subsequent unbox to fail.
     if (func->type() != MIRType_Value)
         func = boxAt(call, func);
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -170,17 +170,17 @@ class RuntimePolicy : public TypePolicy
         return Float32Policy<Op>::staticAdjustInputs(def);
     }
     void setPolicyType(MIRType type) {
         policyType_ = type;
     }
 };
 
 template <unsigned Op>
-class NoFloatPolicy
+class NoFloatPolicy : public TypePolicy
 {
   public:
     static bool staticAdjustInputs(MInstruction *def);
     bool adjustInputs(MInstruction *def) {
         return staticAdjustInputs(def);
     }
 };
 
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -670,21 +670,30 @@ class OutOfLineTruncateSlow : public Out
     FloatRegister src() const {
         return src_;
     }
     Register dest() const {
         return dest_;
     }
 };
 
+OutOfLineCode *
+CodeGeneratorShared::oolTruncateDouble(const FloatRegister &src, const Register &dest)
+{
+    OutOfLineTruncateSlow *ool = new OutOfLineTruncateSlow(src, dest);
+    if (!addOutOfLineCode(ool))
+        return NULL;
+    return ool;
+}
+
 bool
 CodeGeneratorShared::emitTruncateDouble(const FloatRegister &src, const Register &dest)
 {
-    OutOfLineTruncateSlow *ool = new OutOfLineTruncateSlow(src, dest);
-    if (!addOutOfLineCode(ool))
+    OutOfLineCode *ool = oolTruncateDouble(src, dest);
+    if (!ool)
         return false;
 
     masm.branchTruncateDouble(src, dest, ool->entry());
     masm.bind(ool->rejoin());
     return true;
 }
 
 bool
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -278,16 +278,17 @@ class CodeGeneratorShared : public LInst
 
     // Ensure that there is enough room between the last OSI point and the
     // current instruction, such that:
     //  (1) Invalidation will not overwrite the current instruction, and
     //  (2) Overwriting the current instruction will not overwrite
     //      an invalidation marker.
     void ensureOsiSpace();
 
+    OutOfLineCode *oolTruncateDouble(const FloatRegister &src, const Register &dest);
     bool emitTruncateDouble(const FloatRegister &src, const Register &dest);
 
     void emitPreBarrier(Register base, const LAllocation *index, MIRType type);
     void emitPreBarrier(Address address, MIRType type);
 
     inline bool isNextBlock(LBlock *block) {
         return (current->mir()->id() + 1 == block->mir()->id());
     }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6332,8 +6332,19 @@ JS_PreventExtensions(JSContext *cx, JS::
 {
     bool extensible;
     if (!JSObject::isExtensible(cx, obj, &extensible))
         return false;
     if (!extensible)
         return true;
     return JSObject::preventExtensions(cx, obj);
 }
+
+char *
+JSAutoByteString::encodeLatin1(ExclusiveContext *cx, JSString *str)
+{
+    JSLinearString *linear = str->ensureLinear(cx);
+    if (!linear)
+        return NULL;
+
+    mBytes = LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
+    return mBytes;
+}
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1354,38 +1354,16 @@ JS_BeginRequest(JSContext *cx);
 extern JS_PUBLIC_API(void)
 JS_EndRequest(JSContext *cx);
 
 extern JS_PUBLIC_API(bool)
 JS_IsInRequest(JSRuntime *rt);
 
 namespace js {
 
-inline bool
-IsPoisonedId(jsid iden)
-{
-    if (JSID_IS_STRING(iden))
-        return JS::IsPoisonedPtr(JSID_TO_STRING(iden));
-    if (JSID_IS_OBJECT(iden))
-        return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden));
-    return false;
-}
-
-template <> struct GCMethods<jsid>
-{
-    static jsid initial() { return JSID_VOID; }
-    static ThingRootKind kind() { return THING_ROOT_ID; }
-    static bool poisoned(jsid id) { return IsPoisonedId(id); }
-    static bool needsPostBarrier(jsid id) { return false; }
-#ifdef JSGC_GENERATIONAL
-    static void postBarrier(jsid *idp) {}
-    static void relocate(jsid *idp) {}
-#endif
-};
-
 void
 AssertHeapIsIdle(JSRuntime *rt);
 
 void
 AssertHeapIsIdle(JSContext *cx);
 
 } /* namespace js */
 
@@ -3844,17 +3822,17 @@ class JSAutoByteString
 
     char *encodeLatin1(JSContext *cx, JSString *str) {
         JS_ASSERT(!mBytes);
         JS_ASSERT(cx);
         mBytes = JS_EncodeString(cx, str);
         return mBytes;
     }
 
-    char *encodeLatin1(js::ContextFriendFields *cx, JSString *str);
+    char *encodeLatin1(js::ExclusiveContext *cx, JSString *str);
 
     char *encodeUtf8(JSContext *cx, JSString *str) {
         JS_ASSERT(!mBytes);
         JS_ASSERT(cx);
         mBytes = JS_EncodeStringToUTF8(cx, str);
         return mBytes;
     }
 
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -33,21 +33,20 @@ using namespace js::gc;
 
 using mozilla::ArrayEnd;
 using mozilla::ArrayLength;
 using mozilla::RangedPtr;
 
 const char *
 js::AtomToPrintableString(ExclusiveContext *cx, JSAtom *atom, JSAutoByteString *bytes)
 {
-    // The only uses for this method when running off the main thread are for
-    // parse errors/warnings, which will not actually be reported in such cases.
-    if (!cx->isJSContext())
-        return "";
-    return js_ValueToPrintable(cx->asJSContext(), StringValue(atom), bytes);
+    JSString *str = js_QuoteString(cx, atom, 0);
+    if (!str)
+        return NULL;
+    return bytes->encodeLatin1(cx, str);
 }
 
 const char * const js::TypeStrings[] = {
     js_undefined_str,
     js_object_str,
     js_function_str,
     js_string_str,
     js_number_str,
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -289,23 +289,23 @@ class ExclusiveContext : public ThreadSa
     friend class gc::ArenaLists;
     friend class AutoCompartment;
     friend class AutoLockForExclusiveAccess;
     friend struct StackBaseShape;
     friend void JSScript::initCompartment(ExclusiveContext *cx);
     friend class jit::IonContext;
 
     // The worker on which this context is running, if this is not a JSContext.
-    WorkerThread *workerThread;
+    WorkerThread *workerThread_;
 
   public:
 
     ExclusiveContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind)
       : ThreadSafeContext(rt, pt, kind),
-        workerThread(NULL),
+        workerThread_(NULL),
         enterCompartmentDepth_(0)
     {}
 
     /*
      * "Entering" a compartment changes cx->compartment (which changes
      * cx->global). Note that this does not push any StackFrame which means
      * that it is possible for cx->fp()->compartment() != cx->compartment.
      * This is not a problem since, in general, most places in the VM cannot
@@ -331,16 +331,17 @@ class ExclusiveContext : public ThreadSa
         return enterCompartmentDepth_;
     }
 #endif
 
     inline void enterCompartment(JSCompartment *c);
     inline void leaveCompartment(JSCompartment *oldCompartment);
 
     void setWorkerThread(WorkerThread *workerThread);
+    WorkerThread *workerThread() const { return workerThread_; }
 
     // If required, pause this thread until notified to continue by the main thread.
     inline void maybePause() const;
 
     // Threads with an ExclusiveContext may freely access any data in their
     // compartment and zone.
     JSCompartment *compartment() const {
         JS_ASSERT_IF(runtime_->isAtomsCompartment(compartment_),
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -347,18 +347,18 @@ GetNativeStackLimit(ThreadSafeContext *c
     }
     return cx->perThreadData->nativeStackLimit[kind];
 }
 
 inline void
 ExclusiveContext::maybePause() const
 {
 #ifdef JS_WORKER_THREADS
-    if (workerThread)
-        workerThread->maybePause();
+    if (workerThread())
+        workerThread()->maybePause();
 #endif
 }
 
 class AutoLockForExclusiveAccess
 {
 #ifdef JS_WORKER_THREADS
     JSRuntime *runtime;
 
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -727,17 +727,17 @@ Sprinter::realloc_(size_t newSize)
         return false;
     }
     base = newBuf;
     size = newSize;
     base[size - 1] = 0;
     return true;
 }
 
-Sprinter::Sprinter(JSContext *cx)
+Sprinter::Sprinter(ExclusiveContext *cx)
   : context(cx),
 #ifdef DEBUG
     initialized(false),
 #endif
     base(NULL), size(0), offset(0), reportedOOM(false)
 { }
 
 Sprinter::~Sprinter()
@@ -862,17 +862,17 @@ Sprinter::putString(JSString *s)
     size_t size = length;
     if (size == (size_t) -1)
         return -1;
 
     ptrdiff_t oldOffset = offset;
     char *buffer = reserve(size);
     if (!buffer)
         return -1;
-    DeflateStringToBuffer(context, chars, length, buffer, &size);
+    DeflateStringToBuffer(NULL, chars, length, buffer, &size);
     buffer[size] = 0;
 
     return oldOffset;
 }
 
 int
 Sprinter::printf(const char *fmt, ...)
 {
@@ -1018,24 +1018,25 @@ QuoteString(Sprinter *sp, JSString *str,
      */
     if (offset == sp->getOffset() && Sprint(sp, "") < 0)
         return NULL;
 
     return sp->stringAt(offset);
 }
 
 JSString *
-js_QuoteString(JSContext *cx, JSString *str, jschar quote)
+js_QuoteString(ExclusiveContext *cx, JSString *str, jschar quote)
 {
     Sprinter sprinter(cx);
     if (!sprinter.init())
         return NULL;
     char *bytes = QuoteString(&sprinter, str, quote);
-    JSString *escstr = bytes ? JS_NewStringCopyZ(cx, bytes) : NULL;
-    return escstr;
+    if (!bytes)
+        return NULL;
+    return js_NewStringCopyZ<CanGC>(cx, bytes);
 }
 
 /************************************************************************/
 
 static int ReconstructPCStack(JSContext*, JSScript*, jsbytecode*, jsbytecode**);
 
 static unsigned
 StackDepth(JSScript *script)
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -228,17 +228,17 @@ extern const char       js_EscapeMap[];
 #endif
 
 /*
  * Return a GC'ed string containing the chars in str, with any non-printing
  * chars or quotes (' or " as specified by the quote argument) escaped, and
  * with the quote character at the beginning and end of the result string.
  */
 extern JSString *
-js_QuoteString(JSContext *cx, JSString *str, jschar quote);
+js_QuoteString(js::ExclusiveContext *cx, JSString *str, jschar quote);
 
 namespace js {
 
 static inline bool
 IsJumpOpcode(JSOp op)
 {
     uint32_t type = JOF_TYPE(js_CodeSpec[op].format);
 
@@ -417,32 +417,32 @@ class Sprinter
             parent->checkInvariants();
         }
 
         ~InvariantChecker() {
             parent->checkInvariants();
         }
     };
 
-    JSContext               *context;       /* context executing the decompiler */
+    ExclusiveContext        *context;       /* context executing the decompiler */
 
   private:
     static const size_t     DefaultSize;
 #ifdef DEBUG
     bool                    initialized;    /* true if this is initialized, use for debug builds */
 #endif
     char                    *base;          /* malloc'd buffer address */
     size_t                  size;           /* size of buffer allocated at base */
     ptrdiff_t               offset;         /* offset of next free char in buffer */
     bool                    reportedOOM;    /* this sprinter has reported OOM in string ops */
 
     bool realloc_(size_t newSize);
 
   public:
-    explicit Sprinter(JSContext *cx);
+    explicit Sprinter(ExclusiveContext *cx);
     ~Sprinter();
 
     /* Initialize this sprinter, returns false on error */
     bool init();
 
     void checkInvariants() const;
 
     const char *string() const;
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -261,17 +261,17 @@ InflateStringToBuffer(JSContext *maybecx
 
 /*
  * Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for
  * 'length chars. The buffer is NOT null-terminated. The destination length
  * must to be initialized with the buffer size and will contain on return the
  * number of copied bytes.
  */
 extern bool
-DeflateStringToBuffer(JSContext *cx, const jschar *chars,
+DeflateStringToBuffer(JSContext *maybecx, const jschar *chars,
                       size_t charsLength, char *bytes, size_t *length);
 
 /*
  * The String.prototype.replace fast-native entry point is exported for joined
  * function optimization in js{interp,tracer}.cpp.
  */
 extern bool
 str_replace(JSContext *cx, unsigned argc, js::Value *vp);
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -716,27 +716,27 @@ WorkerThread::handleIonWorkload(WorkerTh
     // this incorporation can be delayed indefinitely without affecting
     // performance as long as the main thread is actually executing Ion code.
     runtime->triggerOperationCallback(JSRuntime::TriggerCallbackAnyThreadDontStopIon);
 }
 
 void
 ExclusiveContext::setWorkerThread(WorkerThread *workerThread)
 {
-    this->workerThread = workerThread;
-    this->perThreadData = workerThread->threadData.addr();
+    workerThread_ = workerThread;
+    perThreadData = workerThread->threadData.addr();
 }
 
 frontend::CompileError &
 ExclusiveContext::addPendingCompileError()
 {
     frontend::CompileError *error = js_new<frontend::CompileError>();
     if (!error)
         MOZ_CRASH();
-    if (!workerThread->parseTask->errors.append(error))
+    if (!workerThread()->parseTask->errors.append(error))
         MOZ_CRASH();
     return *error;
 }
 
 void
 WorkerThread::handleParseWorkload(WorkerThreadState &state)
 {
     JS_ASSERT(state.isLocked());
@@ -824,19 +824,35 @@ WorkerThreadState::compressionInProgress
 bool
 SourceCompressionTask::complete()
 {
     JS_ASSERT_IF(!ss, !chars);
     if (active()) {
         WorkerThreadState &state = *cx->workerThreadState();
         AutoLockWorkerThreadState lock(state);
 
+        // If this compression task is itself being completed on a worker
+        // thread, treat the thread as paused while waiting for the completion.
+        // Otherwise we will not wake up and mark this as paused due to the
+        // loop in AutoPauseWorkersForGC.
+        if (cx->workerThread()) {
+            state.numPaused++;
+            if (state.numPaused == state.numThreads)
+                state.notify(WorkerThreadState::MAIN);
+        }
+
         while (state.compressionInProgress(this))
             state.wait(WorkerThreadState::MAIN);
 
+        if (cx->workerThread()) {
+            state.numPaused--;
+            if (state.shouldPause)
+                cx->workerThread()->pause();
+        }
+
         ss->ready_ = true;
 
         // Update memory accounting.
         if (!oom)
             cx->updateMallocCounter(ss->computedSizeOfData());
 
         ss = NULL;
         chars = NULL;
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -439,19 +439,17 @@ class GlobalObject : public JSObject
 
     bool getIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue value) {
         RootedObject holder(cx, intrinsicsHolder());
         RootedId id(cx, NameToId(name));
         if (HasDataProperty(cx, holder, id, value.address()))
             return true;
         if (!cx->runtime()->cloneSelfHostedValue(cx, name, value))
             return false;
-        mozilla::DebugOnly<bool> ok = JS_DefinePropertyById(cx, holder, id, value, NULL, NULL, 0);
-        JS_ASSERT(ok);
-        return true;
+        return JS_DefinePropertyById(cx, holder, id, value, NULL, NULL, 0);
     }
 
     bool setIntrinsicValue(JSContext *cx, PropertyName *name, HandleValue value) {
 #ifdef DEBUG
         RootedObject self(cx, this);
         JS_ASSERT(cx->runtime()->isSelfHostingGlobal(self));
 #endif
         RootedObject holder(cx, intrinsicsHolder());
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1558,65 +1558,65 @@ GetCompartmentName(JSCompartment *c, nsC
             name.ReplaceChar('/', '\\');
     } else {
         name.AssignLiteral("null-principal");
     }
 }
 
 // Telemetry relies on this being a uni-reporter (rather than part of the "js"
 // reporter).
-class JSGCHeapReporter MOZ_FINAL : public MemoryUniReporter
+class JSMainRuntimeGCHeapReporter MOZ_FINAL : public MemoryUniReporter
 {
 public:
-    JSGCHeapReporter()
-      : MemoryUniReporter("js-gc-heap", KIND_OTHER, UNITS_BYTES,
-"Memory used by the garbage-collected JavaScript heap.")
+    JSMainRuntimeGCHeapReporter()
+      : MemoryUniReporter("js-main-runtime-gc-heap", KIND_OTHER, UNITS_BYTES,
+"Memory used by the garbage-collected heap in the main JSRuntime.")
     {}
 private:
     int64_t Amount() MOZ_OVERRIDE
     {
         JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
         return int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
                js::gc::ChunkSize;
     }
 };
 
-// Nb: js-compartments/system + js-compartments/user could be different to the
-// number of compartments reported by JSReporter if a garbage collection
-// occurred between them being consulted.  We could move these reporters into
-// JSReporter to avoid that problem, but then we couldn't easily report them
-// via telemetry, so we live with the small risk of inconsistencies.
-
-class JSCompartmentsSystemReporter MOZ_FINAL : public MemoryUniReporter
+// Nb: js-main-runtime-compartments/system + js-main-runtime-compartments/user
+// could be different to the number of compartments reported by JSReporter if a
+// garbage collection occurred between them being consulted.  We could move
+// these reporters into JSReporter to avoid that problem, but then we couldn't
+// easily report them via telemetry, so we live with the small risk of
+// inconsistencies.
+
+class RedundantJSMainRuntimeCompartmentsSystemReporter MOZ_FINAL : public MemoryUniReporter
 {
 public:
-    JSCompartmentsSystemReporter()
-      : MemoryUniReporter("js-compartments/system", KIND_OTHER, UNITS_COUNT,
-"The number of JavaScript compartments for system code.  The sum of this and "
-"'js-compartments/user' might not match the number of compartments listed "
-"in the 'explicit' tree if a garbage collection occurs at an inopportune "
-"time, but such cases should be rare.")
+    // An empty description is ok because this is a "redundant/"-prefixed
+    // reporter and so is ignored by about:memory.
+    RedundantJSMainRuntimeCompartmentsSystemReporter()
+      : MemoryUniReporter("redundant/js-main-runtime-compartments/system",
+                          KIND_OTHER, UNITS_COUNT, "")
     {}
 private:
     int64_t Amount() MOZ_OVERRIDE
     {
         JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
         return JS::SystemCompartmentCount(rt);
     }
 };
 
-class JSCompartmentsUserReporter MOZ_FINAL : public MemoryUniReporter
+class RedundantJSMainRuntimeCompartmentsUserReporter MOZ_FINAL : public MemoryUniReporter
 {
 public:
-    JSCompartmentsUserReporter()
-      : MemoryUniReporter("js-compartments/user", KIND_OTHER, UNITS_COUNT,
-"The number of JavaScript compartments for user code.  The sum of this and "
-"'js-compartments/system' might not match the number of compartments listed "
-"under 'js' if a garbage collection occurs at an inopportune time, but such "
-"cases should be rare.")
+    // An empty description is ok because this is a "redundant/"-prefixed
+    // reporter and so is ignored by about:memory.
+    RedundantJSMainRuntimeCompartmentsUserReporter()
+      : MemoryUniReporter("redundant/js-main-runtime-compartments/user",
+                          KIND_OTHER, UNITS_COUNT,
+"The number of JavaScript compartments for user code in the main JSRuntime.")
     {}
 private:
     int64_t Amount() MOZ_OVERRIDE
     {
         JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
         return JS::UserCompartmentCount(rt);
     }
 };
@@ -2355,36 +2355,36 @@ ReportJSRuntimeExplicitTreeStats(const J
       do_GetService("@mozilla.org/addons/integration;1");
     return ReportJSRuntimeExplicitTreeStats(rtStats, rtPath, am.get(), cb,
                                             closure, rtTotalOut);
 }
 
 
 } // namespace xpc
 
-class JSCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
+class JSMainRuntimeCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
 {
   public:
     NS_DECL_THREADSAFE_ISUPPORTS
 
     NS_IMETHOD GetName(nsACString &name) {
-        name.AssignLiteral("compartments");
+        name.AssignLiteral("js-main-runtime-compartments");
         return NS_OK;
     }
 
     typedef js::Vector<nsCString, 0, js::SystemAllocPolicy> Paths;
 
     static void CompartmentCallback(JSRuntime *rt, void* data, JSCompartment *c) {
         // silently ignore OOM errors
         Paths *paths = static_cast<Paths *>(data);
         nsCString path;
         GetCompartmentName(c, path, true);
         path.Insert(js::IsSystemCompartment(c)
-                    ? NS_LITERAL_CSTRING("compartments/system/")
-                    : NS_LITERAL_CSTRING("compartments/user/"),
+                    ? NS_LITERAL_CSTRING("js-main-runtime-compartments/system/")
+                    : NS_LITERAL_CSTRING("js-main-runtime-compartments/user/"),
                     0);
         paths->append(path);
     }
 
     NS_IMETHOD CollectReports(nsIMemoryReporterCallback *cb,
                               nsISupports *closure)
     {
         // First we collect the compartment paths.  Then we report them.  Doing
@@ -2395,23 +2395,24 @@ class JSCompartmentsReporter MOZ_FINAL :
 
         Paths paths;
         JS_IterateCompartments(nsXPConnect::GetRuntimeInstance()->Runtime(),
                                &paths, CompartmentCallback);
 
         // Report.
         for (size_t i = 0; i < paths.length(); i++)
             // These ones don't need a description, hence the "".
-            REPORT(nsCString(paths[i]), KIND_OTHER, UNITS_COUNT, 1, "");
+            REPORT(nsCString(paths[i]), KIND_OTHER, UNITS_COUNT, 1,
+                   "A live compartment in the main JSRuntime.");
 
         return NS_OK;
     }
 };
 
-NS_IMPL_ISUPPORTS1(JSCompartmentsReporter, nsIMemoryReporter)
+NS_IMPL_ISUPPORTS1(JSMainRuntimeCompartmentsReporter, nsIMemoryReporter)
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(OrphanMallocSizeOf)
 
 namespace xpc {
 
 static size_t
 SizeOfTreeIncludingThis(nsINode *tree)
 {
@@ -3039,21 +3040,21 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
     JS_SetSourceHook(runtime, SourceHook);
 
     // Set up locale information and callbacks for the newly-created runtime so
     // that the various toLocaleString() methods, localeCompare(), and other
     // internationalization APIs work as desired.
     if (!xpc_LocalizeRuntime(runtime))
         NS_RUNTIMEABORT("xpc_LocalizeRuntime failed.");
 
-    NS_RegisterMemoryReporter(new JSGCHeapReporter());
-    NS_RegisterMemoryReporter(new JSCompartmentsSystemReporter());
-    NS_RegisterMemoryReporter(new JSCompartmentsUserReporter());
+    NS_RegisterMemoryReporter(new JSMainRuntimeGCHeapReporter());
+    NS_RegisterMemoryReporter(new RedundantJSMainRuntimeCompartmentsSystemReporter());
+    NS_RegisterMemoryReporter(new RedundantJSMainRuntimeCompartmentsUserReporter());
     NS_RegisterMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
-    NS_RegisterMemoryReporter(new JSCompartmentsReporter);
+    NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsReporter);
 
     // Install a JavaScript 'debugger' keyword handler in debug builds only
 #ifdef DEBUG
     if (!JS_GetGlobalDebugHooks(runtime)->debuggerHandler)
         xpc_InstallJSDebuggerKeywordHandler(runtime);
 #endif
 }
 
--- a/js/xpconnect/src/event_impl_gen.conf.in
+++ b/js/xpconnect/src/event_impl_gen.conf.in
@@ -5,17 +5,16 @@
 
  The name of the event which real interface should have nsIDOM-prefix,
  and should be in nsIDOM<name>.idl file and which should have
  <name>Init dictionary for the event constructor. """
 
 simple_events = [
     'ProgressEvent',
     'StorageEvent',
-    'DeviceProximityEvent',
     'MozSettingsEvent',
     'UserProximityEvent',
     'CustomEvent',
     'PageTransitionEvent',
     'DOMTransactionEvent',
     'PopStateEvent',
     'HashChangeEvent',
     'CloseEvent',
@@ -47,21 +46,16 @@ simple_events = [
     'MozSmsEvent',
     'MozMmsEvent',
 #ifdef MOZ_WEBSPEECH
     'SpeechSynthesisEvent',
 #endif
     'DeviceStorageChangeEvent',
     'PopupBlockedEvent',
     'RecordErrorEvent',
-#ifdef MOZ_GAMEPAD
-    'GamepadEvent',
-    'GamepadButtonEvent',
-    'GamepadAxisMoveEvent',
-#endif
 #ifdef MOZ_WEBSPEECH
     'SpeechRecognitionEvent',
 #endif
   ]
 
 """ include file names """
 special_includes = [
     'nsContentUtils.h',
@@ -77,11 +71,10 @@ exclude_automatic_type_include = [
   ]
 
 """ Map xpidl interface names to implementation classes. The third column is the canonical interface. """
 xpidl_to_native = [
     ['nsIDOMBluetoothDevice', 'bluetooth::BluetoothDevice', 'nsIDOMBluetoothDevice'],
     ['nsIDOMDocument', 'nsIDocument', 'nsIDocument'],
     ['nsIDOMElement', 'mozilla::dom::Element', 'mozilla::dom::Element'],
     ['nsIDOMCSSStyleSheet', 'nsCSSStyleSheet', 'nsIStyleSheet'],
-    ['nsIDOMGamepad', 'Gamepad', 'nsIDOMGamepad']
   ]
 
--- a/js/xpconnect/tests/chrome/test_bug732665.xul
+++ b/js/xpconnect/tests/chrome/test_bug732665.xul
@@ -54,16 +54,23 @@ https://bugzilla.mozilla.org/show_bug.cg
   chromeSb.ok = contentSb.ok = ok;
   Cu.evalInSandbox(nearNativeStackLimit.toSource(), chromeSb);
   Cu.evalInSandbox(nearNativeStackLimit.toSource(), contentSb);
   var chromeLimit = Cu.evalInSandbox("nearNativeStackLimit(0);", chromeSb);
   var contentLimit = Cu.evalInSandbox("nearNativeStackLimit(0)", contentSb);
   ok(chromeLimit >= contentLimit + 10,
      "Chrome should be able to have at least 10 heavy frames more stack than content: " + chromeLimit + ", " + contentLimit);
 
-  // Exhaust the stack space in content, and then make sure we can still get 10 heavy frames in chrome.
+  // Exhaust the stack space in content, and then make sure we can still get 10
+  // heavy frames in chrome.
+  //
+  // Note that sometimes, if we pass |0| to nearNativeStackLimit, we can end up
+  // so close to the border in content that we can't even get ourselves together
+  // enough to make the cross-compartment call. So rather than exhausting the
+  // stack entirely and then checking for 10 chrome frames, we leave ourselves
+  // one frame's worth, and check for 11.
   contentSb.nnslChrome = chromeSb.nearNativeStackLimit;
-  var nestedLimit = Cu.evalInSandbox("nearNativeStackLimit(0, function() { nestedLimit = nnslChrome(0);}); nestedLimit;", contentSb);
-  ok(nestedLimit >= 10, "Chrome should be invokable from content script with an exhausted stack: " + nestedLimit);
+  var nestedLimit = Cu.evalInSandbox("nearNativeStackLimit(1, function() { nestedLimit = nnslChrome(0);}); nestedLimit;", contentSb);
+  ok(nestedLimit >= 11, "Chrome should be invokable from content script with an exhausted stack: " + nestedLimit);
 
   ]]>
   </script>
 </window>
--- a/layout/generic/StickyScrollContainer.cpp
+++ b/layout/generic/StickyScrollContainer.cpp
@@ -36,23 +36,27 @@ StickyScrollContainer::StickyScrollConta
 
 StickyScrollContainer::~StickyScrollContainer()
 {
   mScrollFrame->RemoveScrollPositionListener(this);
 }
 
 // static
 StickyScrollContainer*
-StickyScrollContainer::StickyScrollContainerForFrame(nsIFrame* aFrame)
+StickyScrollContainer::GetStickyScrollContainerForFrame(nsIFrame* aFrame)
 {
   nsIScrollableFrame* scrollFrame =
     nsLayoutUtils::GetNearestScrollableFrame(aFrame->GetParent(),
       nsLayoutUtils::SCROLLABLE_SAME_DOC |
       nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
-  NS_ASSERTION(scrollFrame, "Need a scrolling container");
+  if (!scrollFrame) {
+    // We might not find any, for instance in the case of
+    // <html style="position: fixed">
+    return nullptr;
+  }
   FrameProperties props = static_cast<nsIFrame*>(do_QueryFrame(scrollFrame))->
     Properties();
   StickyScrollContainer* s = static_cast<StickyScrollContainer*>
     (props.Get(StickyScrollContainerProperty()));
   if (!s) {
     s = new StickyScrollContainer(scrollFrame);
     props.Set(StickyScrollContainerProperty(), s);
   }
@@ -85,18 +89,17 @@ void
 StickyScrollContainer::ComputeStickyOffsets(nsIFrame* aFrame)
 {
   nsIScrollableFrame* scrollableFrame =
     nsLayoutUtils::GetNearestScrollableFrame(aFrame->GetParent(),
       nsLayoutUtils::SCROLLABLE_SAME_DOC |
       nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
 
   if (!scrollableFrame) {
-    // Not sure how this would happen, but bail if it does.
-    NS_ERROR("Couldn't find a scrollable frame");
+    // Bail.
     return;
   }
 
   nsSize scrollContainerSize = scrollableFrame->GetScrolledFrame()->
     GetContentRectRelativeToSelf().Size();
 
   nsMargin computedOffsets;
   const nsStylePosition* position = aFrame->StylePosition();
@@ -108,34 +111,34 @@ StickyScrollContainer::ComputeStickyOffs
   computedOffsets.top    = ComputeStickySideOffset(eSideTop, position->mOffset,
                                                    scrollContainerSize.height);
   computedOffsets.bottom = ComputeStickySideOffset(eSideBottom, position->mOffset,
                                                    scrollContainerSize.height);
 
   // Store the offset
   FrameProperties props = aFrame->Properties();
   nsMargin* offsets = static_cast<nsMargin*>
-    (props.Get(nsIFrame::ComputedStickyOffsetProperty()));
+    (props.Get(nsIFrame::ComputedOffsetProperty()));
   if (offsets) {
     *offsets = computedOffsets;
   } else {
-    props.Set(nsIFrame::ComputedStickyOffsetProperty(),
+    props.Set(nsIFrame::ComputedOffsetProperty(),
               new nsMargin(computedOffsets));
   }
 }
 
 void
 StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame, nsRect* aStick,
                                            nsRect* aContain) const
 {
   aStick->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
   aContain->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
 
   const nsMargin* computedOffsets = static_cast<nsMargin*>(
-    aFrame->Properties().Get(nsIFrame::ComputedStickyOffsetProperty()));
+    aFrame->Properties().Get(nsIFrame::ComputedOffsetProperty()));
   if (!computedOffsets) {
     // We haven't reflowed the scroll frame yet, so offsets haven't been
     // computed. Bail.
     return;
   }
 
   nsIFrame* scrolledFrame = mScrollFrame->GetScrolledFrame();
   nsIFrame* cbFrame = aFrame->GetContainingBlock();
--- a/layout/generic/StickyScrollContainer.h
+++ b/layout/generic/StickyScrollContainer.h
@@ -21,20 +21,20 @@ class nsIFrame;
 class nsIScrollableFrame;
 
 namespace mozilla {
 
 class StickyScrollContainer MOZ_FINAL : public nsIScrollPositionListener
 {
 public:
   /**
-   * Find the StickyScrollContainer associated with the scroll container of
-   * the given frame, creating it if necessary.
+   * Find (and create if necessary) the StickyScrollContainer associated with
+   * the scroll container of the given frame, if a scroll container exists.
    */
-  static StickyScrollContainer* StickyScrollContainerForFrame(nsIFrame* aFrame);
+  static StickyScrollContainer* GetStickyScrollContainerForFrame(nsIFrame* aFrame);
 
   /**
    * Find the StickyScrollContainer associated with the given scroll frame,
    * if it exists.
    */
   static StickyScrollContainer* GetStickyScrollContainerForScrollFrame(nsIFrame* aScrollFrame);
 
   void AddFrame(nsIFrame* aFrame) {
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/914891.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html style="position: fixed;">
+<head>
+<meta charset="UTF-8">
+</head>
+<body>
+<div style="position: sticky;"></div>
+</body>
+</html>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -495,8 +495,9 @@ load 849603.html
 test-pref(layout.css.flexbox.enabled,true) load 851396-1.html
 test-pref(layout.css.flexbox.enabled,true) load 854263-1.html
 test-pref(layout.css.flexbox.enabled,true) load 862947-1.html
 needs-focus pref(accessibility.browsewithcaret,true) load 868906.html
 test-pref(layout.css.flexbox.enabled,true) load 866547-1.html
 asserts(1-4) test-pref(layout.css.flexbox.enabled,true) load 876074-1.html # bug 876749
 load 885009-1.html
 load 893523.html
+test-pref(layout.css.sticky.enabled,true) load 914891.html
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -2577,35 +2577,31 @@ nsBlockFrame::SlideLine(nsBlockReflowSta
   // Adjust the frames in the line
   nsIFrame* kid = aLine->mFirstChild;
   if (!kid) {
     return;
   }
 
   if (aLine->IsBlock()) {
     if (aDY) {
-      nsPoint p = kid->GetPosition();
-      p.y += aDY;
-      kid->SetPosition(p);
+      kid->MovePositionBy(nsPoint(0, aDY));
     }
 
     // Make sure the frame's view and any child views are updated
     ::PlaceFrameView(kid);
   }
   else {
     // Adjust the Y coordinate of the frames in the line.
     // Note: we need to re-position views even if aDY is 0, because
     // one of our parent frames may have moved and so the view's position
     // relative to its parent may have changed
     int32_t n = aLine->GetChildCount();
     while (--n >= 0) {
       if (aDY) {
-        nsPoint p = kid->GetPosition();
-        p.y += aDY;
-        kid->SetPosition(p);
+        kid->MovePositionBy(nsPoint(0, aDY));
       }
       // Make sure the frame's view and any child views are updated
       ::PlaceFrameView(kid);
       kid = kid->GetNextSibling();
     }
   }
 }
 
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -381,18 +381,17 @@ nsBlockReflowState::RecoverFloats(nsLine
 {
   if (aLine->HasFloats()) {
     // Place the floats into the space-manager again. Also slide
     // them, just like the regular frames on the line.
     nsFloatCache* fc = aLine->GetFirstFloat();
     while (fc) {
       nsIFrame* floatFrame = fc->mFloat;
       if (aDeltaY != 0) {
-        nsPoint p = floatFrame->GetPosition();
-        floatFrame->SetPosition(nsPoint(p.x, p.y + aDeltaY));
+        floatFrame->MovePositionBy(nsPoint(0, aDeltaY));
         nsContainerFrame::PositionFrameView(floatFrame);
         nsContainerFrame::PositionChildViews(floatFrame);
       }
 #ifdef DEBUG
       if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) {
         nscoord tx, ty;
         mFloatManager->GetTranslation(tx, ty);
         nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -1092,36 +1092,16 @@ nsFlexContainerFrame::SortChildrenIfNeed
 
 /* virtual */
 nsIAtom*
 nsFlexContainerFrame::GetType() const
 {
   return nsGkAtoms::flexContainerFrame;
 }
 
-/* virtual */
-int
-nsFlexContainerFrame::GetSkipSides(const nsHTMLReflowState* aReflowState) const
-{
-  // (same as nsBlockFrame's GetSkipSides impl)
-  if (IS_TRUE_OVERFLOW_CONTAINER(this)) {
-    return (1 << NS_SIDE_TOP) | (1 << NS_SIDE_BOTTOM);
-  }
-
-  int skip = 0;
-  if (GetPrevInFlow()) {
-    skip |= 1 << NS_SIDE_TOP;
-  }
-  nsIFrame* nif = GetNextInFlow();
-  if (nif && !IS_TRUE_OVERFLOW_CONTAINER(nif)) {
-    skip |= 1 << NS_SIDE_BOTTOM;
-  }
-  return skip;
-}
-
 #ifdef DEBUG
 NS_IMETHODIMP
 nsFlexContainerFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("FlexContainer"), aResult);
 }
 #endif // DEBUG
 
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -44,17 +44,16 @@ public:
                     nsReflowStatus&          aStatus) MOZ_OVERRIDE;
 
   virtual nscoord
     GetMinWidth(nsRenderingContext* aRenderingContext) MOZ_OVERRIDE;
   virtual nscoord
     GetPrefWidth(nsRenderingContext* aRenderingContext) MOZ_OVERRIDE;
 
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
-  virtual int GetSkipSides(const nsHTMLReflowState* aReflowState = nullptr) const MOZ_OVERRIDE;
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif // DEBUG
   // Flexbox-specific public methods
   bool IsHorizontal();
 
 protected:
   // Protected constructor & destructor
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -507,17 +507,21 @@ nsFrame::Init(nsIContent*      aContent,
   }
   const nsStyleDisplay *disp = StyleDisplay();
   if (disp->HasTransform(this)) {
     // The frame gets reconstructed if we toggle the -moz-transform
     // property, so we can set this bit here and then ignore it.
     mState |= NS_FRAME_MAY_BE_TRANSFORMED;
   }
   if (disp->mPosition == NS_STYLE_POSITION_STICKY) {
-    StickyScrollContainer::StickyScrollContainerForFrame(this)->AddFrame(this);
+    StickyScrollContainer* ssc =
+      StickyScrollContainer::GetStickyScrollContainerForFrame(this);
+    if (ssc) {
+      ssc->AddFrame(this);
+    }
   }
 
   if (nsLayoutUtils::FontSizeInflationEnabled(PresContext()) || !GetParent()
 #ifdef DEBUG
       // We have assertions that check inflation invariants even when
       // font size inflation is not enabled.
       || true
 #endif
@@ -588,18 +592,21 @@ nsFrame::DestroyFrom(nsIFrame* aDestruct
   NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(),
                "Frames should be removed before destruction.");
   NS_ASSERTION(aDestructRoot, "Must specify destruct root");
   MOZ_ASSERT(!HasAbsolutelyPositionedChildren());
 
   nsSVGEffects::InvalidateDirectRenderingObservers(this);
 
   if (StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) {
-    StickyScrollContainer::StickyScrollContainerForFrame(this)->
-      RemoveFrame(this);
+    StickyScrollContainer* ssc =
+      StickyScrollContainer::GetStickyScrollContainerForFrame(this);
+    if (ssc) {
+      ssc->RemoveFrame(this);
+    }
   }
 
   // Get the view pointer now before the frame properties disappear
   // when we call NotifyDestroyingFrame()
   nsView* view = GetView();
   nsPresContext* presContext = PresContext();
 
   nsIPresShell *shell = presContext->GetPresShell();
@@ -5058,16 +5065,32 @@ ComputeOutlineAndEffectsRect(nsIFrame* a
         Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
     }
     r = nsSVGIntegrationUtils::ComputePostEffectsVisualOverflowRect(aFrame, r);
   }
 
   return r;
 }
 
+void
+nsIFrame::MovePositionBy(const nsPoint& aTranslation)
+{
+  nsPoint position = GetNormalPosition() + aTranslation;
+
+  const nsMargin* computedOffsets = nullptr;
+  if (IsRelativelyPositioned()) {
+    computedOffsets = static_cast<nsMargin*>
+      (Properties().Get(nsIFrame::ComputedOffsetProperty()));
+  }
+  nsHTMLReflowState::ApplyRelativePositioning(this, computedOffsets ?
+                                              *computedOffsets : nsMargin(),
+                                              &position);
+  SetPosition(position);
+}
+
 nsPoint
 nsIFrame::GetNormalPosition() const
 {
   // It might be faster to first check
   // StyleDisplay()->IsRelativelyPositionedStyle().
   nsPoint* normalPosition = static_cast<nsPoint*>
     (Properties().Get(NormalPositionProperty()));
   if (normalPosition) {
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -826,16 +826,27 @@ nsHTMLReflowState::ComputeRelativeOffset
     // 'Top' isn't 'auto' so compute its value
     aComputedOffsets.top = nsLayoutUtils::
       ComputeHeightDependentValue(aContainingBlockHeight,
                                   position->mOffset.GetTop());
 
     // Computed value for 'bottom' is minus the value of 'top'
     aComputedOffsets.bottom = -aComputedOffsets.top;
   }
+
+  // Store the offset
+  FrameProperties props = aFrame->Properties();
+  nsMargin* offsets = static_cast<nsMargin*>
+    (props.Get(nsIFrame::ComputedOffsetProperty()));
+  if (offsets) {
+    *offsets = aComputedOffsets;
+  } else {
+    props.Set(nsIFrame::ComputedOffsetProperty(),
+              new nsMargin(aComputedOffsets));
+  }
 }
 
 /* static */ void
 nsHTMLReflowState::ApplyRelativePositioning(nsIFrame* aFrame,
                                             const nsMargin& aComputedOffsets,
                                             nsPoint* aPosition)
 {
   // Store the normal position
@@ -847,18 +858,21 @@ nsHTMLReflowState::ApplyRelativePosition
   } else {
     props.Set(nsIFrame::NormalPositionProperty(), new nsPoint(*aPosition));
   }
 
   const nsStyleDisplay* display = aFrame->StyleDisplay();
   if (NS_STYLE_POSITION_RELATIVE == display->mPosition) {
     *aPosition += nsPoint(aComputedOffsets.left, aComputedOffsets.top);
   } else if (NS_STYLE_POSITION_STICKY == display->mPosition) {
-    *aPosition = StickyScrollContainer::StickyScrollContainerForFrame(aFrame)->
-      ComputePosition(aFrame);
+    StickyScrollContainer* ssc =
+      StickyScrollContainer::GetStickyScrollContainerForFrame(aFrame);
+    if (ssc) {
+      *aPosition = ssc->ComputePosition(aFrame);
+    }
   }
 }
 
 nsIFrame*
 nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame* aFrame,
                                                nscoord& aCBLeftEdge,
                                                nscoord& aCBWidth)
 {
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -862,16 +862,23 @@ public:
     }
   }
   void SetSize(const nsSize& aSize) {
     SetRect(nsRect(mRect.TopLeft(), aSize));
   }
   void SetPosition(const nsPoint& aPt) { mRect.MoveTo(aPt); }
 
   /**
+   * Move the frame, accounting for relative positioning. Use this when
+   * adjusting the frame's position by a known amount, to properly update its
+   * saved normal position (see GetNormalPosition below).
+   */
+  void MovePositionBy(const nsPoint& aTranslation);
+
+  /**
    * Return frame's position without relative positioning
    */
   nsPoint GetNormalPosition() const;
 
   virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
   { return aChild->GetPosition(); }
   
   nsPoint GetPositionIgnoringScrolling() {
@@ -922,17 +929,17 @@ public:
     static NS_PROPERTY_DESCRIPTOR_CONST FramePropertyDescriptor descriptor = { nullptr, dtor }; \
     return &descriptor;                                                                        \
   }
 
   NS_DECLARE_FRAME_PROPERTY(IBSplitSpecialSibling, nullptr)
   NS_DECLARE_FRAME_PROPERTY(IBSplitSpecialPrevSibling, nullptr)
 
   NS_DECLARE_FRAME_PROPERTY(NormalPositionProperty, DestroyPoint)
-  NS_DECLARE_FRAME_PROPERTY(ComputedStickyOffsetProperty, DestroyMargin)
+  NS_DECLARE_FRAME_PROPERTY(ComputedOffsetProperty, DestroyMargin)
 
   NS_DECLARE_FRAME_PROPERTY(OutlineInnerRectProperty, DestroyRect)
   NS_DECLARE_FRAME_PROPERTY(PreEffectsBBoxProperty, DestroyRect)
   NS_DECLARE_FRAME_PROPERTY(PreTransformOverflowAreasProperty,
                             DestroyOverflowAreas)
 
   // The initial overflow area passed to FinishAndStoreOverflow. This is only set
   // on frames that Preserve3D(), and when at least one of the overflow areas
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -911,18 +911,16 @@ nsInlineFrame::AccessibleType()
 {
   // Broken image accessibles are created here, because layout
   // replaces the image or image control frame with an inline frame
   nsIAtom *tagAtom = mContent->Tag();
   if (tagAtom == nsGkAtoms::input)  // Broken <input type=image ... />
     return a11y::eHTMLButtonType;
   if (tagAtom == nsGkAtoms::img)  // Create accessible for broken <img>
     return a11y::eHyperTextType;
-  if (tagAtom == nsGkAtoms::label)  // Creat accessible for <label>
-    return a11y::eHTMLLabelType;
 
   return a11y::eNoType;
 }
 #endif
 
 //////////////////////////////////////////////////////////////////////
 
 // nsLineFrame implementation
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -2191,19 +2191,17 @@ nsLineLayout::VerticalAlignFrames(PerSpa
   }
   if (maxBottomBoxHeight > mMaxBottomBoxHeight) {
     mMaxBottomBoxHeight = maxBottomBoxHeight;
   }
 }
 
 static void SlideSpanFrameRect(nsIFrame* aFrame, nscoord aDeltaWidth)
 {
-  nsRect r = aFrame->GetRect();
-  r.x -= aDeltaWidth;
-  aFrame->SetRect(r);
+  aFrame->MovePositionBy(nsPoint(-aDeltaWidth, 0));
 }
 
 bool
 nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
                                        nscoord* aDeltaWidth)
 {
 #ifndef IBMBIDI
 // XXX what about NS_STYLE_DIRECTION_RTL?
--- a/layout/generic/nsSimplePageSequence.cpp
+++ b/layout/generic/nsSimplePageSequence.cpp
@@ -460,20 +460,17 @@ GetPrintCanvasElementsInFrame(nsIFrame* 
 
       // Check if child is a nsHTMLCanvasFrame.
       nsHTMLCanvasFrame* canvasFrame = do_QueryFrame(child);
 
       // If there is a canvasFrame, try to get actual canvas element.
       if (canvasFrame) {
         HTMLCanvasElement* canvas =
           HTMLCanvasElement::FromContentOrNull(canvasFrame->GetContent());
-        nsCOMPtr<nsIPrintCallback> printCallback;
-        if (canvas &&
-            NS_SUCCEEDED(canvas->GetMozPrintCallback(getter_AddRefs(printCallback))) &&
-            printCallback) {
+        if (canvas && canvas->GetMozPrintCallback()) {
           aArr->AppendElement(canvas);
           continue;
         }
       }
 
       if (!child->GetFirstPrincipalChild()) {
         nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(child);
         if (subdocumentFrame) {
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -2635,20 +2635,18 @@ DocHasPrintCallbackCanvas(nsIDocument* a
   if (!root) {
     return true;
   }
   nsRefPtr<nsContentList> canvases = NS_GetContentList(root,
                                                        kNameSpaceID_XHTML,
                                                        NS_LITERAL_STRING("canvas"));
   uint32_t canvasCount = canvases->Length(true);
   for (uint32_t i = 0; i < canvasCount; ++i) {
-    nsCOMPtr<nsIDOMHTMLCanvasElement> canvas = do_QueryInterface(canvases->Item(i, false));
-    nsCOMPtr<nsIPrintCallback> printCallback;
-    if (canvas && NS_SUCCEEDED(canvas->GetMozPrintCallback(getter_AddRefs(printCallback))) &&
-        printCallback) {
+    HTMLCanvasElement* canvas = HTMLCanvasElement::FromContentOrNull(canvases->Item(i, false));
+    if (canvas && canvas->GetMozPrintCallback()) {
       // This subdocument has a print callback. Set result and return false to
       // stop iteration.
       *static_cast<bool*>(aData) = true;
       return false;
     }
   }
   return true;
 }
--- a/layout/reftests/forms/input/range/reftest.list
+++ b/layout/reftests/forms/input/range/reftest.list
@@ -14,18 +14,18 @@ default-preferences pref(dom.experimenta
 != different-fraction-of-range-unthemed-1.html different-fraction-of-range-unthemed-1-notref.html
 == same-fraction-of-range-unthemed-1.html same-fraction-of-range-unthemed-1-ref.html
 
 # dynamic value changes:
 == value-prop-unthemed.html 75pct-unthemed-common-ref.html
 == value-prop.html 75pct-common-ref.html
 == valueAsNumber-prop-unthemed.html 75pct-unthemed-common-ref.html
 == valueAsNumber-prop.html 75pct-common-ref.html
-fails-if(B2G) == stepDown-unthemed.html 75pct-unthemed-common-ref.html
-fails-if(B2G) == stepDown.html 75pct-common-ref.html
+== stepDown-unthemed.html 75pct-unthemed-common-ref.html
+== stepDown.html 75pct-common-ref.html
 == stepUp-unthemed.html 75pct-unthemed-common-ref.html
 == stepUp.html 75pct-common-ref.html
 
 # 'direction' property:
 == direction-unthemed-1.html direction-unthemed-1-ref.html
 
 # ::-moz-range-progress pseudo-element:
 fails-if(B2G) == moz-range-progress-1.html moz-range-progress-1-ref.html
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -165,20 +165,20 @@ skip-if(B2G) == foreignObject-move-repai
 == foreignObject-overflow-01.svg pass.svg
 skip-if(B2G) == foreignObject-start-hidden-01.svg pass.svg # followup from Bug 596765
 skip-if(B2G) == foreignObject-start-hidden-02.svg pass.svg
 skip-if(B2G) == foreignObject-style-change-01.svg pass.svg
 == foreignObject-dynamic-abspos-01.html foreignObject-dynamic-abspos-01-ref.html
 fuzzy-if(Android,18,600) == foreignObject-fixedpos-01.html foreignObject-dynamic-abspos-01-ref.html
 == foreignObject-dynamic-fixedpos-01.html foreignObject-dynamic-abspos-01-ref.html
 == getElementById-a-element-01.svg pass.svg
-fuzzy-if(Android,9,980) == gradient-live-01a.svg gradient-live-01-ref.svg
-fuzzy-if(Android,9,980) == gradient-live-01b.svg gradient-live-01-ref.svg
-fuzzy-if(Android,9,980) == gradient-live-01c.svg gradient-live-01-ref.svg
-fuzzy-if(Android,9,980) == gradient-live-01d.svg gradient-live-01-ref.svg
+fuzzy-if(Android||B2G,9,980) == gradient-live-01a.svg gradient-live-01-ref.svg
+fuzzy-if(Android||B2G,9,980) == gradient-live-01b.svg gradient-live-01-ref.svg
+fuzzy-if(Android||B2G,9,980) == gradient-live-01c.svg gradient-live-01-ref.svg
+fuzzy-if(Android||B2G,9,980) == gradient-live-01d.svg gradient-live-01-ref.svg
 == import-svg-01.html pass.svg
 == invalid-text-01.svg pass.svg
 == lang-attribute-01.svg pass.svg
 == lang-attribute-02.svg pass.svg
 == lang-attribute-03.svg pass.svg
 == linearGradient-basic-01.svg pass.svg
 == linearGradient-basic-02.svg pass.svg
 == markers-and-group-opacity-01.svg markers-and-group-opacity-01-ref.svg
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -976,17 +976,18 @@ nsAnimationManager::GetAnimationRule(moz
 
     if (ea->mStyleRule) {
       ea->PostRestyleForAnimation(mPresContext);
     }
 
     return nullptr;
   }
 
-  NS_WARN_IF_FALSE(ea->mStyleRuleRefreshTime ==
+  NS_WARN_IF_FALSE(!ea->mNeedsRefreshes ||
+                   ea->mStyleRuleRefreshTime ==
                      mPresContext->RefreshDriver()->MostRecentRefresh(),
                    "should already have refreshed style rule");
 
   return ea->mStyleRule;
 }
 
 /* virtual */ void
 nsAnimationManager::WillRefresh(mozilla::TimeStamp aTime)
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -3369,17 +3369,17 @@ CSS_PROP_SVGRESET(
     filter,
     filter,
     Filter,
     CSS_PROPERTY_PARSE_FUNCTION,
     "",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
+    eStyleAnimType_Custom)
 CSS_PROP_SVGRESET(
     flood-color,
     flood_color,
     FloodColor,
     CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HC,
     nullptr,
--- a/layout/style/nsStyleAnimation.cpp
+++ b/layout/style/nsStyleAnimation.cpp
@@ -243,16 +243,44 @@ ToPrimitive(nsCSSValue::Array* aArray)
 
 inline void
 nscoordToCSSValue(nscoord aCoord, nsCSSValue& aCSSValue)
 {
   aCSSValue.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(aCoord),
                           eCSSUnit_Pixel);
 }
 
+static void
+AppendCSSShadowValue(const nsCSSShadowItem *aShadow,
+                     nsCSSValueList **&aResultTail)
+{
+  NS_ABORT_IF_FALSE(aShadow, "shadow expected");
+
+  // X, Y, Radius, Spread, Color, Inset
+  nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(6);
+  nscoordToCSSValue(aShadow->mXOffset, arr->Item(0));
+  nscoordToCSSValue(aShadow->mYOffset, arr->Item(1));
+  nscoordToCSSValue(aShadow->mRadius, arr->Item(2));
+  // NOTE: This code sometimes stores mSpread: 0 even when
+  // the parser would be required to leave it null.
+  nscoordToCSSValue(aShadow->mSpread, arr->Item(3));
+  if (aShadow->mHasColor) {
+    arr->Item(4).SetColorValue(aShadow->mColor);
+  }
+  if (aShadow->mInset) {
+    arr->Item(5).SetIntValue(NS_STYLE_BOX_SHADOW_INSET,
+                             eCSSUnit_Enumerated);
+  }
+
+  nsCSSValueList *resultItem = new nsCSSValueList;
+  resultItem->mValue.SetArrayValue(arr, eCSSUnit_Array);
+  *aResultTail = resultItem;
+  aResultTail = &resultItem->mNext;
+}
+
 // Like nsStyleCoord::Calc, but with length in float pixels instead of nscoord.
 struct CalcValue {
   float mLength, mPercent;
   bool mHasPercent;
 };
 
 // Requires a canonical calc() value that we generated.
 static CalcValue
@@ -748,16 +776,18 @@ nsStyleAnimation::ComputeDistance(nsCSSP
 
         shadow1 = shadow1->mNext;
         shadow2 = shadow2->mNext;
         NS_ABORT_IF_FALSE(!shadow1 == !shadow2, "lists should be same length");
       }
       aDistance = sqrt(squareDistance);
       return true;
     }
+    case eUnit_Filter:
+      // FIXME: Support paced animations for filter function interpolation.
     case eUnit_Transform: {
       return false;
     }
     case eUnit_BackgroundPosition: {
       const nsCSSValueList *position1 = aStartValue.GetCSSValueListValue();
       const nsCSSValueList *position2 = aEndValue.GetCSSValueListValue();
 
       double squareDistance = 0.0;
@@ -1027,16 +1057,48 @@ AddCSSValuePixelPercentCalc(const uint32
       break;
     default:
       return false;
   }
 
   return true;
 }
 
+static inline float
+GetNumberOrPercent(const nsCSSValue &aValue)
+{
+  nsCSSUnit unit = aValue.GetUnit();
+  NS_ABORT_IF_FALSE(unit == eCSSUnit_Number || unit == eCSSUnit_Percent,
+                    "unexpected unit");
+  return (unit == eCSSUnit_Number) ?
+    aValue.GetFloatValue() : aValue.GetPercentValue();
+}
+
+static inline void
+AddCSSValuePercentNumber(const uint32_t aValueRestrictions,
+                         double aCoeff1, const nsCSSValue &aValue1,
+                         double aCoeff2, const nsCSSValue &aValue2,
+                         nsCSSValue &aResult, float aInitialVal)
+{
+  float n1 = GetNumberOrPercent(aValue1);
+  float n2 = GetNumberOrPercent(aValue2);
+
+  // Rather than interpolating aValue1 and aValue2 directly, we
+  // interpolate their *distances from aInitialVal* (the initial value,
+  // which is either 1 or 0 for "filter" functions).  This matters in
+  // cases where aInitialVal is nonzero and the coefficients don't add
+  // up to 1.  For example, if initialVal is 1, aCoeff1 is 0.5, and
+  // aCoeff2 is 0, then we'll return the value halfway between 1 and
+  // aValue1, rather than the value halfway between 0 and aValue1.
+  // Note that we do something similar in AddTransformScale().
+  float result = (n1 - aInitialVal) * aCoeff1 + (n2 - aInitialVal) * aCoeff2;
+  aResult.SetFloatValue(RestrictValue(aValueRestrictions, result + aInitialVal),
+                        eCSSUnit_Number);
+}
+
 static bool
 AddShadowItems(double aCoeff1, const nsCSSValue &aValue1,
                double aCoeff2, const nsCSSValue &aValue2,
                nsCSSValueList **&aResultTail)
 {
   // X, Y, Radius, Spread, Color, Inset
   NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Array,
                     "wrong unit");
@@ -1542,16 +1604,131 @@ AddDifferentTransformLists(double aCoeff
 }
 
 static bool
 TransformFunctionsMatch(nsCSSKeyword func1, nsCSSKeyword func2)
 {
   return ToPrimitive(func1) == ToPrimitive(func2);
 }
 
+static bool
+AddFilterFunctionImpl(double aCoeff1, const nsCSSValueList* aList1,
+                      double aCoeff2, const nsCSSValueList* aList2,
+                      nsCSSValueList**& aResultTail)
+{
+  // AddFilterFunction should be our only caller, and it should ensure that both
+  // args are non-null.
+  NS_ABORT_IF_FALSE(aList1, "expected filter list");
+  NS_ABORT_IF_FALSE(aList2, "expected filter list");
+  NS_ABORT_IF_FALSE(aList1->mValue.GetUnit() == eCSSUnit_Function,
+                    "expected function");
+  NS_ABORT_IF_FALSE(aList2->mValue.GetUnit() == eCSSUnit_Function,
+                    "expected function");
+  nsRefPtr<nsCSSValue::Array> a1 = aList1->mValue.GetArrayValue(),
+                              a2 = aList2->mValue.GetArrayValue();
+  nsCSSKeyword filterFunction = a1->Item(0).GetKeywordValue();
+  if (filterFunction != a2->Item(0).GetKeywordValue())
+    return false; // Can't add two filters of different types.
+
+  nsAutoPtr<nsCSSValueList> resultListEntry(new nsCSSValueList);
+  nsCSSValue::Array* result =
+    resultListEntry->mValue.InitFunction(filterFunction, 1);
+
+  // "hue-rotate" is the only filter-function that accepts negative values, and
+  // we don't use this "restrictions" variable in its clause below.
+  const uint32_t restrictions = CSS_PROPERTY_VALUE_NONNEGATIVE;
+  const nsCSSValue& funcArg1 = a1->Item(1);
+  const nsCSSValue& funcArg2 = a2->Item(1);
+  nsCSSValue& resultArg = result->Item(1);
+  float initialVal = 1.0f;
+  switch (filterFunction) {
+    case eCSSKeyword_blur: {
+      nsCSSUnit unit;
+      if (funcArg1.GetUnit() == funcArg2.GetUnit()) {
+        unit = funcArg1.GetUnit();
+      } else {
+        // If units differ, we'll just combine them with calc().
+        unit = eCSSUnit_Calc;
+      }
+      if (!AddCSSValuePixelPercentCalc(restrictions,
+                                       unit,
+                                       aCoeff1, funcArg1,
+                                       aCoeff2, funcArg2,
+                                       resultArg)) {
+        return false;
+      }
+      break;
+    }
+    case eCSSKeyword_grayscale:
+    case eCSSKeyword_invert:
+    case eCSSKeyword_sepia:
+      initialVal = 0.0f;
+    case eCSSKeyword_brightness:
+    case eCSSKeyword_contrast:
+    case eCSSKeyword_opacity:
+    case eCSSKeyword_saturate:
+      AddCSSValuePercentNumber(restrictions,
+                               aCoeff1, funcArg1,
+                               aCoeff2, funcArg2,
+                               resultArg,
+                               initialVal);
+      break;
+    case eCSSKeyword_hue_rotate:
+      AddCSSValueAngle(aCoeff1, funcArg1,
+                       aCoeff2, funcArg2,
+                       resultArg);
+      break;
+    case eCSSKeyword_drop_shadow: {
+      nsCSSValueList* resultShadow = resultArg.SetListValue();
+      nsAutoPtr<nsCSSValueList> shadowValue;
+      nsCSSValueList **shadowTail = getter_Transfers(shadowValue);
+      NS_ABORT_IF_FALSE(!funcArg1.GetListValue()->mNext &&
+                        !funcArg2.GetListValue()->mNext,
+                        "drop-shadow filter func doesn't support lists");
+      if (!AddShadowItems(aCoeff1, funcArg1.GetListValue()->mValue,
+                          aCoeff2, funcArg2.GetListValue()->mValue,
+                          shadowTail)) {
+        return false;
+      }
+      *resultShadow = *shadowValue;
+      break;
+    }
+    default:
+      NS_ABORT_IF_FALSE(false, "unknown filter function");
+      return false;
+  }
+
+  *aResultTail = resultListEntry.forget();
+  aResultTail = &(*aResultTail)->mNext;
+
+  return true;
+}
+
+static bool
+AddFilterFunction(double aCoeff1, const nsCSSValueList* aList1,
+                  double aCoeff2, const nsCSSValueList* aList2,
+                  nsCSSValueList**& aResultTail)
+{
+  NS_ABORT_IF_FALSE(aList1 || aList2,
+                    "one function list item must not be null");
+  // Note that one of our arguments could be null, indicating that
+  // it's the initial value. Rather than adding special null-handling
+  // logic, we just check for null values and replace them with
+  // 0 * the other value. That way, AddFilterFunctionImpl can assume
+  // its args are non-null.
+  if (!aList1) {
+    return AddFilterFunctionImpl(aCoeff2, aList2, 0, aList2, aResultTail);
+  }
+  if (!aList2) {
+    return AddFilterFunctionImpl(aCoeff1, aList1, 0, aList1, aResultTail);
+  }
+
+  return AddFilterFunctionImpl(aCoeff1, aList1, aCoeff2, aList2, aResultTail);
+}
+
 static nsCSSValueList*
 AddTransformLists(double aCoeff1, const nsCSSValueList* aList1,
                   double aCoeff2, const nsCSSValueList* aList2)
 {
   nsAutoPtr<nsCSSValueList> result;
   nsCSSValueList **resultTail = getter_Transfers(result);
 
   do {
@@ -2055,16 +2232,54 @@ nsStyleAnimation::AddWeighted(nsCSSPrope
           }
 
           longShadow = longShadow->mNext;
         }
       }
       aResultValue.SetAndAdoptCSSValueListValue(result.forget(), eUnit_Shadow);
       return true;
     }
+
+    case eUnit_Filter: {
+      const nsCSSValueList *list1 = aValue1.GetCSSValueListValue();
+      const nsCSSValueList *list2 = aValue2.GetCSSValueListValue();
+
+      nsAutoPtr<nsCSSValueList> result;
+      nsCSSValueList **resultTail = getter_Transfers(result);
+      while (list1 || list2) {
+        NS_ABORT_IF_FALSE(!*resultTail,
+          "resultTail isn't pointing to the tail (may leak)");
+        if ((list1 && list1->mValue.GetUnit() != eCSSUnit_Function) ||
+            (list2 && list2->mValue.GetUnit() != eCSSUnit_Function)) {
+          // If we don't have filter-functions, we must have filter-URLs, which
+          // we can't add or interpolate.
+          return false;
+        }
+
+        if (!AddFilterFunction(aCoeff1, list1, aCoeff2, list2, resultTail)) {
+          // filter function mismatch
+          return false;
+        }
+
+        // move to next list items
+        if (list1) {
+          list1 = list1->mNext;
+        }
+        if (list2) {
+          list2 = list2->mNext;
+        }
+      };
+      NS_ABORT_IF_FALSE(!*resultTail,
+                        "resultTail isn't pointing to the tail (may leak)");
+
+      aResultValue.SetAndAdoptCSSValueListValue(result.forget(),
+                                                eUnit_Filter);
+      return true;
+    }
+
     case eUnit_Transform: {
       const nsCSSValueList *list1 = aValue1.GetCSSValueListValue();
       const nsCSSValueList *list2 = aValue2.GetCSSValueListValue();
 
       // We want to avoid the matrix decomposition when we can, since
       // avoiding it can produce better results both for compound
       // transforms and for skew and skewY (see below).  We can do this
       // in two cases:
@@ -2427,16 +2642,17 @@ nsStyleAnimation::UncomputeValue(nsCSSPr
       }
     } break;
     case eUnit_CSSRect: {
       nsCSSRect& rect = aSpecifiedValue.SetRectValue();
       rect = *aComputedValue.GetCSSRectValue();
     } break;
     case eUnit_Dasharray:
     case eUnit_Shadow:
+    case eUnit_Filter:
     case eUnit_Transform:
     case eUnit_BackgroundPosition:
       aSpecifiedValue.
         SetDependentListValue(aComputedValue.GetCSSValueListValue());
       break;
     case eUnit_CSSValuePairList:
       aSpecifiedValue.
         SetDependentPairListValue(aComputedValue.GetCSSValuePairListValue());
@@ -2539,22 +2755,37 @@ StyleCoordToValue(const nsStyleCoord& aC
 
 static bool
 StyleCoordToCSSValue(const nsStyleCoord& aCoord, nsCSSValue& aCSSValue)
 {
   switch (aCoord.GetUnit()) {
     case eStyleUnit_Coord:
       nscoordToCSSValue(aCoord.GetCoordValue(), aCSSValue);
       break;
+    case eStyleUnit_Factor:
+      aCSSValue.SetFloatValue(aCoord.GetFactorValue(), eCSSUnit_Number);
+      break;
     case eStyleUnit_Percent:
       aCSSValue.SetPercentValue(aCoord.GetPercentValue());
       break;
     case eStyleUnit_Calc:
       SetCalcValue(aCoord.GetCalcValue(), aCSSValue);
       break;
+    case eStyleUnit_Degree:
+      aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Degree);
+      break;
+    case eStyleUnit_Grad:
+      aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Grad);
+      break;
+    case eStyleUnit_Radian:
+      aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Radian);
+      break;
+    case eStyleUnit_Turn:
+      aCSSValue.SetFloatValue(aCoord.GetAngleValue(), eCSSUnit_Turn);
+      break;
     default:
       NS_ABORT_IF_FALSE(false, "unexpected unit");
       return false;
   }
   return true;
 }
 
 /*
@@ -3007,16 +3238,73 @@ nsStyleAnimation::ExtractComputedValue(n
                 break;
             }
           }
 
           aComputedValue.SetAndAdoptCSSValuePairListValue(result.forget());
           break;
         }
 
+        case eCSSProperty_filter: {
+          const nsStyleSVGReset *svgReset =
+            static_cast<const nsStyleSVGReset*>(styleStruct);
+          const nsTArray<nsStyleFilter>& filters = svgReset->mFilters;
+          nsAutoPtr<nsCSSValueList> result;
+          nsCSSValueList **resultTail = getter_Transfers(result);
+          for (uint32_t i = 0; i < filters.Length(); ++i) {
+            nsCSSValueList *item = new nsCSSValueList;
+            *resultTail = item;
+            resultTail = &item->mNext;
+            const nsStyleFilter& filter = filters[i];
+            int32_t type = filter.GetType();
+            if (type == NS_STYLE_FILTER_URL) {
+              nsIDocument* doc = aStyleContext->PresContext()->Document();
+              nsRefPtr<nsStringBuffer> uriAsStringBuffer =
+                GetURIAsUtf16StringBuffer(filter.GetURL());
+              nsRefPtr<mozilla::css::URLValue> url =
+                new mozilla::css::URLValue(filter.GetURL(),
+                                           uriAsStringBuffer,
+                                           doc->GetDocumentURI(),
+                                           doc->NodePrincipal());
+              item->mValue.SetURLValue(url);
+            } else {
+              nsCSSKeyword functionName =
+                nsCSSProps::ValueToKeywordEnum(type,
+                  nsCSSProps::kFilterFunctionKTable);
+              nsCSSValue::Array* filterArray =
+                item->mValue.InitFunction(functionName, 1);
+              if (type >= NS_STYLE_FILTER_BLUR && type <= NS_STYLE_FILTER_HUE_ROTATE) {
+                if (!StyleCoordToCSSValue(
+                      filter.GetFilterParameter(),
+                      filterArray->Item(1))) {
+                  return false;
+                }
+              } else if (type == NS_STYLE_FILTER_DROP_SHADOW) {
+                nsCSSValueList* shadowResult = filterArray->Item(1).SetListValue();
+                nsAutoPtr<nsCSSValueList> tmpShadowValue;
+                nsCSSValueList **tmpShadowResultTail = getter_Transfers(tmpShadowValue);
+                nsCSSShadowArray* shadowArray = filter.GetDropShadow();
+                NS_ABORT_IF_FALSE(shadowArray->Length() == 1,
+                                  "expected exactly one shadow");
+                AppendCSSShadowValue(shadowArray->ShadowAt(0), tmpShadowResultTail);
+                *shadowResult = *tmpShadowValue;
+              } else {
+                // We checked all possible nsStyleFilter types but
+                // NS_STYLE_FILTER_NULL before. We should never enter this path.
+                NS_NOTREACHED("no other filter functions defined");
+                return false;
+              }
+            }
+          }
+
+          aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
+                                                      eUnit_Filter);
+          break;
+        }
+
         case eCSSProperty_transform: {
           const nsStyleDisplay *display =
             static_cast<const nsStyleDisplay*>(styleStruct);
           nsAutoPtr<nsCSSValueList> result;
           if (display->mSpecifiedTransform) {
             // Clone, and convert all lengths (not percents) to pixels.
             nsCSSValueList **resultTail = getter_Transfers(result);
             for (const nsCSSValueList *l = display->mSpecifiedTransform;
@@ -3167,40 +3455,17 @@ nsStyleAnimation::ExtractComputedValue(n
           StyleDataAtOffset(styleStruct, ssOffset));
       if (!shadowArray) {
         aComputedValue.SetAndAdoptCSSValueListValue(nullptr, eUnit_Shadow);
         return true;
       }
       nsAutoPtr<nsCSSValueList> result;
       nsCSSValueList **resultTail = getter_Transfers(result);
       for (uint32_t i = 0, i_end = shadowArray->Length(); i < i_end; ++i) {
-        const nsCSSShadowItem *shadow = shadowArray->ShadowAt(i);
-        // X, Y, Radius, Spread, Color, Inset
-        nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(6);
-        nscoordToCSSValue(shadow->mXOffset, arr->Item(0));
-        nscoordToCSSValue(shadow->mYOffset, arr->Item(1));
-        nscoordToCSSValue(shadow->mRadius, arr->Item(2));
-        // NOTE: This code sometimes stores mSpread: 0 even when
-        // the parser would be required to leave it null.
-        nscoordToCSSValue(shadow->mSpread, arr->Item(3));
-        if (shadow->mHasColor) {
-          arr->Item(4).SetColorValue(shadow->mColor);
-        }
-        if (shadow->mInset) {
-          arr->Item(5).SetIntValue(NS_STYLE_BOX_SHADOW_INSET,
-                                   eCSSUnit_Enumerated);
-        }
-
-        nsCSSValueList *resultItem = new nsCSSValueList;
-        if (!resultItem) {
-          return false;
-        }
-        resultItem->mValue.SetArrayValue(arr, eCSSUnit_Array);
-        *resultTail = resultItem;
-        resultTail = &resultItem->mNext;
+        AppendCSSShadowValue(shadowArray->ShadowAt(i), resultTail);
       }
       aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
                                                   eUnit_Shadow);
       return true;
     }
     case eStyleAnimType_None:
       NS_NOTREACHED("shouldn't use on non-animatable properties");
   }
@@ -3294,22 +3559,24 @@ nsStyleAnimation::Value::operator=(const
       break;
     case eUnit_CSSRect:
       NS_ABORT_IF_FALSE(aOther.mValue.mCSSRect, "rects may not be null");
       mValue.mCSSRect = new nsCSSRect(*aOther.mValue.mCSSRect);
       if (!mValue.mCSSRect) {
         mUnit = eUnit_Null;
       }
       break;
+    case eUnit_Filter:
     case eUnit_Dasharray:
     case eUnit_Shadow:
     case eUnit_Transform:
     case eUnit_BackgroundPosition:
-      NS_ABORT_IF_FALSE(mUnit == eUnit_Shadow || aOther.mValue.mCSSValueList,
-                        "value lists other than shadows may not be null");
+      NS_ABORT_IF_FALSE(mUnit == eUnit_Shadow || mUnit == eUnit_Filter ||
+                        aOther.mValue.mCSSValueList,
+                        "value lists other than shadows and filters may not be null");
       if (aOther.mValue.mCSSValueList) {
         mValue.mCSSValueList = aOther.mValue.mCSSValueList->Clone();
         if (!mValue.mCSSValueList) {
           mUnit = eUnit_Null;
         }
       } else {
         mValue.mCSSValueList = nullptr;
       }
@@ -3448,18 +3715,19 @@ nsStyleAnimation::Value::SetAndAdoptCSSR
 }
 
 void
 nsStyleAnimation::Value::SetAndAdoptCSSValueListValue(
                            nsCSSValueList *aValueList, Unit aUnit)
 {
   FreeValue();
   NS_ABORT_IF_FALSE(IsCSSValueListUnit(aUnit), "bad unit");
-  NS_ABORT_IF_FALSE(aUnit != eUnit_Dasharray || aValueList != nullptr,
-                    "dasharrays may not be null");
+  NS_ABORT_IF_FALSE(aUnit != eUnit_Dasharray || aUnit != eUnit_Filter ||
+                    aValueList != nullptr,
+                    "dasharrays and filters may not be null");
   mUnit = aUnit;
   mValue.mCSSValueList = aValueList; // take ownership
 }
 
 void
 nsStyleAnimation::Value::SetAndAdoptCSSValuePairListValue(
                            nsCSSValuePairList *aValuePairList)
 {
@@ -3518,16 +3786,17 @@ nsStyleAnimation::Value::operator==(cons
       return *mValue.mCSSValue == *aOther.mValue.mCSSValue;
     case eUnit_CSSValuePair:
       return *mValue.mCSSValuePair == *aOther.mValue.mCSSValuePair;
     case eUnit_CSSValueTriplet:
       return *mValue.mCSSValueTriplet == *aOther.mValue.mCSSValueTriplet;
     case eUnit_CSSRect:
       return *mValue.mCSSRect == *aOther.mValue.mCSSRect;
     case eUnit_Dasharray:
+    case eUnit_Filter:
     case eUnit_Shadow:
     case eUnit_Transform:
     case eUnit_BackgroundPosition:
       return *mValue.mCSSValueList == *aOther.mValue.mCSSValueList;
     case eUnit_CSSValuePairList:
       return *mValue.mCSSValuePairList == *aOther.mValue.mCSSValuePairList;
     case eUnit_UnparsedString:
       return (NS_strcmp(GetStringBufferValue(),
--- a/layout/style/nsStyleAnimation.h
+++ b/layout/style/nsStyleAnimation.h
@@ -216,16 +216,17 @@ public:
     eUnit_Float,
     eUnit_Color,
     eUnit_Calc, // nsCSSValue* (never null), always with a single
                 // calc() expression that's either length or length+percent
     eUnit_CSSValuePair, // nsCSSValuePair* (never null)
     eUnit_CSSValueTriplet, // nsCSSValueTriplet* (never null)
     eUnit_CSSRect, // nsCSSRect* (never null)
     eUnit_Dasharray, // nsCSSValueList* (never null)
+    eUnit_Filter, // nsCSSValueList* (may be null)
     eUnit_Shadow, // nsCSSValueList* (may be null)
     eUnit_Transform, // nsCSSValueList* (never null)
     eUnit_BackgroundPosition, // nsCSSValueList* (never null)
     eUnit_CSSValuePairList, // nsCSSValuePairList* (never null)
     eUnit_UnparsedString // nsStringBuffer* (never null)
   };
 
   class Value {
@@ -375,18 +376,19 @@ public:
     }
     static bool IsCSSValueTripletUnit(Unit aUnit) {
       return aUnit == eUnit_CSSValueTriplet;
     }
     static bool IsCSSRectUnit(Unit aUnit) {
       return aUnit == eUnit_CSSRect;
     }
     static bool IsCSSValueListUnit(Unit aUnit) {
-      return aUnit == eUnit_Dasharray || aUnit == eUnit_Shadow ||
-             aUnit == eUnit_Transform || aUnit == eUnit_BackgroundPosition;
+      return aUnit == eUnit_Dasharray || aUnit == eUnit_Filter ||
+             aUnit == eUnit_Shadow || aUnit == eUnit_Transform ||
+             aUnit == eUnit_BackgroundPosition;
     }
     static bool IsCSSValuePairListUnit(Unit aUnit) {
       return aUnit == eUnit_CSSValuePairList;
     }
     static bool IsStringUnit(Unit aUnit) {
       return aUnit == eUnit_UnparsedString;
     }
   };
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -117,16 +117,17 @@ var supported_properties = {
                 test_length_unclamped, test_percent_unclamped ],
     "clip": [ test_rect_transition ],
     "color": [ test_color_transition ],
     "fill": [ test_color_transition ],
     "fill-opacity" : [ test_float_zeroToOne_transition,
                        // opacity is clamped in computed style
                        // (not parsing/interpolation)
                        test_float_zeroToOne_clamped ],
+    "filter" : [ test_filter_transition ],
     "flood-color": [ test_color_transition ],
     "flood-opacity" : [ test_float_zeroToOne_transition,
                         // opacity is clamped in computed style
                         // (not parsing/interpolation)
                         test_float_zeroToOne_clamped ],
     "font-size": [ test_length_transition, test_percent_transition,
                    test_length_percent_calc_transition,
                    test_length_clamped, test_percent_clamped ],
@@ -571,16 +572,166 @@ var transformTests = [
     end: 'skewX(-45deg) rotate(90deg)',
     expected_uncomputed: 'skewX(22.5deg) rotate(90deg)' },
   { start: 'skewX(-60deg) rotate(90deg) translate(0)',
     end: 'skewX(60deg) rotate(90deg)',
     expected: computeMatrix('rotate(120deg) skewX(' + Math.atan(Math.tan(Math.PI * 60/180) / 2) + 'rad) scale(2, 0.5)'),
     round_error_ok: true },
 ];
 
+var filterTests = [
+  { start: "none", end: "none",
+    expected: ["none"] },
+  // function from none (number/length)
+  { start: "none", end: "brightness(0.5)",
+    expected: ["brightness", 0.875] },
+  { start: "none", end: "contrast(0.5)",
+    expected: ["contrast", 0.875] },
+  { start: "none", end: "grayscale(0.5)",
+    expected: ["grayscale", 0.125] },
+  { start: "none", end: "invert(0.5)",
+    expected: ["invert", 0.125] },
+  { start: "none", end: "opacity(0.5)",
+    expected: ["opacity", 0.875] },
+  { start: "none", end: "saturate(0.5)",
+    expected: ["saturate", 0.875] },
+  { start: "none", end: "sepia(0.5)",
+    expected: ["sepia", 0.125] },
+  { start: "none", end: "blur(50px)",
+    expected: ["blur", 12.5] },
+  // function to none (number/length)
+  { start: "brightness(0.5)", end: "none",
+    expected: ["brightness", 0.625] },
+  { start: "contrast(0.5)", end: "none",
+    expected: ["contrast", 0.625] },
+  { start: "grayscale(0.5)", end: "none",
+    expected: ["grayscale", 0.375] },
+  { start: "invert(0.5)", end: "none",
+    expected: ["invert", 0.375] },
+  { start: "opacity(0.5)", end: "none",
+    expected: ["opacity", 0.625] },
+  { start: "saturate(0.5)", end: "none",
+    expected: ["saturate", 0.625] },
+  { start: "sepia(0.5)", end: "none",
+    expected: ["sepia", 0.375] },
+  { start: "blur(50px)", end: "none",
+    expected: ["blur", 37.5] },
+  // function to same function (number/length)
+  { start: "brightness(0.25)", end: "brightness(0.75)",
+    expected: ["brightness", 0.375] },
+  { start: "contrast(0.25)", end: "contrast(0.75)",
+    expected: ["contrast", 0.375] },
+  { start: "grayscale(0.25)", end: "grayscale(0.75)",
+    expected: ["grayscale", 0.375] },
+  { start: "invert(0.25)", end: "invert(0.75)",
+    expected: ["invert", 0.375] },
+  { start: "opacity(0.25)", end: "opacity(0.75)",
+    expected: ["opacity", 0.375] },
+  { start: "saturate(0.25)", end: "saturate(0.75)",
+    expected: ["saturate", 0.375] },
+  { start: "sepia(0.25)", end: "sepia(0.75)",
+    expected: ["sepia", 0.375] },
+  { start: "blur(25px)", end: "blur(75px)",
+    expected: ["blur", 37.5] },
+  // function to same function (percent)
+  { start: "brightness(25%)", end: "brightness(75%)",
+    expected: ["brightness", 0.375] },
+  { start: "contrast(25%)", end: "contrast(75%)",
+    expected: ["contrast", 0.375] },
+  { start: "grayscale(25%)", end: "grayscale(75%)",
+    expected: ["grayscale", 0.375] },
+  { start: "invert(25%)", end: "invert(75%)",
+    expected: ["invert", 0.375] },
+  { start: "opacity(25%)", end: "opacity(75%)",
+    expected: ["opacity", 0.375] },
+  { start: "saturate(25%)", end: "saturate(75%)",
+    expected: ["saturate", 0.375] },
+  { start: "sepia(25%)", end: "sepia(75%)",
+    expected: ["sepia", 0.375] },
+  // function to same function (percent, number/length)
+  { start: "brightness(0.25)", end: "brightness(75%)",
+    expected: ["brightness", 0.375] },
+  { start: "contrast(25%)", end: "contrast(0.75)",
+    expected: ["contrast", 0.375] },
+  // hue-rotate with different angle values
+  { start: "hue-rotate(0deg)", end: "hue-rotate(720deg)",
+    expected: ["hue-rotate", Math.PI.toFixed(5)] },
+  { start: "hue-rotate(0rad)", end: "hue-rotate("+4*Math.PI+"rad)",
+    expected: ["hue-rotate", Math.PI.toFixed(5)] },
+  { start: "hue-rotate(0grad)", end: "hue-rotate(800grad)",
+    expected: ["hue-rotate", Math.PI.toFixed(5)] },
+  { start: "hue-rotate(0turn)", end: "hue-rotate(2turn)",
+    expected: ["hue-rotate", Math.PI.toFixed(5)] },
+  { start: "hue-rotate(0deg)", end: "hue-rotate("+4*Math.PI+"rad)",
+    expected: ["hue-rotate", Math.PI.toFixed(5)] },
+  { start: "hue-rotate(0turn)", end: "hue-rotate(800grad)",
+    expected: ["hue-rotate", Math.PI.toFixed(5)] },
+  { start: "hue-rotate(0grad)", end: "hue-rotate("+4*Math.PI+"rad)",
+    expected: ["hue-rotate", Math.PI.toFixed(5)] },
+  { start: "hue-rotate(0grad)", end: "hue-rotate(0turn)",
+    expected: ["hue-rotate", 0] },
+  // multiple matching functions, same length
+  { start: "contrast(25%) brightness(0.25) blur(25px) sepia(75%)",
+    end: "contrast(75%) brightness(0.75) blur(75px) sepia(25%)",
+    expected: ["contrast", 0.375, "brightness", 0.375, "blur", 37.5, "sepia", 0.625] },
+  { start: "invert(25%) brightness(0.25) blur(25px) invert(50%) brightness(0.5) blur(50px)",
+    end: "invert(75%) brightness(0.75) blur(75px)",
+    expected: ["invert", 0.375, "brightness", 0.375, "blur", 37.5, "invert", 0.375, "brightness", 0.625, "blur", 37.5] },
+  // multiple matching functions, different length
+  { start: "contrast(25%) brightness(0.5) blur(50px)",
+    end: "contrast(75%)",
+    expected: ["contrast", 0.375, "brightness", 0.625, "blur", 37.5] },
+  // mismatching filter functions
+  { start: "contrast(0%)", end: "blur(10px)",
+    expected: ["blur", 10] },
+  // not supported interpolations
+  { start: "none", end: "url('#b')",
+    expected: ["url", "\""+document.URL+"#b\""] },
+  { start: "url('#a')", end: "none",
+    expected: ["none"] },
+  { start: "url('#a')", end: "url('#b')",
+    expected: ["url", "\""+document.URL+"#b\""] },
+  { start: "url('#a')", end: "blur(10px)",
+    expected: ["blur", 10] },
+  { start: "blur(10px)", end: "url('#a')",
+    expected: ["url", "\""+document.URL+"#a\""] },
+  { start: "blur(0px) url('#a')", end: "blur(20px)",
+    expected: ["blur", 20] },
+  { start: "blur(0px)", end: "blur(20px) url('#a')",
+    expected: ["blur", 20, "url", "\""+document.URL+"#a\""] },
+  { start: "contrast(0.25) brightness(0.25) blur(25px)",
+    end: "contrast(0.75) url('#a')",
+    expected: ["contrast", 0.75, "url", "\""+document.URL+"#a\""] },
+  { start: "contrast(0.25) brightness(0.25) blur(75px)",
+    end: "brightness(0.75) contrast(0.75) blur(25px)",
+    expected: ["brightness", 0.75, "contrast", 0.75, "blur", 25] },
+  { start: "contrast(0.25) brightness(0.25) blur(25px)",
+    end: "contrast(0.75) brightness(0.75) contrast(0.75)",
+    expected: ["contrast", 0.75, "brightness", 0.75, "contrast", 0.75] },
+  // drop-shadow animation
+  { start: "none",
+    end: "drop-shadow(rgb(0, 0, 0) 4px 4px 0px)",
+    expected: ["drop-shadow", "rgba(0, 0, 0, 0.25) 1px 1px 0px"] },
+  { start: "drop-shadow(rgb(0, 0, 0) 0px 0px 0px)",
+    end: "drop-shadow(rgb(0, 0, 0) 4px 4px 0px)",
+    expected: ["drop-shadow", "rgb(0, 0, 0) 1px 1px 0px"] },
+  { start: "drop-shadow(#038000 4px 4px)",
+    end: "drop-shadow(8px 8px 8px red)",
+    expected: ["drop-shadow", "rgb(66, 96, 0) 5px 5px 2px"] },
+  { start: "blur(25px) drop-shadow(8px 8px)",
+    end: "blur(75px)",
+    expected: ["blur", 37.5, "drop-shadow", "rgb(0, 0, 0) 6px 6px 0px"] },
+  { start: "blur(75px)",
+    end: "blur(25px) drop-shadow(8px 8px)",
+    expected: ["blur", 62.5, "drop-shadow", "rgb(0, 0, 0) 2px 2px 0px"] },
+  { start: "drop-shadow(2px 2px blue)",
+    end: "none",
+    expected: ["drop-shadow", "rgba(0, 0, 255, 0.75) 1.5px 1.5px 0px"] },
+];
+
 var prop;
 for (prop in supported_properties) {
   // Test that prop is in the property database.
   ok(prop in gCSSProperties, "property " + prop + " in gCSSProperties");
 
   // Test that the entry has at least one test function.
   ok(supported_properties[prop].length > 0,
      "property " + prop + " must have at least one test function");
@@ -990,16 +1141,98 @@ function test_border_color_transition(pr
   is(cs.getPropertyValue(prop), "rgb(96, 48, 32)",
      "color-valued property " + prop + ": interpolation of initial value");
 
   check_distance(prop, "rgb(128, 64, 0)", "rgb(96, 48, 32)", "initial");
 
   div.style.removeProperty("color");
 }
 
+function filter_function_list_equals(computedValStr, expectedList)
+{
+  // Check simple case "none"
+  if (computedValStr == "none" && computedValStr == expectedList[0]) {
+    return true;
+  }
+
+  // The regular expression does not filter out the last parenthesis.
+  // Remove last character for now.
+  is(computedValStr.substring(computedValStr.length - 1, computedValStr.length),
+                              ')', "Check if last character is close-paren");
+  computedValStr = computedValStr.substring(0, computedValStr.length - 1);
+
+  var reg = /\)*\s*(blur|brightness|contrast|grayscale|hue\-rotate|invert|opacity|saturate|sepia|drop\-shadow|url)\(/
+  var matches = computedValStr.split(reg);
+  // First item must be empty. All other items are of functionName, functionValue.
+  if (!matches || matches.shift() != "") {
+    ok(false, "computed style of 'filter' isn't in the format we expect");
+    return false;
+  }
+
+  // Odd items are the function name, even items the function value.
+  if (!matches.length || matches.length % 2 ||
+      expectedList.length != matches.length) {
+    ok(false, "computed style of 'filter' isn't in the format we expect");
+    return false;
+  }
+  for (var i = 0; i < matches.length; i += 2) {
+    var functionName = matches[i];
+    var functionValue = matches[i+1];
+    var expected = expectedList[i+1]
+    var tolerance = 0;
+    // Check if we have the expected function.
+    if (functionName != expectedList[i]) {
+      return false;
+    }
+    if (functionName == "blur") {
+      // Last two characters must be "px".
+      if (functionValue.search("px") != functionValue.length - 2) {
+        return false;
+      }
+      functionValue = functionValue.substring(0, functionValue.length - 2);
+    } else if (functionName == "hue-rotate") {
+      // Last two characters must be "rad".
+      if (functionValue.search("rad") != functionValue.length - 3) {
+        return false;
+      }
+      tolerance = 0.001;
+      functionValue = functionValue.substring(0, functionValue.length - 3);
+    } else if (functionName == "drop-shadow" || functionName == "url") {
+      if (functionValue != expected) {
+        return false;
+      }
+      continue;
+    }
+    // Check if string is not a number or difference is not in tolerance level.
+    if (isNaN(functionValue) ||
+      Math.abs(parseFloat(functionValue) - expected) > tolerance) {
+      return false;
+    }
+  }
+  return true;
+}
+
+function test_filter_transition(prop) {
+  if (!SpecialPowers.getBoolPref("layout.css.filters.enabled")) {
+    return;
+  }
+  for (var i in filterTests) {
+    var test = filterTests[i];
+    div.style.setProperty("transition-property", "none", "");
+    div.style.setProperty(prop, test.start, "");
+    cs.getPropertyValue(prop);
+    div.style.setProperty("transition-property", prop, "");
+    div.style.setProperty(prop, test.end, "");
+    var actual = cs.getPropertyValue(prop);
+    ok(filter_function_list_equals(actual, test.expected),
+                                   "Filter property is " + actual + " expected values of " +
+                                   test.expected);
+  }
+}
+
 function test_shadow_transition(prop) {
   var spreadStr = (prop == "box-shadow") ? " 0px" : "";
 
   div.style.setProperty("transition-property", "none", "");
   div.style.setProperty(prop, "none", "");
   is(cs.getPropertyValue(prop), "none",
      "shadow-valued property " + prop + ": computed value before transition");
   div.style.setProperty("transition-property", prop, "");
--- a/layout/svg/nsSVGTextFrame2.cpp
+++ b/layout/svg/nsSVGTextFrame2.cpp
@@ -5415,19 +5415,16 @@ nsSVGTextFrame2::SetupCairoStroke(gfxCon
                                   SVGTextObjectPaint* aThisObjectPaint)
 {
   const nsStyleSVG *style = aFrame->StyleSVG();
   if (style->mStroke.mType == eStyleSVGPaintType_None) {
     aThisObjectPaint->SetStrokeOpacity(0.0f);
     return false;
   }
 
-  gfxContextMatrixAutoSaveRestore matrixRestore(aContext);
-  aContext->IdentityMatrix();
-
   nsSVGUtils::SetupCairoStrokeGeometry(aFrame, aContext, aOuterObjectPaint);
   float opacity = nsSVGUtils::GetOpacity(style->mStrokeOpacitySource,
                                          style->mStrokeOpacity,
                                          aOuterObjectPaint);
 
   SetupInheritablePaint(aContext, aFrame, opacity, aOuterObjectPaint,
                         aThisObjectPaint->mStrokePaint, &nsStyleSVG::mStroke,
                         nsSVGEffects::StrokeProperty());
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -55,16 +55,17 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include "stun_client_ctx.h"
 #include "stun_server_ctx.h"
 #include "turn_client_ctx.h"
 #include "ice_ctx.h"
 #include "ice_candidate.h"
 #include "ice_reg.h"
 #include "ice_util.h"
 #include "nr_socket_turn.h"
+#include "nr_socket.h"
 
 static int next_automatic_preference = 224;
 
 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand);
 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand);
 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
 #ifdef USE_TURN
@@ -377,18 +378,22 @@ int nr_ice_candidate_compute_priority(nr
         }
         else {
           ABORT(r);
         }
       }
     }
     else {
       char key_of_interface[MAXIFNAME + 41];
+      nr_transport_addr addr;
 
-      if(r=nr_transport_addr_fmt_ifname_addr_string(&cand->base,key_of_interface,
+      if(r=nr_socket_getaddr(cand->isock->sock, &addr))
+        ABORT(r);
+
+      if(r=nr_transport_addr_fmt_ifname_addr_string(&addr,key_of_interface,
          sizeof(key_of_interface))) {
         ABORT(r);
       }
       if(r=nr_interface_prioritizer_get_priority(cand->ctx->interface_prioritizer,
          key_of_interface,&interface_preference)) {
         ABORT(r);
       }
     }
--- a/media/webrtc/signaling/signaling.gyp
+++ b/media/webrtc/signaling/signaling.gyp
@@ -582,16 +582,17 @@
         './src/sipcc/include/ccapi_device_listener.h',
         './src/sipcc/include/ccapi_feature_info.h',
         './src/sipcc/include/ccapi_line.h',
         './src/sipcc/include/ccapi_line_info.h',
         './src/sipcc/include/ccapi_line_listener.h',
         './src/sipcc/include/ccapi_service.h',
         './src/sipcc/include/ccapi_types.h',
         './src/sipcc/include/ccsdp.h',
+        './src/sipcc/include/ccsdp_rtcp_fb.h',
         './src/sipcc/include/config_api.h',
         './src/sipcc/include/dns_util.h',
         './src/sipcc/include/plat_api.h',
         './src/sipcc/include/reset_api.h',
         './src/sipcc/include/sll_lite.h',
         './src/sipcc/include/vcm.h',
         './src/sipcc/include/xml_parser_defines.h',
 
--- a/media/webrtc/signaling/src/media-conduit/CodecConfig.h
+++ b/media/webrtc/signaling/src/media-conduit/CodecConfig.h
@@ -2,17 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef CODEC_CONFIG_H_
 #define CODEC_CONFIG_H_
 
 #include <string>
-
+#include "ccsdp_rtcp_fb.h"
 
 namespace mozilla {
 
 /**
  * Minimalistic Audio Codec Config Params
  */
 struct AudioCodecConfig
 {
@@ -51,21 +51,37 @@ struct AudioCodecConfig
 struct VideoCodecConfig
 {
   /*
    * The data-types for these properties mimic the
    * corresponding webrtc::VideoCodec data-types.
    */
   int mType;
   std::string mName;
+  uint32_t mRtcpFbTypes;
 
-  /* When we have resolution negotiation information (RFC 6236)
-   * it will be stored here.
-   */
+  VideoCodecConfig(int type,
+                   std::string name,
+                   int rtcpFbTypes): mType(type),
+                                     mName(name),
+                                     mRtcpFbTypes(rtcpFbTypes)
+  {
+  }
+
 
-  VideoCodecConfig(int type, std::string name): mType(type),
-                                                mName(name)
+  bool RtcpFbIsSet(sdp_rtcp_fb_nack_type_e type) const
+  {
+    return mRtcpFbTypes & sdp_rtcp_fb_nack_to_bitmap(type);
+  }
+
+  bool RtcpFbIsSet(sdp_rtcp_fb_ack_type_e type) const
   {
+    return mRtcpFbTypes & sdp_rtcp_fb_ack_to_bitmap(type);
+  }
+
+  bool RtcpFbIsSet(sdp_rtcp_fb_ccm_type_e type) const
+  {
+    return mRtcpFbTypes & sdp_rtcp_fb_ccm_to_bitmap(type);
   }
 
 };
 }
 #endif
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -1,15 +1,18 @@
 /* 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 "CSFLog.h"
 #include "nspr.h"
 
+// For rtcp-fb constants
+#include "ccsdp.h"
+
 #include "VideoConduit.h"
 #include "AudioConduit.h"
 #include "webrtc/video_engine/include/vie_errors.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidJNIWrapper.h"
 #endif
 
@@ -240,32 +243,16 @@ MediaConduitErrorCode WebrtcVideoConduit
   }
   // Turn on RTCP and loss feedback reporting.
   if(mPtrRTP->SetRTCPStatus(mChannel, webrtc::kRtcpCompound_RFC4585) != 0)
   {
     CSFLogError(logTag,  "%s RTCPStatus Failed %d ", __FUNCTION__,
                 mPtrViEBase->LastError());
     return kMediaConduitRTCPStatusError;
   }
-  // Enable pli as key frame request method.
-  if(mPtrRTP->SetKeyFrameRequestMethod(mChannel,
-                                    webrtc::kViEKeyFrameRequestPliRtcp) != 0)
-  {
-    CSFLogError(logTag,  "%s KeyFrameRequest Failed %d ", __FUNCTION__,
-                mPtrViEBase->LastError());
-    return kMediaConduitKeyFrameRequestError;
-  }
-  // Enable lossless transport
-  // XXX Note: We may want to disable this or limit it
-  if (mPtrRTP->SetNACKStatus(mChannel, true) != 0)
-  {
-    CSFLogError(logTag,  "%s NACKStatus Failed %d ", __FUNCTION__,
-                mPtrViEBase->LastError());
-    return kMediaConduitNACKStatusError;
-  }
   CSFLogError(logTag, "%s Initialization Done", __FUNCTION__);
   return kMediaConduitNoError;
 }
 
 void
 WebrtcVideoConduit::SyncTo(WebrtcAudioConduit *aConduit)
 {
   CSFLogDebug(logTag, "%s Synced to %p", __FUNCTION__, aConduit);
@@ -413,28 +400,37 @@ WebrtcVideoConduit::ConfigureSendMediaCo
     }
     CSFLogError(logTag, "%s SetSendCodec Failed %d ", __FUNCTION__,
                 mPtrViEBase->LastError());
     return kMediaConduitUnknownError;
   }
   mSendingWidth = 0;
   mSendingHeight = 0;
 
+  if(codecConfig->RtcpFbIsSet(SDP_RTCP_FB_NACK_BASIC)) {
+    CSFLogDebug(logTag, "Enabling NACK (send) for video stream\n");
+    if (mPtrRTP->SetNACKStatus(mChannel, true) != 0)
+    {
+      CSFLogError(logTag,  "%s NACKStatus Failed %d ", __FUNCTION__,
+                  mPtrViEBase->LastError());
+      return kMediaConduitNACKStatusError;
+    }
+  }
+
   if(mPtrViEBase->StartSend(mChannel) == -1)
   {
     CSFLogError(logTag, "%s Start Send Error %d ", __FUNCTION__,
                 mPtrViEBase->LastError());
     return kMediaConduitUnknownError;
   }
 
   //Copy the applied codec for future reference
   delete mCurSendCodecConfig;
 
-  mCurSendCodecConfig = new VideoCodecConfig(codecConfig->mType,
-                                             codecConfig->mName);
+  mCurSendCodecConfig = new VideoCodecConfig(*codecConfig);
 
   mPtrRTP->SetRembStatus(mChannel, true, false);
 
   // by now we should be successfully started the transmission
   mEngineTransmitting = true;
   return kMediaConduitNoError;
 }
 
@@ -467,28 +463,49 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
   }
 
   if(codecConfigList.empty())
   {
     CSFLogError(logTag, "%s Zero number of codecs to configure", __FUNCTION__);
     return kMediaConduitMalformedArgument;
   }
 
+  webrtc::ViEKeyFrameRequestMethod kf_request = webrtc::kViEKeyFrameRequestNone;
+  bool use_nack_basic = false;
+
   //Try Applying the codecs in the list
   // we treat as success if atleast one codec was applied and reception was
   // started successfully.
   for(std::vector<VideoCodecConfig*>::size_type i=0;i < codecConfigList.size();i++)
   {
     //if the codec param is invalid or diplicate, return error
     if((condError = ValidateCodecConfig(codecConfigList[i],false)) != kMediaConduitNoError)
     {
       return condError;
     }
 
+    // Check for the keyframe request type: PLI is preferred
+    // over FIR, and FIR is preferred over none.
+    if (codecConfigList[i]->RtcpFbIsSet(SDP_RTCP_FB_NACK_PLI))
+    {
+      kf_request = webrtc::kViEKeyFrameRequestPliRtcp;
+    } else if(kf_request == webrtc::kViEKeyFrameRequestNone &&
+              codecConfigList[i]->RtcpFbIsSet(SDP_RTCP_FB_CCM_FIR))
+    {
+      kf_request = webrtc::kViEKeyFrameRequestFirRtcp;
+    }
+
+    // Check whether NACK is requested
+    if(codecConfigList[i]->RtcpFbIsSet(SDP_RTCP_FB_NACK_BASIC))
+    {
+      use_nack_basic = true;
+    }
+
     webrtc::VideoCodec  video_codec;
+
     mEngineReceiving = false;
     memset(&video_codec, 0, sizeof(webrtc::VideoCodec));
     //Retrieve pre-populated codec structure for our codec.
     for(int idx=0; idx < mPtrViECodec->NumberOfCodecs(); idx++)
     {
       if(mPtrViECodec->GetCodec(idx, video_codec) == 0)
       {
         payloadName = video_codec.plName;
@@ -518,16 +535,61 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
   }//end for
 
   if(!success)
   {
     CSFLogError(logTag, "%s Setting Receive Codec Failed ", __FUNCTION__);
     return kMediaConduitInvalidReceiveCodec;
   }
 
+  // XXX Currently, we gather up all of the feedback types that the remote
+  // party indicated it supports for all video codecs and configure the entire
+  // conduit based on those capabilities. This is technically out of spec,
+  // as these values should be configured on a per-codec basis. However,
+  // the video engine only provides this API on a per-conduit basis, so that's
+  // how we have to do it. The approach of considering the remote capablities
+  // for the entire conduit to be a union of all remote codec capabilities
+  // (rather than the more conservative approach of using an intersection)
+  // is made to provide as many feedback mechanisms as are likely to be
+  // processed by the remote party (and should be relatively safe, since the
+  // remote party is required to ignore feedback types that it does not
+  // understand).
+  //
+  // Note that our configuration uses this union of remote capabilites as
+  // input to the configuration. It is not isomorphic to the configuration.
+  // For example, it only makes sense to have one frame request mechanism
+  // active at a time; so, if the remote party indicates more than one
+  // supported mechanism, we're only configuring the one we most prefer.
+  //
+  // See http://code.google.com/p/webrtc/issues/detail?id=2331
+
+  if (kf_request != webrtc::kViEKeyFrameRequestNone)
+  {
+    CSFLogDebug(logTag, "Enabling %s frame requests for video stream\n",
+                (kf_request == webrtc::kViEKeyFrameRequestPliRtcp ?
+                 "PLI" : "FIR"));
+    if(mPtrRTP->SetKeyFrameRequestMethod(mChannel, kf_request) != 0)
+    {
+      CSFLogError(logTag,  "%s KeyFrameRequest Failed %d ", __FUNCTION__,
+                  mPtrViEBase->LastError());
+      return kMediaConduitKeyFrameRequestError;
+    }
+  }
+
+  if(use_nack_basic)
+  {
+    CSFLogDebug(logTag, "Enabling NACK (recv) for video stream\n");
+    if (mPtrRTP->SetNACKStatus(mChannel, true) != 0)
+    {
+      CSFLogError(logTag,  "%s NACKStatus Failed %d ", __FUNCTION__,
+                  mPtrViEBase->LastError());
+      return kMediaConduitNACKStatusError;
+    }
+  }
+
   //Start Receive on the video engine
   if(mPtrViEBase->StartReceive(mChannel) == -1)
   {
     error = mPtrViEBase->LastError();
     CSFLogError(logTag, "%s Start Receive Error %d ", __FUNCTION__, error);
 
     return kMediaConduitUnknownError;
   }
@@ -784,18 +846,17 @@ WebrtcVideoConduit::CodecConfigToWebRTCC
   cinst.minBitrate = 200;
   cinst.startBitrate = 300;
   cinst.maxBitrate = 2000;
 }
 
 bool
 WebrtcVideoConduit::CopyCodecToDB(const VideoCodecConfig* codecInfo)
 {
-  VideoCodecConfig* cdcConfig = new VideoCodecConfig(codecInfo->mType,
-                                                     codecInfo->mName);
+  VideoCodecConfig* cdcConfig = new VideoCodecConfig(*codecInfo);
   mRecvCodecList.push_back(cdcConfig);
   return true;
 }
 
 /**
  * Checks if the codec is already in Conduit's database
  */
 
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -1481,17 +1481,18 @@ static int vcmRxStartICE_m(cc_mcapid_t m
       return VCM_ERROR;
 
     mozilla::VideoCodecConfig *config_raw;
 
     for(int i=0; i <num_payloads; i++)
     {
       config_raw = new mozilla::VideoCodecConfig(
         payloads[i].remote_rtp_pt,
-        ccsdpCodecName(payloads[i].codec_type));
+        ccsdpCodecName(payloads[i].codec_type),
+        payloads[i].video.rtcp_fb_types);
       configs.push_back(config_raw);
     }
 
     if (conduit->ConfigureRecvMediaCodecs(configs))
       return VCM_ERROR;
 
     // Now we have all the pieces, create the pipeline
     mozilla::RefPtr<mozilla::MediaPipeline> pipeline =
@@ -2112,17 +2113,18 @@ static int vcmTxStartICE_m(cc_mcapid_t m
 
     // Now we have all the pieces, create the pipeline
     stream->StorePipeline(pc_track_id, pipeline);
 
   } else if (CC_IS_VIDEO(mcap_id)) {
     mozilla::VideoCodecConfig *config_raw;
     config_raw = new mozilla::VideoCodecConfig(
       payload->remote_rtp_pt,
-      ccsdpCodecName(payload->codec_type));
+      ccsdpCodecName(payload->codec_type),
+      payload->video.rtcp_fb_types);
 
     // Take possession of this pointer
     mozilla::ScopedDeletePtr<mozilla::VideoCodecConfig> config(config_raw);
 
     // Instantiate an appropriate conduit
     mozilla::RefPtr<mozilla::VideoSessionConduit> conduit =
       mozilla::VideoSessionConduit::Create();
 
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -4537,31 +4537,31 @@ gsmsdp_add_rtcp_fb (int level, sdp_t *sd
     for (pt_index = 1; pt_index <= num_pts; pt_index++) {
         pt_codec = sdp_get_media_payload_type (sdp_p, level, pt_index,
                                                &indicator);
         if ((pt_codec & 0xFF) == codec) {
             int pt = GET_DYN_PAYLOAD_TYPE_VALUE(pt_codec);
 
             /* Add requested a=rtcp-fb:nack attributes */
             for (j = 0; j < SDP_MAX_RTCP_FB_NACK; j++) {
-                if (types & SDP_RTCP_FB_NACK_TO_BITMAP(j)) {
+                if (types & sdp_rtcp_fb_nack_to_bitmap(j)) {
                     gsmsdp_set_rtcp_fb_nack_attribute(level, sdp_p, pt, j);
                 }
             }
 
             /* Add requested a=rtcp-fb:ack attributes */
             for (j = 0; j < SDP_MAX_RTCP_FB_ACK; j++) {
-                if (types & SDP_RTCP_FB_ACK_TO_BITMAP(j)) {
+                if (types & sdp_rtcp_fb_ack_to_bitmap(j)) {
                     gsmsdp_set_rtcp_fb_nack_attribute(level, sdp_p, pt, j);
                 }
             }
 
             /* Add requested a=rtcp-fb:ccm attributes */
             for (j = 0; j < SDP_MAX_RTCP_FB_CCM; j++) {
-                if (types & SDP_RTCP_FB_CCM_TO_BITMAP(j)) {
+                if (types & sdp_rtcp_fb_ccm_to_bitmap(j)) {
                     gsmsdp_set_rtcp_fb_ccm_attribute(level, sdp_p, pt, j);
                 }
             }
 
         }
     }
     return CC_CAUSE_OK;
 }
@@ -4621,52 +4621,52 @@ gsmsdp_negotiate_rtcp_fb (cc_sdp_t *cc_s
         fb_types = 0;
 
         /* a=rtcp-fb:nack */
         i = 1;
         do {
             nack_type = sdp_attr_get_rtcp_fb_nack(cc_sdp_p->dest_sdp,
                                                   level, remote_pt, i);
             if (nack_type >= 0 && nack_type < SDP_MAX_RTCP_FB_NACK) {
-                fb_types |= SDP_RTCP_FB_NACK_TO_BITMAP(nack_type);
+                fb_types |= sdp_rtcp_fb_nack_to_bitmap(nack_type);
             }
             i++;
         } while (nack_type != SDP_RTCP_FB_NACK_NOT_FOUND);
 
         /* a=rtcp-fb:ack */
         i = 1;
         do {
             ack_type = sdp_attr_get_rtcp_fb_ack(cc_sdp_p->dest_sdp,
                                                 level, remote_pt, i);
             if (ack_type >= 0 && ack_type < SDP_MAX_RTCP_FB_ACK) {
-                fb_types |= SDP_RTCP_FB_ACK_TO_BITMAP(ack_type);
+                fb_types |= sdp_rtcp_fb_ack_to_bitmap(ack_type);
             }
             i++;
         } while (ack_type != SDP_RTCP_FB_ACK_NOT_FOUND);
 
         /* a=rtcp-fb:ccm */
         i = 1;
         do {
             ccm_type = sdp_attr_get_rtcp_fb_ccm(cc_sdp_p->dest_sdp,
                                                 level, remote_pt, i);
             if (ccm_type >= 0 && ccm_type < SDP_MAX_RTCP_FB_CCM) {
-                fb_types |= SDP_RTCP_FB_CCM_TO_BITMAP(ccm_type);
+                fb_types |= sdp_rtcp_fb_ccm_to_bitmap(ccm_type);
             }
             i++;
         } while (ccm_type != SDP_RTCP_FB_CCM_NOT_FOUND);
 
         /*
          * Mask out the types that we do not support
          */
         switch (codec) {
             case RTP_VP8:
                 fb_types &=
-                  SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_BASIC) |
-                  SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_PLI) |
-                  SDP_RTCP_FB_CCM_TO_BITMAP(SDP_RTCP_FB_CCM_FIR);
+                  sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_BASIC) |
+                  sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_PLI) |
+                  sdp_rtcp_fb_ccm_to_bitmap(SDP_RTCP_FB_CCM_FIR);
                 break;
             default:
                 fb_types = 0;
         }
 
         /*
          * Now, in our local SDP, set rtcp-fb types that both we and the
          * remote party support
@@ -5584,19 +5584,19 @@ gsmsdp_add_media_line (fsmdef_dcb_t *dcb
 
         if (media->support_direction != SDP_DIRECTION_INACTIVE) {
 
           gsmsdp_set_local_sdp_direction(dcb_p, media, media->direction);
 
           /* Add supported rtcp-fb types */
           if (media_cap->type == SDP_MEDIA_VIDEO) {
               gsmsdp_add_rtcp_fb (level, dcb_p->sdp->src_sdp, RTP_VP8,
-                  SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_BASIC) |
-                  SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_PLI) |
-                  SDP_RTCP_FB_CCM_TO_BITMAP(SDP_RTCP_FB_CCM_FIR));
+                  sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_BASIC) |
+                  sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_PLI) |
+                  sdp_rtcp_fb_ccm_to_bitmap(SDP_RTCP_FB_CCM_FIR));
           }
 
           /* setup and connection attributes */
           gsmsdp_set_setup_attribute(level, dcb_p->sdp->src_sdp, media->setup);
 
           /* This is a new media line so we should send connection:new */
           gsmsdp_set_connection_attribute(level, dcb_p->sdp->src_sdp,
             SDP_CONNECTION_NEW);
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
@@ -469,74 +469,24 @@ typedef enum {
 
 typedef enum {
     SDP_RTCP_UNICAST_MODE_REFLECTION,
     SDP_RTCP_UNICAST_MODE_RSI,
     SDP_RTCP_MAX_UNICAST_MODE,
     SDP_RTCP_UNICAST_MODE_NOT_PRESENT
 } sdp_rtcp_unicast_mode_e;
 
-/* a=rtcp-fb enumerations */
-
-typedef enum {
-    SDP_RTCP_FB_ANY = -1,
-    SDP_RTCP_FB_ACK = 0,
-    SDP_RTCP_FB_CCM,
-    SDP_RTCP_FB_NACK,
-    SDP_RTCP_FB_TRR_INT,
-    SDP_MAX_RTCP_FB,
-    SDP_RTCP_FB_UNKNOWN
-} sdp_rtcp_fb_type_e;
-
-typedef enum {
-    SDP_RTCP_FB_NACK_NOT_FOUND = -1,
-    SDP_RTCP_FB_NACK_BASIC = 0,
-    SDP_RTCP_FB_NACK_SLI,
-    SDP_RTCP_FB_NACK_PLI,
-    SDP_RTCP_FB_NACK_RPSI,
-    SDP_RTCP_FB_NACK_APP,
-    SDP_RTCP_FB_NACK_RAI,
-    SDP_RTCP_FB_NACK_TLLEI,
-    SDP_RTCP_FB_NACK_PSLEI,
-    SDP_RTCP_FB_NACK_ECN,
-    SDP_MAX_RTCP_FB_NACK,
-    SDP_RTCP_FB_NACK_UNKNOWN
-} sdp_rtcp_fb_nack_type_e;
-
-typedef enum {
-    SDP_RTCP_FB_ACK_NOT_FOUND = -1,
-    SDP_RTCP_FB_ACK_RPSI = 0,
-    SDP_RTCP_FB_ACK_APP,
-    SDP_MAX_RTCP_FB_ACK,
-    SDP_RTCP_FB_ACK_UNKNOWN
-} sdp_rtcp_fb_ack_type_e;
-
-typedef enum {
-    SDP_RTCP_FB_CCM_NOT_FOUND = -1,
-    SDP_RTCP_FB_CCM_FIR = 0,
-    SDP_RTCP_FB_CCM_TMMBR,
-    SDP_RTCP_FB_CCM_TSTR,
-    SDP_RTCP_FB_CCM_VBCM,
-    SDP_MAX_RTCP_FB_CCM,
-    SDP_RTCP_FB_CCM_UNKNOWN
-} sdp_rtcp_fb_ccm_type_e;
-
 typedef enum {
     SDP_CONNECTION_NOT_FOUND = -1,
     SDP_CONNECTION_NEW = 0,
     SDP_CONNECTION_EXISTING,
     SDP_MAX_CONNECTION,
     SDP_CONNECTION_UNKNOWN
 } sdp_connection_type_e;
 
-#define SDP_RTCP_FB_NACK_TO_BITMAP(type) (1 << (type))
-#define SDP_RTCP_FB_ACK_TO_BITMAP(type)  (1 << (SDP_MAX_RTCP_FB_NACK + (type)))
-#define SDP_RTCP_FB_CCM_TO_BITMAP(type)  (1 << (SDP_MAX_RTCP_FB_NACK + \
-                                                SDP_MAX_RTCP_FB_ACK + (type)))
-
 /*
  * sdp_srtp_fec_order_t
  *  This type defines the order in which to perform FEC
  *  (Forward Error Correction) and SRTP Encryption/Authentication.
  */
 typedef enum sdp_srtp_fec_order_t_ {
     SDP_SRTP_THEN_FEC, /* upon sending perform SRTP then FEC */
     SDP_FEC_THEN_SRTP, /* upon sending perform FEC then SRTP */
--- a/media/webrtc/signaling/src/sipcc/include/ccsdp.h
+++ b/media/webrtc/signaling/src/sipcc/include/ccsdp.h
@@ -42,16 +42,17 @@
  *             attribute is specified for.
  * </pre>
  */
 
 #ifndef __CCSDP_H__
 #define __CCSDP_H__
 
 #include "cpr_types.h"
+#include "ccsdp_rtcp_fb.h"
 
 #define SIPSDP_ILBC_MODE20 20
 
 /**
  * Return codes for sdp helper APIs
  */
 typedef enum rtp_ptype_
 {
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/sipcc/include/ccsdp_rtcp_fb.h
@@ -0,0 +1,96 @@
+/* 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 __CCSDP_RTCP_FB_H__
+#define __CCSDP_RTCP_FB_H__
+
+/* a=rtcp-fb enumerations */
+
+typedef enum {
+    SDP_RTCP_FB_ANY = -1,
+    SDP_RTCP_FB_ACK = 0,
+    SDP_RTCP_FB_CCM,
+    SDP_RTCP_FB_NACK,
+    SDP_RTCP_FB_TRR_INT,
+    SDP_MAX_RTCP_FB,
+    SDP_RTCP_FB_UNKNOWN
+} sdp_rtcp_fb_type_e;
+
+typedef enum {
+    SDP_RTCP_FB_NACK_NOT_FOUND = -1,
+    SDP_RTCP_FB_NACK_BASIC = 0,
+    SDP_RTCP_FB_NACK_SLI,
+    SDP_RTCP_FB_NACK_PLI,
+    SDP_RTCP_FB_NACK_RPSI,
+    SDP_RTCP_FB_NACK_APP,
+    SDP_RTCP_FB_NACK_RAI,
+    SDP_RTCP_FB_NACK_TLLEI,
+    SDP_RTCP_FB_NACK_PSLEI,
+    SDP_RTCP_FB_NACK_ECN,
+    SDP_MAX_RTCP_FB_NACK,
+    SDP_RTCP_FB_NACK_UNKNOWN
+} sdp_rtcp_fb_nack_type_e;
+
+typedef enum {
+    SDP_RTCP_FB_ACK_NOT_FOUND = -1,
+    SDP_RTCP_FB_ACK_RPSI = 0,
+    SDP_RTCP_FB_ACK_APP,
+    SDP_MAX_RTCP_FB_ACK,
+    SDP_RTCP_FB_ACK_UNKNOWN
+} sdp_rtcp_fb_ack_type_e;
+
+typedef enum {
+    SDP_RTCP_FB_CCM_NOT_FOUND = -1,
+    SDP_RTCP_FB_CCM_FIR = 0,
+    SDP_RTCP_FB_CCM_TMMBR,
+    SDP_RTCP_FB_CCM_TSTR,
+    SDP_RTCP_FB_CCM_VBCM,
+    SDP_MAX_RTCP_FB_CCM,
+    SDP_RTCP_FB_CCM_UNKNOWN
+} sdp_rtcp_fb_ccm_type_e;
+
+#ifdef __cplusplus
+static_assert(SDP_MAX_RTCP_FB_NACK +
+              SDP_MAX_RTCP_FB_ACK +
+              SDP_MAX_RTCP_FB_CCM < 32,
+              "rtcp-fb Bitmap is larger than 32 bits");
+#endif
+
+static int32_t
+sdp_rtcp_fb_nack_to_bitmap(sdp_rtcp_fb_nack_type_e type)
+{
+  int bitnumber = type;
+
+  if (type < 0 || type >= SDP_MAX_RTCP_FB_NACK) {
+    return 0;
+  }
+
+  return (1 << bitnumber);
+}
+
+static int32_t
+sdp_rtcp_fb_ack_to_bitmap(sdp_rtcp_fb_ack_type_e type)
+{
+  int bitnumber = type + SDP_MAX_RTCP_FB_NACK;
+
+  if (type < 0 || type >= SDP_MAX_RTCP_FB_ACK) {
+    return 0;
+  }
+
+  return (1 << bitnumber);
+}
+
+static int32_t
+sdp_rtcp_fb_ccm_to_bitmap(sdp_rtcp_fb_ccm_type_e type)
+{
+  int bitnumber = type + SDP_MAX_RTCP_FB_NACK + SDP_MAX_RTCP_FB_ACK;
+
+  if (type < 0 || type >= SDP_MAX_RTCP_FB_CCM) {
+    return 0;
+  }
+
+  return (1 << bitnumber);
+}
+
+#endif
--- a/media/webrtc/signaling/test/mediaconduit_unittests.cpp
+++ b/media/webrtc/signaling/test/mediaconduit_unittests.cpp
@@ -265,17 +265,17 @@ void AudioSendAndReceive::GenerateMusic(
 
 //Hardcoded for 16 bit samples for now
 void AudioSendAndReceive::GenerateAndReadSamples()
 {
    int16_t audioInput[PLAYOUT_SAMPLE_LENGTH];
    int16_t audioOutput[PLAYOUT_SAMPLE_LENGTH];
    short* inbuf;
    int sampleLengthDecoded = 0;
-   int SAMPLES = (PLAYOUT_SAMPLE_FREQUENCY * 10); //10 seconds
+   unsigned int SAMPLES = (PLAYOUT_SAMPLE_FREQUENCY * 10); //10 seconds
    int CHANNELS = 1; //mono audio
    int sampleLengthInBytes = sizeof(audioInput);
    //generated audio buffer
    inbuf = (short *)moz_xmalloc(sizeof(short)*SAMPLES*CHANNELS);
    memset(audioInput,0,sampleLengthInBytes);
    memset(audioOutput,0,sampleLengthInBytes);
    MOZ_ASSERT(SAMPLES <= PLAYOUT_SAMPLE_LENGTH);
 
@@ -294,17 +294,17 @@ void AudioSendAndReceive::GenerateAndRea
    //Create input file with the music
    WriteWaveHeader(PLAYOUT_SAMPLE_FREQUENCY, 1, inFile);
    GenerateMusic(inbuf, SAMPLES);
    fwrite(inbuf,1,SAMPLES*sizeof(inbuf[0])*CHANNELS,inFile);
    FinishWaveHeader(inFile);
    fclose(inFile);
 
    WriteWaveHeader(PLAYOUT_SAMPLE_FREQUENCY, 1, outFile);
-   int numSamplesReadFromInput = 0;
+   unsigned int numSamplesReadFromInput = 0;
    do
    {
     if(!memcpy(audioInput, inbuf, sampleLengthInBytes))
     {
       return;
     }
 
     numSamplesReadFromInput += PLAYOUT_SAMPLE_LENGTH;
@@ -568,18 +568,18 @@ class TransportConduitTest : public ::te
     err = mVideoSession2->AttachRenderer(mVideoRenderer);
     ASSERT_EQ(mozilla::kMediaConduitNoError, err);
     err = mVideoSession->AttachTransport(mVideoTransport);
     ASSERT_EQ(mozilla::kMediaConduitNoError, err);
     err = mVideoSession2->AttachTransport(mVideoTransport);
     ASSERT_EQ(mozilla::kMediaConduitNoError, err);
 
     //configure send and recv codecs on theconduit
-    mozilla::VideoCodecConfig cinst1(120, "VP8");
-    mozilla::VideoCodecConfig cinst2(124, "I420");
+    mozilla::VideoCodecConfig cinst1(120, "VP8", 0);
+    mozilla::VideoCodecConfig cinst2(124, "I420", 0);
 
 
     std::vector<mozilla::VideoCodecConfig* > rcvCodecList;
     rcvCodecList.push_back(&cinst1);
     rcvCodecList.push_back(&cinst2);
 
     err = mVideoSession->ConfigureSendMediaCodec(&cinst1);
     ASSERT_EQ(mozilla::kMediaConduitNoError, err);
@@ -632,35 +632,35 @@ class TransportConduitTest : public ::te
 
     std::vector<mozilla::VideoCodecConfig* > rcvCodecList;
 
     //Same APIs
     cerr << "   *************************************************" << endl;
     cerr << "    1. Same Codec (VP8) Repeated Twice " << endl;
     cerr << "   *************************************************" << endl;
 
-    mozilla::VideoCodecConfig cinst1(120, "VP8");
-    mozilla::VideoCodecConfig cinst2(120, "VP8");
+    mozilla::VideoCodecConfig cinst1(120, "VP8", 0);
+    mozilla::VideoCodecConfig cinst2(120, "VP8", 0);
     rcvCodecList.push_back(&cinst1);
     rcvCodecList.push_back(&cinst2);
     err = mVideoSession->ConfigureRecvMediaCodecs(rcvCodecList);
     EXPECT_NE(err,mozilla::kMediaConduitNoError);
     rcvCodecList.pop_back();
     rcvCodecList.pop_back();
 
 
     PR_Sleep(PR_SecondsToInterval(2));
     cerr << "   *************************************************" << endl;
     cerr << "    2. Codec With Invalid Payload Names " << endl;
     cerr << "   *************************************************" << endl;
     cerr << "   Setting payload 1 with name: I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676" << endl;
     cerr << "   Setting payload 2 with name of zero length" << endl;
 
-    mozilla::VideoCodecConfig cinst3(124, "I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676");
-    mozilla::VideoCodecConfig cinst4(124, "");
+    mozilla::VideoCodecConfig cinst3(124, "I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676", 0);
+    mozilla::VideoCodecConfig cinst4(124, "", 0);
 
     rcvCodecList.push_back(&cinst3);
     rcvCodecList.push_back(&cinst4);
 
     err = mVideoSession->ConfigureRecvMediaCodecs(rcvCodecList);
     EXPECT_TRUE(err != mozilla::kMediaConduitNoError);
     rcvCodecList.pop_back();
     rcvCodecList.pop_back();
--- a/mobile/android/themes/core/aboutMemory.css
+++ b/mobile/android/themes/core/aboutMemory.css
@@ -1,15 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
- * This file is used for both about:memory and about:compartments.
- *
  * The version used for desktop is located at
  * toolkit/components/aboutmemory/content/aboutMemory.css.
  * Mobile-specific stuff is at the bottom of this file.
  */
 
 html {
   background: -moz-Dialog;
   font: message-box;
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -200,17 +200,17 @@ pref("media.wave.enabled", true);
 #endif
 #ifdef MOZ_WEBM
 pref("media.webm.enabled", true);
 #endif
 #ifdef MOZ_DASH
 pref("media.dash.enabled", false);
 #endif
 #ifdef MOZ_GSTREAMER
-pref("media.gstreamer.enabled", false);
+pref("media.gstreamer.enabled", true);
 #endif
 #ifdef MOZ_WEBRTC
 pref("media.navigator.enabled", true);
 pref("media.navigator.video.default_width",640);
 pref("media.navigator.video.default_height",480);
 pref("media.navigator.video.default_fps",30);
 pref("media.navigator.video.default_minfps",10);
 pref("media.peerconnection.enabled", true);
--- a/netwerk/test/unit/test_unix_domain.js
+++ b/netwerk/test/unit/test_unix_domain.js
@@ -86,22 +86,29 @@ function test_echo()
       // The client socket is anonymous, so the server transport should
       // have an empty peer address.
       do_check_eq(connection.host, '');
       do_check_eq(connection.port, 0);
       let connectionPeerAddr = connection.getScriptablePeerAddr();
       do_check_eq(connectionPeerAddr.family, Ci.nsINetAddr.FAMILY_LOCAL);
       do_check_eq(connectionPeerAddr.address, '');
 
-      let serverInput = new ScriptableInputStream(connection.openInputStream(0, 0, 0));
+      let serverAsyncInput = connection.openInputStream(0, 0, 0).QueryInterface(Ci.nsIAsyncInputStream);
       let serverOutput = connection.openOutputStream(0, 0, 0);
 
-      // Receive data from the client, and send back a response.
-      do_check_eq(serverInput.readBytes(17), "Mervyn Murgatroyd");
-      serverOutput.write("Ruthven Murgatroyd", 18);
+      serverAsyncInput.asyncWait(function (aStream) {
+        do_print("called test_echo's server's onInputStreamReady");
+        let serverScriptableInput = new ScriptableInputStream(aStream);
+
+        // Receive data from the client, and send back a response.
+        do_check_eq(serverScriptableInput.readBytes(17), "Mervyn Murgatroyd");
+        do_print("server has read message from client");
+        serverOutput.write("Ruthven Murgatroyd", 18);
+        do_print("server has written to client");
+      }, 0, 0, threadManager.currentThread);
     },
 
     onStopListening: function(aServ, aStatus) {
       do_print("called test_echo's onStopListening");
       log += 's';
 
       do_check_eq(aServ, server);
       do_check_eq(log, 'acs');
@@ -115,34 +122,37 @@ function test_echo()
   do_check_eq(client.host, socketName.path);
   do_check_eq(client.port, 0);
 
   let clientAsyncInput = client.openInputStream(0, 0, 0).QueryInterface(Ci.nsIAsyncInputStream);
   let clientInput = new ScriptableInputStream(clientAsyncInput);
   let clientOutput = client.openOutputStream(0, 0, 0);
 
   clientOutput.write("Mervyn Murgatroyd", 17);
+  do_print("client has written to server");
+
   clientAsyncInput.asyncWait(function (aStream) {
-    do_print("called test_echo's onInputStreamReady");
+    do_print("called test_echo's client's onInputStreamReady");
     log += 'c';
 
     do_check_eq(aStream, clientAsyncInput);
 
     // Now that the connection has been established, we can check the
     // transport's self and peer addresses.
     let clientSelfAddr = client.getScriptableSelfAddr();
     do_check_eq(clientSelfAddr.family, Ci.nsINetAddr.FAMILY_LOCAL);
     do_check_eq(clientSelfAddr.address, '');
 
     do_check_eq(client.host, socketName.path); // re-check, but hey
     let clientPeerAddr = client.getScriptablePeerAddr();
     do_check_eq(clientPeerAddr.family, Ci.nsINetAddr.FAMILY_LOCAL);
     do_check_eq(clientPeerAddr.address, socketName.path);
 
     do_check_eq(clientInput.readBytes(18), "Ruthven Murgatroyd");
+    do_print("client has read message from server");
 
     server.close();
   }, 0, 0, threadManager.currentThread);
 }
 
 // Create client and server sockets using a path that's too long.
 function test_name_too_long()
 {
@@ -354,42 +364,47 @@ function test_connect_permission()
       client3AsyncInput.asyncWait(client3InputStreamReady, 0, 0, threadManager.currentThread);
     }, 0, 0, threadManager.currentThread);
   }, 0, 0, threadManager.currentThread);
 
   function socketAccepted(aServ, aTransport) {
     do_print("called test_connect_permission's onSocketAccepted");
     log += 'a';
 
-    let serverInput = new ScriptableInputStream(aTransport.openInputStream(0, 0, 0));
+    let serverInput = aTransport.openInputStream(0, 0, 0).QueryInterface(Ci.nsIAsyncInputStream);
     let serverOutput = aTransport.openOutputStream(0, 0, 0);
 
-    // Receive data from the client, and send back a response.
-    do_check_eq(serverInput.readBytes(8), "Hanratty");
-    serverOutput.write("Ferlingatti", 11);
+    serverInput.asyncWait(function (aStream) {
+      do_print("called test_connect_permission's socketAccepted's onInputStreamReady");
+      log += 'i';
+
+      // Receive data from the client, and send back a response.
+      let serverScriptableInput = new ScriptableInputStream(serverInput);
+      do_check_eq(serverScriptableInput.readBytes(8), "Hanratty");
+      serverOutput.write("Ferlingatti", 11);
+    }, 0, 0, threadManager.currentThread);
   }
 
   function client3InputStreamReady(aStream) {
     do_print("called client3's onInputStreamReady");
     log += '3';
 
     let client3Input = new ScriptableInputStream(aStream);
 
     do_check_eq(client3Input.readBytes(11), "Ferlingatti");
 
-    aStream.close();
     client3.close(Cr.NS_OK);
     server.close();
   }
 
   function stopListening(aServ, aStatus) {
     do_print("called test_connect_permission's server's stopListening");
     log += 's';
 
-    do_check_eq(log, '12a3s');
+    do_check_eq(log, '12ai3s');
 
     run_next_test();
   }
 }
 
 // Creating a socket with a long filename doesn't crash.
 function test_long_socket_name()
 {
--- a/python/mozboot/mozboot/debian.py
+++ b/python/mozboot/mozboot/debian.py
@@ -1,31 +1,49 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-import os
+# 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/.
 
 from mozboot.base import BaseBootstrapper
 
 class DebianBootstrapper(BaseBootstrapper):
+    # These are common packages for all Debian-derived distros (such as
+    # Ubuntu).
+    COMMON_PACKAGES = [
+        'autoconf2.13',
+        'build-essential',
+        'ccache',
+        'libasound2-dev',
+        'libcurl4-openssl-dev',
+        'libdbus-1-dev',
+        'libdbus-glib-1-dev',
+        'libgconf2-dev',
+        'libgstreamer0.10-dev',
+        'libgstreamer-plugins-base0.10-dev',
+        'libgtk2.0-dev',
+        'libiw-dev',
+        'libnotify-dev',
+        'libxt-dev',
+        'mercurial',
+        'mesa-common-dev',
+        'python-dev',
+        'unzip',
+        'uuid',
+        'yasm',
+        'xvfb',
+        'zip',
+    ]
+
+    # Subclasses can add packages to this variable to have them installed.
+    DISTRO_PACKAGES = []
+
     def __init__(self, version, dist_id):
         BaseBootstrapper.__init__(self)
 
         self.version = version
         self.dist_id = dist_id
 
     def install_system_packages(self):
-        self.run_as_root(['apt-get', 'build-dep', 'iceweasel'])
+        packages = self.COMMON_PACKAGES + self.DISTRO_PACKAGES
+        self.apt_install(*packages)
 
-        self.apt_install(
-            'autoconf2.13',
-            'libasound2-dev',
-            'libcurl4-openssl-dev',
-            'libgstreamer0.10-dev',
-            'libgstreamer-plugins-base0.10-dev',
-            'libiw-dev',
-            'libnotify-dev',
-            'libxt-dev',
-            'mercurial',
-            'mesa-common-dev',
-            'uuid',
-            'yasm')
+    def _update_package_manager(self):
+        self.run_as_root(['apt-get', 'update'])
--- a/python/mozboot/mozboot/ubuntu.py
+++ b/python/mozboot/mozboot/ubuntu.py
@@ -1,39 +1,38 @@
 # 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/.
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import os
 
-from mozboot.base import BaseBootstrapper
-
-class UbuntuBootstrapper(BaseBootstrapper):
-    def __init__(self, version, dist_id):
-        BaseBootstrapper.__init__(self)
+from mozboot.debian import DebianBootstrapper
 
-        self.version = version
-        self.dist_id = dist_id
-
-    def install_system_packages(self):
-        self.run_as_root(['apt-get', 'build-dep', 'firefox'])
 
-        self.apt_install(
-            'autoconf2.13',
-            'libasound2-dev',
-            'libcurl4-openssl-dev',
-            'libgstreamer0.10-dev',
-            'libgstreamer-plugins-base0.10-dev',
-            'libiw-dev',
-            'libnotify-dev',
-            'libxt-dev',
-            'mercurial',
-            'mesa-common-dev',
-            'uuid',
-            'yasm')
+MERCURIAL_PPA = '''
+Ubuntu does not provide a modern Mercurial in its package repository. So,
+we will install a PPA that does.
+'''.strip()
 
-    def _update_package_manager(self):
-        self.run_as_root(['apt-get', 'update'])
+# Ubuntu shares much logic with Debian, so it inherits from it.
+class UbuntuBootstrapper(DebianBootstrapper):
+    DISTRO_PACKAGES = [
+        # This contains add-apt-repository.
+        'software-properties-common',
+    ]
 
     def upgrade_mercurial(self, current):
-        self._ensure_package_manager_updated()
+        # Ubuntu releases up through at least 13.04 don't ship a modern
+        # Mercurial. So we hook up a PPA that provides one.
+        self._add_ppa('mercurial-ppa/releases')
+        self._update_package_manager()
         self.apt_install('mercurial')
 
+    def _add_ppa(self, ppa):
+        # Detect PPAs that have already been added. Sadly add-apt-repository
+        # doesn't do this for us and will import keys, etc every time. This
+        # incurs a user prompt and is annoying, so we try to prevent it.
+        list_file = ppa.replace('/', '-')
+        for source in os.listdir('/etc/apt/sources.list.d'):
+            if source.startswith(list_file) and source.endswith('.list'):
+                return
+
+        self.run_as_root(['add-apt-repository', 'ppa:%s' % ppa])
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -141,16 +141,17 @@ class TreeMetadataEmitter(LoggingMixin):
             IS_COMPONENT='IS_COMPONENT',
             JS_MODULES_PATH='JS_MODULES_PATH',
             LIBRARY_NAME='LIBRARY_NAME',
             LIBS='LIBS',
             LIBXUL_LIBRARY='LIBXUL_LIBRARY',
             MODULE='MODULE',
             MSVC_ENABLE_PGO='MSVC_ENABLE_PGO',
             NO_DIST_INSTALL='NO_DIST_INSTALL',
+            OS_LIBS='OS_LIBS',
             SDK_LIBRARY='SDK_LIBRARY',
             SHARED_LIBRARY_LIBS='SHARED_LIBRARY_LIBS',
             SIMPLE_PROGRAMS='SIMPLE_PROGRAMS',
             SSRCS='SSRCS',
         )
         for mak, moz in varmap.items():
             if sandbox[moz]:
                 passthru.variables[mak] = sandbox[moz]
--- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
@@ -234,16 +234,22 @@ VARIABLES = {
     'LOCAL_INCLUDES': (StrictOrderingOnAppendList, list, [],
         """Additional directories to be searched for include files by the compiler.
         """),
 
     'MSVC_ENABLE_PGO': (bool, bool, False,
         """Whether profile-guided optimization is enabled in this directory.
         """),
 
+    'OS_LIBS': (list, list, [],
+        """System link libraries.
+
+        This variable contains a list of system libaries to link against.
+        """),
+
     'SDK_LIBRARY': (StrictOrderingOnAppendList, list, [],
         """Elements of the distributed SDK.
 
         Files on this list will be copied into SDK_LIB_DIR ($DIST/sdk/lib).
         """),
 
     'SHARED_LIBRARY_LIBS': (StrictOrderingOnAppendList, list, [],
         """Libraries linked into a shared library.
--- a/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
@@ -23,16 +23,18 @@ GTEST_CPP_SOURCES = ['test1.cpp', 'test2
 HOST_CPPSRCS = ['bar.cpp', 'foo.cpp']
 HOST_CSRCS = ['bar.c', 'foo.c']
 
 HOST_LIBRARY_NAME = 'host_bar'
 
 LIBRARY_NAME = 'lib_name'
 LIBS = ['bar.lib', 'foo.lib']
 
+OS_LIBS = ['foo.so', '-l123', 'bar.a']
+
 SDK_LIBRARY = ['bar.sdk', 'foo.sdk']
 
 SHARED_LIBRARY_LIBS += ['bar.sll', 'foo.sll']
 
 SIMPLE_PROGRAMS = ['bar.x', 'foo.x']
 
 CSRCS += ['bar.c', 'foo.c']
 
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -207,16 +207,21 @@ class TestRecursiveMakeBackend(BackendTe
                 'LIBRARY_NAME := lib_name',
             ],
             'LIBXUL_LIBRARY': [
                 'LIBXUL_LIBRARY := 1',
             ],
             'MSVC_ENABLE_PGO': [
                 'MSVC_ENABLE_PGO := 1',
             ],
+            'OS_LIBS': [
+                'OS_LIBS += foo.so',
+                'OS_LIBS += -l123',
+                'OS_LIBS += bar.a',
+            ],
             'SDK_LIBRARY': [
                 'SDK_LIBRARY += bar.sdk',
                 'SDK_LIBRARY += foo.sdk',
             ],
             'SHARED_LIBRARY_LIBS': [
                 'SHARED_LIBRARY_LIBS += bar.sll',
                 'SHARED_LIBRARY_LIBS += foo.sll',
             ],
--- a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
@@ -23,16 +23,18 @@ GTEST_CPP_SOURCES = ['test1.cpp', 'test2
 HOST_CPPSRCS += ['fans.cpp', 'tans.cpp']
 HOST_CSRCS += ['fans.c', 'tans.c']
 
 HOST_LIBRARY_NAME = 'host_fans'
 
 LIBRARY_NAME = 'lib_name'
 LIBS += ['fans.lib', 'tans.lib']
 
+OS_LIBS += ['foo.so', '-l123', 'aaa.a']
+
 SDK_LIBRARY += ['fans.sdk', 'tans.sdk']
 
 SHARED_LIBRARY_LIBS += ['fans.sll', 'tans.sll']
 
 SIMPLE_PROGRAMS += ['fans.x', 'tans.x']
 
 CSRCS += ['fans.c', 'tans.c']
 
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -149,16 +149,17 @@ class TestEmitterBasic(unittest.TestCase
             HOST_LIBRARY_NAME='host_fans',
             IS_COMPONENT=True,
             LIBRARY_NAME='lib_name',
             LIBS=['fans.lib', 'tans.lib'],
             LIBXUL_LIBRARY=True,
             MSVC_ENABLE_PGO=True,
             NO_DIST_INSTALL=True,
             MODULE='module_name',
+            OS_LIBS=['foo.so', '-l123', 'aaa.a'],
             SDK_LIBRARY=['fans.sdk', 'tans.sdk'],
             SHARED_LIBRARY_LIBS=['fans.sll', 'tans.sll'],
             SIMPLE_PROGRAMS=['fans.x', 'tans.x'],
             SSRCS=['fans.S', 'tans.S'],
         )
 
         variables = objs[1].variables
         self.assertEqual(len(variables), len(wanted))
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -4,16 +4,19 @@
  */
 "use strict";
 
 const { 'classes': Cc, 'interfaces': Ci, 'utils': Cu, 'results': Cr } = Components;
 
 let { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 let { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
 let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+let { Promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let { HttpServer } = Cu.import("resource://testing-common/httpd.js", {});
+let { ctypes } = Cu.import("resource://gre/modules/ctypes.jsm");