Merge latest green fx-team changeset and mozilla-central
authorEd Morley <emorley@mozilla.com>
Thu, 12 Sep 2013 12:07:04 +0100
changeset 146780 ca8fd217b83639254d906e0184d68c6efcd79a6a
parent 146779 23708fab4a390389063e3d644a42db84178499f0 (current diff)
parent 146775 a9d76ddf0ee2caeee5ccfb7fa4e2f40a11cb6d94 (diff)
child 146781 92bea49b46b49c4d159a63291b69a07d5bade2c1
child 146787 29a87d8049b0279f630a958e49bebeecac199740
child 146828 03299b97544330eaabd21972fc85dfb82f7f1729
child 146884 4f01c85af38f2032f5b995c15a49117096df0777
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone26.0a1
Merge latest green fx-team 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/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "9e3d2b3f6706916168b9ad9bb96084c01df8771f", 
+    "revision": "af6b88994605d8833693cde83e43fe3d9e93d181", 
     "repo_path": "/integration/gaia-central"
 }
--- 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/network/tests/marionette/manifest.ini
+++ b/dom/network/tests/marionette/manifest.ini
@@ -5,15 +5,16 @@ qemu = true
 
 [test_mobile_networks.js]
 disabled = Bug 808783
 [test_mobile_voice_state.js]
 [test_mobile_iccinfo.js]
 [test_mobile_operator_names.js]
 [test_mobile_preferred_network_type.js]
 disabled = Bug 808783
+[test_mobile_data_connection.js]
 [test_mobile_data_location.js]
 [test_mobile_data_state.js]
 [test_mobile_mmi.js]
 [test_mobile_roaming_preference.js]
 [test_call_barring_get_option.js]
 [test_call_barring_set_error.js]
 [test_call_barring_change_password.js]
new file mode 100644
--- /dev/null
+++ b/dom/network/tests/marionette/test_mobile_data_connection.js
@@ -0,0 +1,308 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+
+const DATA_KEY = "ril.data.enabled";
+const DATA_ROAMING_KEY = "ril.data.roaming_enabled";
+const APN_KEY = "ril.data.apnSettings";
+
+SpecialPowers.setBoolPref("dom.mozSettings.enabled", true);
+SpecialPowers.addPermission("mobileconnection", true, document);
+SpecialPowers.addPermission("settings-read", true, document);
+SpecialPowers.addPermission("settings-write", true, document);
+
+let settings = window.navigator.mozSettings;
+let connection = window.navigator.mozMobileConnection;
+ok(connection instanceof MozMobileConnection,
+   "connection is instanceof " + connection.constructor);
+
+
+let pendingEmulatorCmdCount = 0;
+function sendCmdToEmulator(cmd, callback) {
+  ++pendingEmulatorCmdCount;
+
+  runEmulatorCmd(cmd, function (result) {
+    --pendingEmulatorCmdCount;
+
+    is(result[0], "OK", "Emulator response");
+
+    if (callback) {
+      callback();
+    }
+  });
+}
+
+let tasks = {
+  // List of test fuctions. Each of them should call |tasks.next()| when
+  // completed or |tasks.finish()| to jump to the last one.
+  _tasks: [],
+  _nextTaskIndex: 0,
+
+  push: function push(func) {
+    this._tasks.push(func);
+  },
+
+  next: function next() {
+    let index = this._nextTaskIndex++;
+    let task = this._tasks[index];
+    try {
+      task();
+    } catch (ex) {
+      ok(false, "test task[" + index + "] throws: " + ex);
+      // Run last task as clean up if possible.
+      if (index != this._tasks.length - 1) {
+        this.finish();
+      }
+    }
+  },
+
+  finish: function finish() {
+    this._tasks[this._tasks.length - 1]();
+  },
+
+  run: function run() {
+    this.next();
+  }
+};
+
+function setSetting(key, value, callback) {
+  let setLock = settings.createLock();
+  let obj = {};
+  obj[key] = value;
+
+  let setReq = setLock.set(obj);
+  setReq.addEventListener("success", function onSetSuccess() {
+    ok(true, "set '" + key + "' to " + obj[key]);
+    if (callback) {
+      callback();
+    }
+  });
+  setReq.addEventListener("error", function onSetError() {
+    ok(false, "cannot set '" + key + "'");
+    tasks.finish();
+  });
+}
+
+function getSetting(key, callback) {
+  let getLock = settings.createLock();
+
+  let getReq = getLock.get(key);
+  getReq.addEventListener("success", function onGetSuccess() {
+    ok(true, "get " + key + " setting okay");
+    let value = getReq.result[key];
+    callback(value);
+  });
+  getReq.addEventListener("error", function onGetError() {
+    ok(false, "cannot get '" + key + "'");
+    tasks.finish();
+  });
+}
+
+function setEmulatorAPN(callback) {
+  let apn =
+    [
+      [
+        {"carrier":"T-Mobile US",
+         "apn":"epc.tmobile.com",
+         "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc",
+         "types":["default","supl","mms"]}
+      ]
+    ];
+  setSetting(APN_KEY, apn, callback);
+}
+
+function setEmulatorRoaming(roaming, callback) {
+  log("Setting emulator roaming state: " + roaming + ".");
+
+  // Set voice registration state first and then data registration state.
+  let cmd = "gsm voice " + (roaming ? "roaming" : "home");
+  sendCmdToEmulator(cmd, function() {
+
+    connection.addEventListener("voicechange", function onvoicechange() {
+      connection.removeEventListener("voicechange", onvoicechange);
+      log("mobileConnection.voice.roaming is now '"
+        + connection.voice.roaming + "'.");
+      is(connection.voice.roaming, roaming, "voice.roaming");
+
+      let cmd = "gsm data " + (roaming ? "roaming" : "home");
+      sendCmdToEmulator(cmd, function () {
+
+        connection.addEventListener("datachange", function ondatachange() {
+          connection.removeEventListener("datachange", ondatachange);
+          log("mobileConnection.data.roaming is now '"
+            + connection.data.roaming + "'.");
+          is(connection.data.roaming, roaming, "data.roaming");
+          if (callback) {
+            callback();
+          }
+        });
+      });
+    });
+  });
+}
+
+function setEmulatorHome(callback) {
+  let voiceRegistration = false;
+  let dataRegistration = false;
+
+  if (connection.voice.state != "registered") {
+    sendCmdToEmulator("gsm voice home", function() {
+      connection.addEventListener("voicechange", function onvoicechange() {
+        connection.removeEventListener("voicechange", onvoicechange);
+        log("mobileConnection.voice.state is now '"
+          + connection.voice.state + "'.");
+        is(connection.voice.state, "registered", "voice.state");
+        voiceRegistration = true;
+      });
+    });
+  } else {
+    voiceRegistration = true;
+  }
+
+  if (connection.data.state != "registered") {
+    sendCmdToEmulator("gsm data home", function() {
+      connection.addEventListener("datachange", function ondatachange() {
+        connection.removeEventListener("datachange", ondatachange);
+        log("mobileConnection.data.state is now '"
+          + connection.data.state + "'.");
+        is(connection.data.state, "registered", "data.state");
+        dataRegistration = true;
+      });
+    });
+  } else {
+    dataRegistration = true;
+  }
+
+  waitFor(callback, function() {
+    return (voiceRegistration && dataRegistration);
+  });
+}
+
+
+tasks.push(function verifyInitialState() {
+  log("Verifying initial state.");
+
+  // Want to start test with mobileConnection.data.state 'registered',
+  // This is the default state; if it is not currently this value then set it.
+  setEmulatorHome(function() {
+    // Want to start test with data off,
+    // This is the default state; if it is not currently this value then set it.
+    getSetting(DATA_KEY, function(result) {
+      let value = result;
+      log("Starting data enabled: " + value);
+      if (value) {
+        setSetting(DATA_KEY, false);
+
+        connection.addEventListener("datachange", function ondatachange() {
+          connection.removeEventListener("datachange", ondatachange);
+          log("mobileConnection.data.connected is now '"
+            + connection.data.connected + "'.");
+          is(connection.data.connected, false, "data.connected");
+          setEmulatorAPN(function() {
+            tasks.next();
+          });
+        });
+      } else {
+        setEmulatorAPN(function() {
+          tasks.next();
+        });
+      }
+    });
+  });
+});
+
+tasks.push(function testEnableData() {
+  log("Turn data on.");
+
+  connection.addEventListener("datachange", function ondatachange() {
+    connection.removeEventListener("datachange", ondatachange);
+    log("mobileConnection.data.connected is now '"
+      + connection.data.connected + "'.");
+    is(connection.data.connected, true, "data.connected");
+    tasks.next();
+  });
+
+  setSetting(DATA_KEY, true);
+});
+
+tasks.push(function testDisableDataRoamingWhileRoaming() {
+  log("Disable data roaming while roaming.");
+
+  setSetting(DATA_ROAMING_KEY, false);
+
+  // Wait for roaming state to change, then data connection should
+  // be disconnected due to data roaming set to off.
+  setEmulatorRoaming(true, function() {
+    connection.addEventListener("datachange", function ondatachange() {
+      connection.removeEventListener("datachange", ondatachange);
+      log("mobileConnection.data.connected is now '"
+        + connection.data.connected + "'.");
+      is(connection.data.connected, false, "data.connected");
+      tasks.next();
+    });
+  });
+});
+
+tasks.push(function testEnableDataRoamingWhileRoaming() {
+  log("Enable data roaming while roaming.");
+
+  // Data should be re-connected as we enabled data roaming.
+  connection.addEventListener("datachange", function ondatachange() {
+    connection.removeEventListener("datachange", ondatachange);
+    log("mobileConnection.data.connected is now '"
+      + connection.data.connected + "'.");
+    is(connection.data.connected, true, "data.connected");
+    tasks.next();
+  });
+
+  setSetting(DATA_ROAMING_KEY, true);
+});
+
+tasks.push(function testDisableDataRoamingWhileNotRoaming() {
+  log("Disable data roaming while not roaming.");
+
+  // Wait for roaming state to change then set data roaming back
+  // to off.
+  setEmulatorRoaming(false, function() {
+    setSetting(DATA_ROAMING_KEY, false);
+
+    // No change event will be received cause data connection state
+    // remains the same.
+    window.setTimeout(function() {
+      is(connection.data.connected, true, "data.connected");
+      tasks.next();
+    }, 1000);
+  });
+});
+
+tasks.push(function testDisableData() {
+  log("Turn data off.");
+
+  connection.addEventListener("datachange", function ondatachange() {
+    connection.removeEventListener("datachange", ondatachange);
+    log("mobileConnection.data.connected is now '"
+      + connection.data.connected + "'.");
+    is(connection.data.connected, false, "data.connected");
+    tasks.next();
+  });
+
+  setSetting(DATA_KEY, false);
+});
+
+// WARNING: All tasks should be pushed before this!!!
+tasks.push(function cleanUp() {
+  if (pendingEmulatorCmdCount) {
+    window.setTimeout(cleanUp, 100);
+    return;
+  }
+
+  SpecialPowers.removePermission("mobileconnection", document);
+  SpecialPowers.removePermission("settings-write", document);
+  SpecialPowers.removePermission("settings-read", document);
+  SpecialPowers.clearUserPref("dom.mozSettings.enabled");
+  finish();
+});
+
+tasks.run();
+
--- 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/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1353,20 +1353,17 @@ let RIL = {
    *        String containing the number to dial.
    * @param clirMode
    *        Integer for showing/hidding the caller Id to the called party.
    * @param uusInfo
    *        Integer doing something XXX TODO
    */
   dial: function dial(options) {
     let onerror = (function onerror(errorMsg) {
-      options.callIndex = -1;
-      options.rilMessageType = "callError";
-      options.errorMsg = errorMsg;
-      this.sendChromeMessage(options);
+      this._sendCallError(-1, errorMsg);
     }).bind(this);
 
     if (this._isEmergencyNumber(options.number)) {
       this.dialEmergencyNumber(options, onerror);
     } else {
       if (!this._isCdma) {
         // TODO: Both dial() and sendMMI() functions should be unified at some
         // point in the future. In the mean time we handle temporary CLIR MMI
@@ -3647,17 +3644,25 @@ let RIL = {
   },
 
   _handleDisconnectedCall: function _handleDisconnectedCall(disconnectedCall) {
     let message = {rilMessageType: "callDisconnected",
                    call: disconnectedCall};
     this.sendChromeMessage(message);
   },
 
+  _sendCallError: function _sendCallError(callIndex, errorMsg) {
+    this.sendChromeMessage({rilMessageType: "callError",
+                           callIndex: callIndex,
+                           errorMsg: errorMsg});
+  },
+
   _sendDataCallError: function _sendDataCallError(message, errorCode) {
+    // Should not include token for unsolicited response.
+    delete message.rilMessageToken;
     message.rilMessageType = "datacallerror";
     if (errorCode == ERROR_GENERIC_FAILURE) {
       message.errorMsg = RIL_ERROR_TO_GECKO_ERROR[errorCode];
     } else {
       message.errorMsg = RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[errorCode];
     }
     this.sendChromeMessage(message);
   },
@@ -4974,19 +4979,18 @@ RIL[REQUEST_LAST_CALL_FAIL_CAUSE] = func
   }
 
   let failCause = Buf.readUint32();
   switch (failCause) {
     case CALL_FAIL_NORMAL:
       this._handleDisconnectedCall(options);
       break;
     default:
-      options.rilMessageType = "callError";
-      options.errorMsg = RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[failCause];
-      this.sendChromeMessage(options);
+      this._sendCallError(options.callIndex,
+                          RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[failCause]);
       break;
   }
 };
 RIL[REQUEST_SIGNAL_STRENGTH] = function REQUEST_SIGNAL_STRENGTH(length, options) {
   this._receivedNetworkInfo(NETWORK_INFO_SIGNAL);
 
   if (options.rilRequestError) {
     return;
--- 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/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -6,16 +6,17 @@ qemu = true
 [test_crash_emulator.js]
 [test_incoming_answer_hangup.js]
 [test_incoming_reject.js]
 [test_outgoing_answer_hangup.js]
 [test_incoming_answer_hangup_oncallschanged.js]
 [test_outgoing_answer_hangup_oncallschanged.js]
 [test_outgoing_hangup_alerting.js]
 [test_outgoing_hangup_held.js]
+[test_outgoing_radio_off.js]
 [test_outgoing_badNumber.js]
 [test_outgoing_busy.js]
 [test_outgoing_reject.js]
 [test_incoming_hold_resume.js]
 [test_outgoing_hold_resume.js]
 [test_incoming_already_connected.js]
 [test_incoming_answer_remote_hangup.js]
 [test_incoming_connecting_hangup.js]
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_outgoing_radio_off.js
@@ -0,0 +1,126 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+
+permissions = [
+  "mobileconnection",
+  "settings-write",
+  "telephony"
+];
+
+for (let per of permissions) {
+  SpecialPowers.addPermission(per, true, document);
+}
+
+let gSettingsEnabled = SpecialPowers.getBoolPref("dom.mozSettings.enabled");
+if (!gSettingsEnabled) {
+  SpecialPowers.setBoolPref("dom.mozSettings.enabled", true);
+}
+
+let icc = navigator.mozIccManager;
+ok(icc instanceof MozIccManager, "icc is instanceof " + icc.constructor);
+
+let connection = navigator.mozMobileConnection;
+ok(connection instanceof MozMobileConnection,
+   "connection is instanceof " + connection.constructor);
+
+let telephony = navigator.mozTelephony;
+ok(telephony instanceof Telephony,
+   "telephony is instanceof " + telephony.constructor);
+
+let outgoing;
+let pendingEmulatorCmdCount = 0;
+
+function sendToEmulator(cmd, callback) {
+  pendingEmulatorCmdCount++;
+  runEmulatorCmd(cmd, function (result) {
+    pendingEmulatorCmdCount--;
+    if (callback && typeof callback === 'function') {
+      callback(result);
+    }
+  });
+}
+
+function changeSetting(key, value, callback) {
+  let obj = {};
+  obj[key] = value;
+
+  let setReq = navigator.mozSettings.createLock().set(obj);
+  setReq.addEventListener("success", function onSetSuccess() {
+    ok(true, "set '" + key + "' to " + obj[key]);
+    setReq.removeEventListener("success", onSetSuccess);
+    callback();
+  });
+  setReq.addEventListener("error", function onSetError() {
+    ok(false, "cannot set '" + key + "'");
+    cleanUp();
+  });
+}
+
+function setRadioEnabled(enabled, callback) {
+  changeSetting("ril.radio.disabled", !enabled, function() {
+    icc.addEventListener("cardstatechange", function handler() {
+      // Wait until card state changes to "ready" after turning on radio.
+      // Wait until card state changes to "not-ready" after turning off radio.
+      if ((enabled && icc.cardState == "ready") ||
+          (!enabled && icc.cardState != "ready")) {
+        icc.removeEventListener("cardstatechange", handler);
+        callback();
+      }
+    });
+  });
+}
+
+function dial(number) {
+  // Verify initial state before dial.
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  log("Make an outgoing call.");
+  outgoing = telephony.dial(number);
+
+  ok(outgoing);
+  is(outgoing.number, number);
+  is(outgoing.state, "dialing");
+
+  is(telephony.active, outgoing);
+  is(telephony.calls.length, 1);
+  is(telephony.calls[0], outgoing);
+
+  outgoing.onerror = function onerror(event) {
+    log("Received 'error' event.");
+    is(event.call, outgoing);
+    ok(event.call.error);
+    is(event.call.error.name, "RadioNotAvailable");
+
+    sendToEmulator("gsm list", function(result) {
+      log("Initial call list: " + result);
+      is(result[0], "OK");
+
+      setRadioEnabled(true, cleanUp);
+    });
+  };
+}
+
+function cleanUp() {
+  if (pendingEmulatorCmdCount) {
+    window.setTimeout(cleanUp, 100);
+    return;
+  }
+
+  for (let per of permissions) {
+    SpecialPowers.removePermission(per, document);
+  }
+  SpecialPowers.clearUserPref("dom.mozSettings.enabled");
+  finish();
+}
+
+setRadioEnabled(false, function() {
+  sendToEmulator("gsm clear", function(result) {
+    is(result[0], "OK");
+    dial("0912345678");
+  });
+});
--- 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&quo