Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 19 Nov 2013 20:43:15 -0500
changeset 156458 4f993fa378ebe15621a7e03114ae99552db757f5
parent 156381 0587548f1428abdf30f79082903b43953924f794 (current diff)
parent 156457 b92529577644a37517e87fe053ba29ab9e3f4c90 (diff)
child 156459 7e9be570d4b89b016f7bdbe7cb6bafa2b29589fa
child 156469 ec6d7da7e373251008d70e3a5a290db080dcef58
child 156740 00965a4106e458e427210b7a826be609d14de4ab
push id25678
push userryanvm@gmail.com
push dateWed, 20 Nov 2013 03:26:13 +0000
treeherdermozilla-central@4f993fa378eb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
4f993fa378eb / 28.0a1 / 20131120030202 / files
nightly linux64
4f993fa378eb / 28.0a1 / 20131120030202 / files
nightly mac
4f993fa378eb / 28.0a1 / 20131120030202 / files
nightly win32
4f993fa378eb / 28.0a1 / 20131120030202 / files
nightly win64
4f993fa378eb / 28.0a1 / 20131120030202 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c.
dom/bindings/BindingGen.py
dom/bindings/ExampleGen.py
dom/bindings/GlobalGen.py
dom/contacts/tests/test_contacts_upgrade.html
dom/indexedDB/test/test_globalObjects.html
dom/indexedDB/test/test_globalObjects.xul
dom/indexedDB/test/unit/test_globalObjects.js
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
mobile/android/base/moz.build
mobile/android/base/resources/drawable-hdpi/awesomebar_sep_left.9.png
mobile/android/base/resources/drawable-hdpi/awesomebar_sep_right.9.png
mobile/android/base/resources/drawable-hdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-hdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-hdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-hdpi/ic_notif_button_cancel.png
mobile/android/base/resources/drawable-hdpi/ic_notif_button_pause.png
mobile/android/base/resources/drawable-hdpi/ic_notif_button_resume.png
mobile/android/base/resources/drawable-mdpi/awesomebar_sep_left.9.png
mobile/android/base/resources/drawable-mdpi/awesomebar_sep_right.9.png
mobile/android/base/resources/drawable-mdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-mdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-mdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-mdpi/crash_reporter.png
mobile/android/base/resources/drawable-mdpi/ic_notif_button_cancel.png
mobile/android/base/resources/drawable-mdpi/ic_notif_button_pause.png
mobile/android/base/resources/drawable-mdpi/ic_notif_button_resume.png
mobile/android/base/resources/drawable-xhdpi/awesomebar_sep_left.9.png
mobile/android/base/resources/drawable-xhdpi/awesomebar_sep_right.9.png
mobile/android/base/resources/drawable-xhdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-xhdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-xhdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-xhdpi/ic_notif_button_cancel.png
mobile/android/base/resources/drawable-xhdpi/ic_notif_button_pause.png
mobile/android/base/resources/drawable-xhdpi/ic_notif_button_resume.png
mobile/android/base/resources/drawable-xlarge-hdpi-v11/awesomebar_sep_left.9.png
mobile/android/base/resources/drawable-xlarge-hdpi-v11/awesomebar_sep_right.9.png
mobile/android/base/resources/drawable-xlarge-hdpi-v11/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-xlarge-hdpi-v11/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-xlarge-hdpi-v11/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-xlarge-mdpi-v11/awesomebar_sep_left.9.png
mobile/android/base/resources/drawable-xlarge-mdpi-v11/awesomebar_sep_right.9.png
mobile/android/base/resources/drawable-xlarge-mdpi-v11/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-xlarge-mdpi-v11/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-xlarge-mdpi-v11/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-xlarge-xhdpi-v11/awesomebar_sep_left.9.png
mobile/android/base/resources/drawable-xlarge-xhdpi-v11/awesomebar_sep_right.9.png
mobile/android/base/resources/drawable-xlarge-xhdpi-v11/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-xlarge-xhdpi-v11/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-xlarge-xhdpi-v11/awesomebar_tab_right.9.png
mobile/android/base/resources/layout/crash_reporter.xml
mobile/android/branding/aurora/content/fennec_144x144.png
mobile/android/branding/aurora/content/fennec_48x48.png
mobile/android/branding/aurora/content/fennec_72x72.png
mobile/android/branding/aurora/content/fennec_96x96.png
mobile/android/branding/beta/content/fennec_144x144.png
mobile/android/branding/beta/content/fennec_48x48.png
mobile/android/branding/beta/content/fennec_72x72.png
mobile/android/branding/beta/content/fennec_96x96.png
mobile/android/branding/nightly/content/fennec_144x144.png
mobile/android/branding/nightly/content/fennec_48x48.png
mobile/android/branding/nightly/content/fennec_72x72.png
mobile/android/branding/nightly/content/fennec_96x96.png
mobile/android/branding/official/content/fennec_144x144.png
mobile/android/branding/official/content/fennec_48x48.png
mobile/android/branding/official/content/fennec_72x72.png
mobile/android/branding/official/content/fennec_96x96.png
mobile/android/branding/unofficial/content/fennec_144x144.png
mobile/android/branding/unofficial/content/fennec_48x48.png
mobile/android/branding/unofficial/content/fennec_72x72.png
mobile/android/branding/unofficial/content/fennec_96x96.png
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,9 +13,11 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-Australis landing.
+Bug 934646 needs a clobber -- the icon resources previously copied
+into $OBJDIR/mobile/android/base/res will conflict with those in
+$BRANDING_DIRECTORY/res.
--- a/accessible/src/atk/nsMaiInterfaceValue.cpp
+++ b/accessible/src/atk/nsMaiInterfaceValue.cpp
@@ -1,122 +1,100 @@
 /* -*- 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 "InterfaceInitFuncs.h"
-#include "mozilla/Likely.h"
 
 #include "AccessibleWrap.h"
 #include "nsMai.h"
 
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Likely.h"
+
+using namespace mozilla;
 using namespace mozilla::a11y;
 
 extern "C" {
 
 static void
 getCurrentValueCB(AtkValue *obj, GValue *value)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
   if (!accWrap)
     return;
 
-    nsCOMPtr<nsIAccessibleValue> accValue;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleValue),
-                            getter_AddRefs(accValue));
-    if (!accValue)
-        return;
+  memset (value,  0, sizeof (GValue));
+  double accValue = accWrap->CurValue();
+  if (IsNaN(accValue))
+    return;
 
-    memset (value,  0, sizeof (GValue));
-    double accDouble;
-    if (NS_FAILED(accValue->GetCurrentValue(&accDouble)))
-        return;
-    g_value_init (value, G_TYPE_DOUBLE);
-    g_value_set_double (value, accDouble);
+  g_value_init (value, G_TYPE_DOUBLE);
+  g_value_set_double (value, accValue);
 }
 
 static void
 getMaximumValueCB(AtkValue *obj, GValue *value)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
   if (!accWrap)
     return;
 
-    nsCOMPtr<nsIAccessibleValue> accValue;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleValue),
-                            getter_AddRefs(accValue));
-    if (!accValue)
-        return;
+  memset(value,  0, sizeof (GValue));
+  double accValue = accWrap->MaxValue();
+  if (IsNaN(accValue))
+    return;
 
-    memset (value,  0, sizeof (GValue));
-    double accDouble;
-    if (NS_FAILED(accValue->GetMaximumValue(&accDouble)))
-        return;
-    g_value_init (value, G_TYPE_DOUBLE);
-    g_value_set_double (value, accDouble);
+  g_value_init(value, G_TYPE_DOUBLE);
+  g_value_set_double(value, accValue);
 }
 
 static void
 getMinimumValueCB(AtkValue *obj, GValue *value)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
   if (!accWrap)
     return;
 
-    nsCOMPtr<nsIAccessibleValue> accValue;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleValue),
-                            getter_AddRefs(accValue));
-    if (!accValue)
-        return;
+  memset(value,  0, sizeof (GValue));
+  double accValue = accWrap->MinValue();
+  if (IsNaN(accValue))
+    return;
 
-    memset (value,  0, sizeof (GValue));
-    double accDouble;
-    if (NS_FAILED(accValue->GetMinimumValue(&accDouble)))
-        return;
-    g_value_init (value, G_TYPE_DOUBLE);
-    g_value_set_double (value, accDouble);
+  g_value_init(value, G_TYPE_DOUBLE);
+  g_value_set_double(value, accValue);
 }
 
 static void
 getMinimumIncrementCB(AtkValue *obj, GValue *minimumIncrement)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
   if (!accWrap)
     return;
 
-    nsCOMPtr<nsIAccessibleValue> accValue;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleValue),
-                            getter_AddRefs(accValue));
-    if (!accValue)
-        return;
+  memset(minimumIncrement,  0, sizeof (GValue));
+  double accValue = accWrap->Step();
+  if (IsNaN(accValue))
+    accValue = 0; // zero if the minimum increment is undefined
 
-    memset (minimumIncrement,  0, sizeof (GValue));
-    double accDouble;
-    if (NS_FAILED(accValue->GetMinimumIncrement(&accDouble)))
-        return;
-    g_value_init (minimumIncrement, G_TYPE_DOUBLE);
-    g_value_set_double (minimumIncrement, accDouble);
+  g_value_init(minimumIncrement, G_TYPE_DOUBLE);
+  g_value_set_double(minimumIncrement, accValue);
 }
 
 static gboolean
 setCurrentValueCB(AtkValue *obj, const GValue *value)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
   if (!accWrap)
     return FALSE;
 
-    nsCOMPtr<nsIAccessibleValue> accValue;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleValue),
-                            getter_AddRefs(accValue));
-    NS_ENSURE_TRUE(accValue, FALSE);
-
-    double accDouble =g_value_get_double (value);
-    return !NS_FAILED(accValue->SetCurrentValue(accDouble));
+  double accValue =g_value_get_double(value);
+  return accWrap->SetCurValue(accValue);
 }
 }
 
 void
 valueInterfaceInitCB(AtkValueIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid aIface");
   if (MOZ_UNLIKELY(!aIface))
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -73,16 +73,17 @@
 #include "nsNetUtil.h"
 #include "nsEventStates.h"
 
 #ifdef DEBUG
 #include "nsIDOMCharacterData.h"
 #endif
 
 #include "mozilla/Assertions.h"
+#include "mozilla/FloatingPoint.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/unused.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
@@ -1667,71 +1668,63 @@ Accessible::Value(nsString& aValue)
         option = listbox->GetSelectedItem(0);
     }
 
     if (option)
       nsTextEquivUtils::GetTextEquivFromSubtree(option, aValue);
   }
 }
 
-// nsIAccessibleValue
-NS_IMETHODIMP
-Accessible::GetMaximumValue(double *aMaximumValue)
+double
+Accessible::MaxValue() const
 {
-  return GetAttrValue(nsGkAtoms::aria_valuemax, aMaximumValue);
+  return AttrNumericValue(nsGkAtoms::aria_valuemax);
 }
 
-NS_IMETHODIMP
-Accessible::GetMinimumValue(double *aMinimumValue)
+double
+Accessible::MinValue() const
 {
-  return GetAttrValue(nsGkAtoms::aria_valuemin, aMinimumValue);
+  return AttrNumericValue(nsGkAtoms::aria_valuemin);
 }
 
-NS_IMETHODIMP
-Accessible::GetMinimumIncrement(double *aMinIncrement)
+double
+Accessible::Step() const
 {
-  NS_ENSURE_ARG_POINTER(aMinIncrement);
-  *aMinIncrement = 0;
-
-  // No mimimum increment in dynamic content spec right now
-  return NS_OK_NO_ARIA_VALUE;
+  return UnspecifiedNaN(); // no mimimum increment (step) in ARIA.
 }
 
-NS_IMETHODIMP
-Accessible::GetCurrentValue(double *aValue)
+double
+Accessible::CurValue() const
 {
-  return GetAttrValue(nsGkAtoms::aria_valuenow, aValue);
+  return AttrNumericValue(nsGkAtoms::aria_valuenow);
 }
 
-NS_IMETHODIMP
-Accessible::SetCurrentValue(double aValue)
+bool
+Accessible::SetCurValue(double aValue)
 {
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
   if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
-    return NS_OK_NO_ARIA_VALUE;
+    return false;
 
   const uint32_t kValueCannotChange = states::READONLY | states::UNAVAILABLE;
-
   if (State() & kValueCannotChange)
-    return NS_ERROR_FAILURE;
-
-  double minValue = 0;
-  if (NS_SUCCEEDED(GetMinimumValue(&minValue)) && aValue < minValue)
-    return NS_ERROR_INVALID_ARG;
-
-  double maxValue = 0;
-  if (NS_SUCCEEDED(GetMaximumValue(&maxValue)) && aValue > maxValue)
-    return NS_ERROR_INVALID_ARG;
-
-  nsAutoString newValue;
-  newValue.AppendFloat(aValue);
-  return mContent->SetAttr(kNameSpaceID_None,
-                           nsGkAtoms::aria_valuenow, newValue, true);
+    return false;
+
+  double checkValue = MinValue();
+  if (!IsNaN(checkValue) && aValue < checkValue)
+    return false;
+
+  checkValue = MaxValue();
+  if (!IsNaN(checkValue) && aValue > checkValue)
+    return false;
+
+  nsAutoString strValue;
+  strValue.AppendFloat(aValue);
+
+  return NS_SUCCEEDED(
+    mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow, strValue, true));
 }
 
 /* void setName (in DOMString name); */
 NS_IMETHODIMP
 Accessible::SetName(const nsAString& aName)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
@@ -3111,41 +3104,29 @@ Accessible::GetFirstAvailableAccessible(
     Accessible* accessible = mDoc->GetAccessible(node);
     if (accessible)
       return accessible;
   }
 
   return nullptr;
 }
 
-nsresult
-Accessible::GetAttrValue(nsIAtom *aProperty, double *aValue)
+double
+Accessible::AttrNumericValue(nsIAtom* aAttr) const
 {
-  NS_ENSURE_ARG_POINTER(aValue);
-  *aValue = 0;
-
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;  // Node already shut down
-
- if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
-    return NS_OK_NO_ARIA_VALUE;
+  if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
+    return UnspecifiedNaN();
 
   nsAutoString attrValue;
-  mContent->GetAttr(kNameSpaceID_None, aProperty, attrValue);
-
-  // Return zero value if there is no attribute or its value is empty.
-  if (attrValue.IsEmpty())
-    return NS_OK;
+  if (!mContent->GetAttr(kNameSpaceID_None, aAttr, attrValue))
+    return UnspecifiedNaN();
 
   nsresult error = NS_OK;
   double value = attrValue.ToDouble(&error);
-  if (NS_SUCCEEDED(error))
-    *aValue = value;
-
-  return NS_OK;
+  return NS_FAILED(error) ? UnspecifiedNaN() : value;
 }
 
 uint32_t
 Accessible::GetActionRule()
 {
   if (!HasOwnContent() || (InteractiveState() & states::UNAVAILABLE))
     return eNoAction;
 
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -8,19 +8,19 @@
 
 #include "mozilla/a11y/AccTypes.h"
 #include "mozilla/a11y/RelationType.h"
 #include "mozilla/a11y/Role.h"
 #include "mozilla/a11y/States.h"
 
 #include "nsIAccessible.h"
 #include "nsIAccessibleHyperLink.h"
-#include "nsIAccessibleValue.h"
 #include "nsIAccessibleStates.h"
 #include "xpcAccessibleSelectable.h"
+#include "xpcAccessibleValue.h"
 
 #include "nsIContent.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsRefPtrHashtable.h"
 
 struct nsRoleMapEntry;
 
@@ -100,28 +100,27 @@ typedef nsRefPtrHashtable<nsPtrHashKey<c
   0x4913,                                               \
   0x4355,                                               \
   { 0xbd, 0x50, 0x42, 0x6b, 0xd1, 0xd6, 0xe1, 0xad }    \
 }
 
 class Accessible : public nsIAccessible,
                    public nsIAccessibleHyperLink,
                    public xpcAccessibleSelectable,
-                   public nsIAccessibleValue
+                   public xpcAccessibleValue
 {
 public:
   Accessible(nsIContent* aContent, DocAccessible* aDoc);
   virtual ~Accessible();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(Accessible, nsIAccessible)
 
   NS_DECL_NSIACCESSIBLE
   NS_DECL_NSIACCESSIBLEHYPERLINK
-  NS_DECL_NSIACCESSIBLEVALUE
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ACCESSIBLE_IMPL_IID)
 
   //////////////////////////////////////////////////////////////////////////////
   // Public methods
 
   /**
    * Return the document accessible for this accessible.
    */
@@ -684,16 +683,25 @@ public:
   virtual bool SelectAll();
 
   /**
    * Unselect all items. Return true if success.
    */
   virtual bool UnselectAll();
 
   //////////////////////////////////////////////////////////////////////////////
+  // Value (numeric value interface)
+
+  virtual double MaxValue() const;
+  virtual double MinValue() const;
+  virtual double CurValue() const;
+  virtual double Step() const;
+  virtual bool SetCurValue(double aValue);
+
+  //////////////////////////////////////////////////////////////////////////////
   // Widgets
 
   /**
    * Return true if accessible is a widget, i.e. control or accessible that
    * manages its items. Note, being a widget the accessible may be a part of
    * composite widget.
    */
   virtual bool IsWidget() const;
@@ -906,24 +914,22 @@ protected:
 
   /**
    *  Get the container node for an atomic region, defined by aria-atomic="true"
    *  @return the container node
    */
   nsIContent* GetAtomicRegion() const;
 
   /**
-   * Get numeric value of the given ARIA attribute.
+   * Return numeric value of the given ARIA attribute, NaN if not applicable.
    *
-   * @param aAriaProperty - the ARIA property we're using
-   * @param aValue - value of the attribute
-   *
-   * @return - NS_OK_NO_ARIA_VALUE if there is no setted ARIA attribute
+   * @param aARIAProperty  [in] the ARIA property we're using
+   * @return  a numeric value
    */
-  nsresult GetAttrValue(nsIAtom *aAriaProperty, double *aValue);
+  double AttrNumericValue(nsIAtom* aARIAAttr) const;
 
   /**
    * Return the action rule based on ARIA enum constants EActionRule
    * (see ARIAMap.h). Used by ActionCount() and GetActionName().
    */
   uint32_t GetActionRule();
 
   /**
--- a/accessible/src/generic/FormControlAccessible.cpp
+++ b/accessible/src/generic/FormControlAccessible.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/. */
 
 // NOTE: alphabetically ordered
 
 #include "FormControlAccessible.h"
 #include "Role.h"
 
+#include "mozilla/FloatingPoint.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDOMXULControlElement.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // ProgressMeterAccessible
@@ -77,106 +78,89 @@ ProgressMeterAccessible<Max>::IsWidget()
 template<int Max>
 void
 ProgressMeterAccessible<Max>::Value(nsString& aValue)
 {
   LeafAccessible::Value(aValue);
   if (!aValue.IsEmpty())
     return;
 
-  double maxValue = 0;
-  nsresult rv = GetMaximumValue(&maxValue);
-  if (NS_FAILED(rv) || maxValue == 0)
+  double maxValue = MaxValue();
+  if (IsNaN(maxValue) || maxValue == 0)
     return;
 
-  double curValue = 0;
-  GetCurrentValue(&curValue);
-  if (NS_FAILED(rv))
+  double curValue = CurValue();
+  if (IsNaN(curValue))
     return;
 
   // Treat the current value bigger than maximum as 100%.
   double percentValue = (curValue < maxValue) ?
     (curValue / maxValue) * 100 : 100;
 
   aValue.AppendFloat(percentValue);
   aValue.AppendLiteral("%");
 }
 
 template<int Max>
-NS_IMETHODIMP
-ProgressMeterAccessible<Max>::GetMaximumValue(double* aMaximumValue)
+double
+ProgressMeterAccessible<Max>::MaxValue() const
 {
-  nsresult rv = LeafAccessible::GetMaximumValue(aMaximumValue);
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
+  double value = LeafAccessible::MaxValue();
+  if (!IsNaN(value))
+    return value;
 
-  nsAutoString value;
-  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::max, value)) {
+  nsAutoString strValue;
+  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::max, strValue)) {
     nsresult result = NS_OK;
-    *aMaximumValue = value.ToDouble(&result);
-    return result;
+    value = strValue.ToDouble(&result);
+    if (NS_SUCCEEDED(result))
+      return value;
   }
 
-  *aMaximumValue = Max;
-  return NS_OK;
+  return Max;
 }
 
 template<int Max>
-NS_IMETHODIMP
-ProgressMeterAccessible<Max>::GetMinimumValue(double* aMinimumValue)
+double
+ProgressMeterAccessible<Max>::MinValue() const
 {
-  nsresult rv = LeafAccessible::GetMinimumValue(aMinimumValue);
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
-
-  *aMinimumValue = 0;
-  return NS_OK;
+  double value = LeafAccessible::MinValue();
+  return IsNaN(value) ? 0 : value;
 }
 
 template<int Max>
-NS_IMETHODIMP
-ProgressMeterAccessible<Max>::GetMinimumIncrement(double* aMinimumIncrement)
+double
+ProgressMeterAccessible<Max>::Step() const
 {
-  nsresult rv = LeafAccessible::GetMinimumIncrement(aMinimumIncrement);
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
-
-  *aMinimumIncrement = 0;
-  return NS_OK;
+  double value = LeafAccessible::Step();
+  return IsNaN(value) ? 0 : value;
 }
 
 template<int Max>
-NS_IMETHODIMP
-ProgressMeterAccessible<Max>::GetCurrentValue(double* aCurrentValue)
+double
+ProgressMeterAccessible<Max>::CurValue() const
 {
-  nsresult rv = LeafAccessible::GetCurrentValue(aCurrentValue);
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
+  double value = LeafAccessible::CurValue();
+  if (!IsNaN(value))
+    return value;
 
   nsAutoString attrValue;
-  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue);
-
-  // Return zero value if there is no attribute or its value is empty.
-  if (attrValue.IsEmpty())
-    return NS_OK;
+  if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue))
+    return UnspecifiedNaN();
 
   nsresult error = NS_OK;
-  double value = attrValue.ToDouble(&error);
-  if (NS_FAILED(error))
-    return NS_OK; // Zero value because of wrong markup.
-
-  *aCurrentValue = value;
-  return NS_OK;
+  value = attrValue.ToDouble(&error);
+  return NS_FAILED(error) ? UnspecifiedNaN() : value;
 }
 
 template<int Max>
-NS_IMETHODIMP
-ProgressMeterAccessible<Max>::SetCurrentValue(double aValue)
+bool
+ProgressMeterAccessible<Max>::SetCurValue(double aValue)
 {
-  return NS_ERROR_FAILURE; // Progress meters are readonly.
+  return false; // progress meters are readonly.
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // RadioButtonAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 RadioButtonAccessible::
   RadioButtonAccessible(nsIContent* aContent, DocAccessible* aDoc) :
--- a/accessible/src/generic/FormControlAccessible.h
+++ b/accessible/src/generic/FormControlAccessible.h
@@ -23,23 +23,29 @@ public:
   {
     // Ignore 'ValueChange' DOM event in lieu of @value attribute change
     // notifications.
     mStateFlags |= eHasNumericValue | eIgnoreDOMUIEvent;
     mType = eProgressType;
   }
 
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIACCESSIBLEVALUE
 
   // Accessible
   virtual void Value(nsString& aValue);
   virtual mozilla::a11y::role NativeRole();
   virtual uint64_t NativeState();
 
+  // Value
+  virtual double MaxValue() const MOZ_OVERRIDE;
+  virtual double MinValue() const MOZ_OVERRIDE;
+  virtual double CurValue() const MOZ_OVERRIDE;
+  virtual double Step() const MOZ_OVERRIDE;
+  virtual bool SetCurValue(double aValue) MOZ_OVERRIDE;
+
   // Widgets
   virtual bool IsWidget() const;
 };
 
 /**
   * Generic class used for radio buttons.
   */
 class RadioButtonAccessible : public LeafAccessible
--- a/accessible/src/html/HTMLFormControlAccessible.cpp
+++ b/accessible/src/html/HTMLFormControlAccessible.cpp
@@ -22,16 +22,17 @@
 #include "nsIEditor.h"
 #include "nsIFormControl.h"
 #include "nsINameSpaceManager.h"
 #include "nsIPersistentProperties2.h"
 #include "nsISelectionController.h"
 #include "nsIServiceManager.h"
 #include "nsITextControlFrame.h"
 
+#include "mozilla/FloatingPoint.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLCheckboxAccessible
@@ -540,19 +541,16 @@ HTMLFileInputAccessible::HandleAccEvent(
   return NS_OK;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLRangeAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
-NS_IMPL_ISUPPORTS_INHERITED1(HTMLRangeAccessible, LeafAccessible,
-                             nsIAccessibleValue)
-
 role
 HTMLRangeAccessible::NativeRole()
 {
   return roles::SLIDER;
 }
 
 bool
 HTMLRangeAccessible::IsWidget() const
@@ -565,68 +563,63 @@ HTMLRangeAccessible::Value(nsString& aVa
 {
   LeafAccessible::Value(aValue);
   if (!aValue.IsEmpty())
     return;
 
   HTMLInputElement::FromContent(mContent)->GetValue(aValue);
 }
 
-NS_IMETHODIMP
-HTMLRangeAccessible::GetMaximumValue(double* aMaximumValue)
+double
+HTMLRangeAccessible::MaxValue() const
 {
-  nsresult rv = LeafAccessible::GetMaximumValue(aMaximumValue);
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
-
-  *aMaximumValue = HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
-  return NS_OK;
-}
+  double value = LeafAccessible::MaxValue();
+  if (!IsNaN(value))
+    return value;
 
-
-NS_IMETHODIMP
-HTMLRangeAccessible::GetMinimumValue(double* aMinimumValue)
-{
-  nsresult rv = LeafAccessible::GetMinimumValue(aMinimumValue);
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
-
-  *aMinimumValue = HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
-  return NS_OK;
+  return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
 }
 
 
-NS_IMETHODIMP
-HTMLRangeAccessible::GetMinimumIncrement(double* aMinimumIncrement)
+double
+HTMLRangeAccessible::MinValue() const
 {
-  nsresult rv = LeafAccessible::GetMinimumIncrement(aMinimumIncrement);
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
+  double value = LeafAccessible::MinValue();
+  if (!IsNaN(value))
+    return value;
 
-  *aMinimumIncrement = HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
-  return NS_OK;
+  return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
 }
 
-NS_IMETHODIMP
-HTMLRangeAccessible::GetCurrentValue(double* aCurrentValue)
+double
+HTMLRangeAccessible::Step() const
 {
-  nsresult rv = LeafAccessible::GetCurrentValue(aCurrentValue);
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
+  double value = LeafAccessible::Step();
+  if (!IsNaN(value))
+    return value;
 
-  *aCurrentValue = HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
-  return NS_OK;
+  return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
 }
 
-NS_IMETHODIMP
-HTMLRangeAccessible::SetCurrentValue(double aValue)
+double
+HTMLRangeAccessible::CurValue() const
+{
+  double value = LeafAccessible::CurValue();
+  if (!IsNaN(value))
+    return value;
+
+  return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
+}
+
+bool
+HTMLRangeAccessible::SetCurValue(double aValue)
 {
   ErrorResult er;
   HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
-  return er.ErrorCode();
+  return !er.Failed();
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLGroupboxAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 HTMLGroupboxAccessible::
--- a/accessible/src/html/HTMLFormControlAccessible.h
+++ b/accessible/src/html/HTMLFormControlAccessible.h
@@ -167,23 +167,27 @@ class HTMLRangeAccessible : public LeafA
 {
 public:
   HTMLRangeAccessible(nsIContent* aContent, DocAccessible* aDoc) :
     LeafAccessible(aContent, aDoc)
   {
     mStateFlags |= eHasNumericValue;
   }
 
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIACCESSIBLEVALUE
-
   // Accessible
   virtual void Value(nsString& aValue);
   virtual mozilla::a11y::role NativeRole();
 
+  // Value
+  virtual double MaxValue() const MOZ_OVERRIDE;
+  virtual double MinValue() const MOZ_OVERRIDE;
+  virtual double CurValue() const MOZ_OVERRIDE;
+  virtual double Step() const MOZ_OVERRIDE;
+  virtual bool SetCurValue(double aValue) MOZ_OVERRIDE;
+
   // Widgets
   virtual bool IsWidget() const;
 };
 
 
 /**
  * Accessible for HTML fieldset element.
  */
--- a/accessible/src/jsat/AccessFu.jsm
+++ b/accessible/src/jsat/AccessFu.jsm
@@ -81,17 +81,17 @@ this.AccessFu = {
     if (this._enabled)
       return;
     this._enabled = true;
 
     Cu.import('resource://gre/modules/accessibility/Utils.jsm');
     Cu.import('resource://gre/modules/accessibility/TouchAdapter.jsm');
     Cu.import('resource://gre/modules/accessibility/Presentation.jsm');
 
-    Logger.info('enable');
+    Logger.info('Enabled');
 
     for each (let mm in Utils.AllMessageManagers) {
       this._addMessageListeners(mm);
       this._loadFrameScript(mm);
     }
 
     // Add stylesheet
     let stylesheetURL = 'chrome://global/content/accessibility/AccessFu.css';
@@ -140,17 +140,17 @@ this.AccessFu = {
    * Disable AccessFu and return to default interaction mode.
    */
   _disable: function _disable() {
     if (!this._enabled)
       return;
 
     this._enabled = false;
 
-    Logger.info('disable');
+    Logger.info('Disabled');
 
     Utils.win.document.removeChild(this.stylesheet.get());
 
     for each (let mm in Utils.AllMessageManagers) {
       mm.sendAsyncMessage('AccessFu:Stop');
       this._removeMessageListeners(mm);
     }
 
@@ -519,19 +519,18 @@ var Output = {
 
     output: function output(aActions) {
       if (!this.inited) {
         this.init();
       }
 
       for (let action of aActions) {
         let window = Utils.win;
-        Logger.info('tts.' + action.method,
-                    '"' + action.data + '"',
-                    JSON.stringify(action.options));
+        Logger.debug('tts.' + action.method, '"' + action.data + '"',
+                     JSON.stringify(action.options));
 
         if (!action.options.enqueue && this.webspeechEnabled) {
           window.speechSynthesis.cancel();
         }
 
         if (action.method === 'speak' && this.webspeechEnabled) {
           window.speechSynthesis.speak(
             new window.SpeechSynthesisUtterance(action.data));
@@ -710,18 +709,18 @@ var Input = {
       }
     } catch (x) {
       Logger.logException(x);
     }
   },
 
   _handleGesture: function _handleGesture(aGesture) {
     let gestureName = aGesture.type + aGesture.touches.length;
-    Logger.info('Gesture', aGesture.type,
-                '(fingers: ' + aGesture.touches.length + ')');
+    Logger.debug('Gesture', aGesture.type,
+                 '(fingers: ' + aGesture.touches.length + ')');
 
     switch (gestureName) {
       case 'dwell1':
       case 'explore1':
         this.moveToPoint('Simple', aGesture.x, aGesture.y);
         break;
       case 'doubletap1':
         this.activateCurrent();
new file mode 100644
--- /dev/null
+++ b/accessible/src/jsat/Constants.jsm
@@ -0,0 +1,39 @@
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+
+this.EXPORTED_SYMBOLS = ['Roles', 'Events', 'Relations', 'Filters'];
+
+function ConstantsMap (aObject, aPrefix) {
+  let offset = aPrefix.length;
+  for (var name in aObject) {
+    if (name.indexOf(aPrefix) === 0) {
+      this[name.slice(offset)] = aObject[name];
+    }
+  }
+}
+
+XPCOMUtils.defineLazyGetter(
+  this, 'Roles',
+  function() {
+    return new ConstantsMap(Ci.nsIAccessibleRole, 'ROLE_');
+  });
+
+XPCOMUtils.defineLazyGetter(
+  this, 'Events',
+  function() {
+    return new ConstantsMap(Ci.nsIAccessibleEvent, 'EVENT_');
+  });
+
+XPCOMUtils.defineLazyGetter(
+  this, 'Relations',
+  function() {
+    return new ConstantsMap(Ci.nsIAccessibleRelation, 'RELATION_');
+  });
+
+XPCOMUtils.defineLazyGetter(
+  this, 'Filters',
+  function() {
+    return new ConstantsMap(Ci.nsIAccessibleTraversalRule, 'FILTER_');
+  });
--- a/accessible/src/jsat/EventManager.jsm
+++ b/accessible/src/jsat/EventManager.jsm
@@ -2,44 +2,33 @@
  * 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/. */
 
 'use strict';
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
-const EVENT_VIRTUALCURSOR_CHANGED = Ci.nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED;
-const EVENT_STATE_CHANGE = Ci.nsIAccessibleEvent.EVENT_STATE_CHANGE;
-const EVENT_SCROLLING_START = Ci.nsIAccessibleEvent.EVENT_SCROLLING_START;
-const EVENT_TEXT_CARET_MOVED = Ci.nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED;
-const EVENT_TEXT_INSERTED = Ci.nsIAccessibleEvent.EVENT_TEXT_INSERTED;
-const EVENT_TEXT_REMOVED = Ci.nsIAccessibleEvent.EVENT_TEXT_REMOVED;
-const EVENT_FOCUS = Ci.nsIAccessibleEvent.EVENT_FOCUS;
-const EVENT_SHOW = Ci.nsIAccessibleEvent.EVENT_SHOW;
-const EVENT_HIDE = Ci.nsIAccessibleEvent.EVENT_HIDE;
-
-const ROLE_INTERNAL_FRAME = Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME;
-const ROLE_DOCUMENT = Ci.nsIAccessibleRole.ROLE_DOCUMENT;
-const ROLE_CHROME_WINDOW = Ci.nsIAccessibleRole.ROLE_CHROME_WINDOW;
-const ROLE_TEXT_LEAF = Ci.nsIAccessibleRole.ROLE_TEXT_LEAF;
-
 const TEXT_NODE = 3;
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Services',
   'resource://gre/modules/Services.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Presentation',
   'resource://gre/modules/accessibility/Presentation.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'TraversalRules',
   'resource://gre/modules/accessibility/TraversalRules.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Roles',
+  'resource://gre/modules/accessibility/Constants.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Events',
+  'resource://gre/modules/accessibility/Constants.jsm');
 
 this.EXPORTED_SYMBOLS = ['EventManager'];
 
 this.EventManager = function EventManager(aContentScope) {
   this.contentScope = aContentScope;
   this.addEventListener = this.contentScope.addEventListener.bind(
     this.contentScope);
   this.removeEventListener = this.contentScope.removeEventListener.bind(
@@ -52,17 +41,17 @@ this.EventManager = function EventManage
 };
 
 this.EventManager.prototype = {
   editState: {},
 
   start: function start() {
     try {
       if (!this._started) {
-        Logger.info('EventManager.start', Utils.MozBuildApp);
+        Logger.debug('EventManager.start');
 
         this._started = true;
 
         AccessibilityEventObserver.addListener(this);
 
         this.webProgress.addProgressListener(this,
           (Ci.nsIWebProgress.NOTIFY_STATE_ALL |
            Ci.nsIWebProgress.NOTIFY_LOCATION));
@@ -79,17 +68,17 @@ this.EventManager.prototype = {
   },
 
   // XXX: Stop is not called when the tab is closed (|TabClose| event is too
   // late). It is only called when the AccessFu is disabled explicitly.
   stop: function stop() {
     if (!this._started) {
       return;
     }
-    Logger.info('EventManager.stop', Utils.MozBuildApp);
+    Logger.debug('EventManager.stop');
     AccessibilityEventObserver.removeListener(this);
     try {
       this.webProgress.removeProgressListener(this);
       this.removeEventListener('scroll', this, true);
       this.removeEventListener('resize', this, true);
       // XXX: Ideally this would be an a11y event. Bug #742280.
       this.removeEventListener('DOMActivate', this, true);
     } catch (x) {
@@ -139,70 +128,70 @@ this.EventManager.prototype = {
 
   handleAccEvent: function handleAccEvent(aEvent) {
     if (Logger.logLevel >= Logger.DEBUG)
       Logger.debug('A11yEvent', Logger.eventToString(aEvent),
                    Logger.accessibleToString(aEvent.accessible));
 
     // Don't bother with non-content events in firefox.
     if (Utils.MozBuildApp == 'browser' &&
-        aEvent.eventType != EVENT_VIRTUALCURSOR_CHANGED &&
+        aEvent.eventType != Events.VIRTUALCURSOR_CHANGED &&
         // XXX Bug 442005 results in DocAccessible::getDocType returning
         // NS_ERROR_FAILURE. Checking for aEvent.accessibleDocument.docType ==
         // 'window' does not currently work.
         (aEvent.accessibleDocument.DOMDocument.doctype &&
          aEvent.accessibleDocument.DOMDocument.doctype.name === 'window')) {
       return;
     }
 
     switch (aEvent.eventType) {
-      case EVENT_VIRTUALCURSOR_CHANGED:
+      case Events.VIRTUALCURSOR_CHANGED:
       {
         let pivot = aEvent.accessible.
           QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
         let position = pivot.position;
-        if (position && position.role == ROLE_INTERNAL_FRAME)
+        if (position && position.role == Roles.INTERNAL_FRAME)
           break;
         let event = aEvent.
           QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent);
         let reason = event.reason;
 
         if (this.editState.editing) {
           aEvent.accessibleDocument.takeFocus();
         }
         this.present(
           Presentation.pivotChanged(position, event.oldAccessible, reason,
                                     pivot.startOffset, pivot.endOffset));
 
         break;
       }
-      case EVENT_STATE_CHANGE:
+      case Events.STATE_CHANGE:
       {
         let event = aEvent.QueryInterface(Ci.nsIAccessibleStateChangeEvent);
         if (event.state == Ci.nsIAccessibleStates.STATE_CHECKED &&
             !(event.isExtraState)) {
           this.present(
             Presentation.
               actionInvoked(aEvent.accessible,
                             event.isEnabled ? 'check' : 'uncheck'));
         } else if (event.state == Ci.nsIAccessibleStates.STATE_SELECTED) {
           this.present(
             Presentation.
               actionInvoked(aEvent.accessible,
                             event.isEnabled ? 'select' : 'unselect'));
         }
         break;
       }
-      case EVENT_SCROLLING_START:
+      case Events.SCROLLING_START:
       {
         let vc = Utils.getVirtualCursor(aEvent.accessibleDocument);
         vc.moveNext(TraversalRules.Simple, aEvent.accessible, true);
         break;
       }
-      case EVENT_TEXT_CARET_MOVED:
+      case Events.TEXT_CARET_MOVED:
       {
         let acc = aEvent.accessible;
         let characterCount = acc.
           QueryInterface(Ci.nsIAccessibleText).characterCount;
         let caretOffset = aEvent.
           QueryInterface(Ci.nsIAccessibleCaretMoveEvent).caretOffset;
 
         // Update editing state, both for presenter and other things
@@ -228,66 +217,66 @@ this.EventManager.prototype = {
           this.sendMsgFunc("AccessFu:Input", editState);
 
         this.present(Presentation.textSelectionChanged(acc.getText(0,-1),
                      caretOffset, caretOffset, 0, 0, aEvent.isFromUserInput));
 
         this.editState = editState;
         break;
       }
-      case EVENT_SHOW:
+      case Events.SHOW:
       {
         let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
           ['additions', 'all']);
         // Only handle show if it is a relevant live region.
         if (!liveRegion) {
           break;
         }
         // Show for text is handled by the EVENT_TEXT_INSERTED handler.
-        if (aEvent.accessible.role === ROLE_TEXT_LEAF) {
+        if (aEvent.accessible.role === Roles.TEXT_LEAF) {
           break;
         }
-        this._dequeueLiveEvent(EVENT_HIDE, liveRegion);
+        this._dequeueLiveEvent(Events.HIDE, liveRegion);
         this.present(Presentation.liveRegion(liveRegion, isPolite, false));
         break;
       }
-      case EVENT_HIDE:
+      case Events.HIDE:
       {
         let {liveRegion, isPolite} = this._handleLiveRegion(
           aEvent.QueryInterface(Ci.nsIAccessibleHideEvent),
           ['removals', 'all']);
         // Only handle hide if it is a relevant live region.
         if (!liveRegion) {
           break;
         }
         // Hide for text is handled by the EVENT_TEXT_REMOVED handler.
-        if (aEvent.accessible.role === ROLE_TEXT_LEAF) {
+        if (aEvent.accessible.role === Roles.TEXT_LEAF) {
           break;
         }
-        this._queueLiveEvent(EVENT_HIDE, liveRegion, isPolite);
+        this._queueLiveEvent(Events.HIDE, liveRegion, isPolite);
         break;
       }
-      case EVENT_TEXT_INSERTED:
-      case EVENT_TEXT_REMOVED:
+      case Events.TEXT_INSERTED:
+      case Events.TEXT_REMOVED:
       {
         let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
           ['text', 'all']);
         if (aEvent.isFromUserInput || liveRegion) {
           // Handle all text mutations coming from the user or if they happen
           // on a live region.
           this._handleText(aEvent, liveRegion, isPolite);
         }
         break;
       }
-      case EVENT_FOCUS:
+      case Events.FOCUS:
       {
         // Put vc where the focus is at
         let acc = aEvent.accessible;
         let doc = aEvent.accessibleDocument;
-        if (acc.role != ROLE_DOCUMENT && doc.role != ROLE_CHROME_WINDOW) {
+        if (acc.role != Roles.DOCUMENT && doc.role != Roles.CHROME_WINDOW) {
           let vc = Utils.getVirtualCursor(doc);
           vc.moveNext(TraversalRules.Simple, acc, true);
         }
         break;
       }
     }
   },
 
@@ -309,21 +298,21 @@ this.EventManager.prototype = {
     // If there are embedded objects in the text, ignore them.
     // Assuming changes to the descendants would already be handled by the
     // show/hide event.
     let modifiedText = event.modifiedText.replace(/\uFFFC/g, '').trim();
     if (!modifiedText) {
       return;
     }
     if (aLiveRegion) {
-      if (aEvent.eventType === EVENT_TEXT_REMOVED) {
-        this._queueLiveEvent(EVENT_TEXT_REMOVED, aLiveRegion, aIsPolite,
+      if (aEvent.eventType === Events.TEXT_REMOVED) {
+        this._queueLiveEvent(Events.TEXT_REMOVED, aLiveRegion, aIsPolite,
           modifiedText);
       } else {
-        this._dequeueLiveEvent(EVENT_TEXT_REMOVED, aLiveRegion);
+        this._dequeueLiveEvent(Events.TEXT_REMOVED, aLiveRegion);
         this.present(Presentation.liveRegion(aLiveRegion, aIsPolite, false,
           modifiedText));
       }
     } else {
       this.present(Presentation.textChanged(isInserted, event.start,
         event.length, text, modifiedText));
     }
   },
--- a/accessible/src/jsat/Makefile.in
+++ b/accessible/src/jsat/Makefile.in
@@ -1,19 +1,3 @@
 # 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/.
-
-INSTALL_TARGETS += ACCESSFU
-
-ACCESSFU_FILES := \
-  AccessFu.jsm \
-  EventManager.jsm \
-  jar.mn \
-  Makefile.in \
-  OutputGenerator.jsm \
-  Presentation.jsm \
-  TouchAdapter.jsm \
-  TraversalRules.jsm \
-  Utils.jsm \
-  $(NULL)
-
-ACCESSFU_DEST = $(FINAL_TARGET)/modules/accessibility
--- a/accessible/src/jsat/OutputGenerator.jsm
+++ b/accessible/src/jsat/OutputGenerator.jsm
@@ -13,29 +13,27 @@ const INCLUDE_DESC = 0x01;
 const INCLUDE_NAME = 0x02;
 const INCLUDE_VALUE = 0x04;
 const INCLUDE_CUSTOM = 0x08;
 const NAME_FROM_SUBTREE_RULE = 0x10;
 
 const OUTPUT_DESC_FIRST = 0;
 const OUTPUT_DESC_LAST = 1;
 
-const ROLE_LISTITEM = Ci.nsIAccessibleRole.ROLE_LISTITEM;
-const ROLE_STATICTEXT = Ci.nsIAccessibleRole.ROLE_STATICTEXT;
-const ROLE_LINK = Ci.nsIAccessibleRole.ROLE_LINK;
-
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'PrefCache',
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'PluralForm',
   'resource://gre/modules/PluralForm.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Roles',
+  'resource://gre/modules/accessibility/Constants.jsm');
 
 var gStringBundle = Cc['@mozilla.org/intl/stringbundle;1'].
   getService(Ci.nsIStringBundleService).
   createBundle('chrome://global/locale/AccessFu.properties');
 
 this.EXPORTED_SYMBOLS = ['UtteranceGenerator', 'BrailleGenerator'];
 
 this.OutputGenerator = {
@@ -692,18 +690,18 @@ this.BrailleGenerator = {
   objectOutputFunctions: {
 
     __proto__: OutputGenerator.objectOutputFunctions,
 
     defaultFunc: function defaultFunc(aAccessible, aRoleStr, aStates, aFlags) {
       let braille = this.objectOutputFunctions._generateBaseOutput.apply(this, arguments);
 
       if (aAccessible.indexInParent === 1 &&
-          aAccessible.parent.role == ROLE_LISTITEM &&
-          aAccessible.previousSibling.role == ROLE_STATICTEXT) {
+          aAccessible.parent.role == Roles.LISTITEM &&
+          aAccessible.previousSibling.role == Roles.STATICTEXT) {
         if (aAccessible.parent.parent && aAccessible.parent.parent.DOMNode &&
             aAccessible.parent.parent.DOMNode.nodeName == 'UL') {
           braille.unshift('*');
         } else {
           braille.unshift(aAccessible.previousSibling.name);
         }
       }
 
@@ -750,17 +748,17 @@ this.BrailleGenerator = {
 
     rowheader: function rowheader() {
       return this.objectOutputFunctions.cell.apply(this, arguments);
     },
 
     statictext: function statictext(aAccessible, aRoleStr, aStates, aFlags) {
       // Since we customize the list bullet's output, we add the static
       // text from the first node in each listitem, so skip it here.
-      if (aAccessible.parent.role == ROLE_LISTITEM) {
+      if (aAccessible.parent.role == Roles.LISTITEM) {
         return [];
       }
 
       return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
     },
 
     _useStateNotRole: function _useStateNotRole(aAccessible, aRoleStr, aStates, aFlags) {
       let braille = [];
@@ -783,17 +781,17 @@ this.BrailleGenerator = {
     },
 
     togglebutton: function radiobutton(aAccessible, aRoleStr, aStates, aFlags) {
       return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
     }
   },
 
   _getContextStart: function _getContextStart(aContext) {
-    if (aContext.accessible.parent.role == ROLE_LINK) {
+    if (aContext.accessible.parent.role == Roles.LINK) {
       return [aContext.accessible.parent];
     }
 
     return [];
   },
 
   _getOutputName: function _getOutputName(aName) {
     return OutputGenerator._getOutputName(aName) + 'Abbr';
--- a/accessible/src/jsat/TouchAdapter.jsm
+++ b/accessible/src/jsat/TouchAdapter.jsm
@@ -41,17 +41,17 @@ this.TouchAdapter = {
 
   // The virtual touch ID generated by a mouse event.
   MOUSE_ID: 'mouse',
 
   // Synthesized touch ID.
   SYNTH_ID: -1,
 
   start: function TouchAdapter_start() {
-    Logger.info('TouchAdapter.start');
+    Logger.debug('TouchAdapter.start');
 
     this._touchPoints = {};
     this._dwellTimeout = 0;
     this._prevGestures = {};
     this._lastExploreTime = 0;
     this._dpi = Utils.win.QueryInterface(Ci.nsIInterfaceRequestor).
       getInterface(Ci.nsIDOMWindowUtils).displayDPI;
 
@@ -59,17 +59,17 @@ this.TouchAdapter = {
 
     for (let eventType in this.eventsOfInterest) {
       target.addEventListener(eventType, this, true, true);
     }
 
   },
 
   stop: function TouchAdapter_stop() {
-    Logger.info('TouchAdapter.stop');
+    Logger.debug('TouchAdapter.stop');
 
     let target = Utils.win;
 
     for (let eventType in this.eventsOfInterest) {
       target.removeEventListener(eventType, this, true, true);
     }
   },
 
--- a/accessible/src/jsat/TraversalRules.jsm
+++ b/accessible/src/jsat/TraversalRules.jsm
@@ -4,308 +4,271 @@
 
 'use strict';
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
-const FILTER_IGNORE = Ci.nsIAccessibleTraversalRule.FILTER_IGNORE;
-const FILTER_MATCH = Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
-const FILTER_IGNORE_SUBTREE = Ci.nsIAccessibleTraversalRule.FILTER_IGNORE_SUBTREE;
-
-const ROLE_MENUITEM = Ci.nsIAccessibleRole.ROLE_MENUITEM;
-const ROLE_LINK = Ci.nsIAccessibleRole.ROLE_LINK;
-const ROLE_PAGETAB = Ci.nsIAccessibleRole.ROLE_PAGETAB;
-const ROLE_GRAPHIC = Ci.nsIAccessibleRole.ROLE_GRAPHIC;
-const ROLE_STATICTEXT = Ci.nsIAccessibleRole.ROLE_STATICTEXT;
-const ROLE_TEXT_LEAF = Ci.nsIAccessibleRole.ROLE_TEXT_LEAF;
-const ROLE_PUSHBUTTON = Ci.nsIAccessibleRole.ROLE_PUSHBUTTON;
-const ROLE_SPINBUTTON = Ci.nsIAccessibleRole.ROLE_SPINBUTTON;
-const ROLE_CHECKBUTTON = Ci.nsIAccessibleRole.ROLE_CHECKBUTTON;
-const ROLE_RADIOBUTTON = Ci.nsIAccessibleRole.ROLE_RADIOBUTTON;
-const ROLE_COMBOBOX = Ci.nsIAccessibleRole.ROLE_COMBOBOX;
-const ROLE_PROGRESSBAR = Ci.nsIAccessibleRole.ROLE_PROGRESSBAR;
-const ROLE_BUTTONDROPDOWN = Ci.nsIAccessibleRole.ROLE_BUTTONDROPDOWN;
-const ROLE_BUTTONMENU = Ci.nsIAccessibleRole.ROLE_BUTTONMENU;
-const ROLE_CHECK_MENU_ITEM = Ci.nsIAccessibleRole.ROLE_CHECK_MENU_ITEM;
-const ROLE_PASSWORD_TEXT = Ci.nsIAccessibleRole.ROLE_PASSWORD_TEXT;
-const ROLE_RADIO_MENU_ITEM = Ci.nsIAccessibleRole.ROLE_RADIO_MENU_ITEM;
-const ROLE_TOGGLE_BUTTON = Ci.nsIAccessibleRole.ROLE_TOGGLE_BUTTON;
-const ROLE_KEY = Ci.nsIAccessibleRole.ROLE_KEY;
-const ROLE_ENTRY = Ci.nsIAccessibleRole.ROLE_ENTRY;
-const ROLE_LIST = Ci.nsIAccessibleRole.ROLE_LIST;
-const ROLE_DEFINITION_LIST = Ci.nsIAccessibleRole.ROLE_DEFINITION_LIST;
-const ROLE_LISTITEM = Ci.nsIAccessibleRole.ROLE_LISTITEM;
-const ROLE_BUTTONDROPDOWNGRID = Ci.nsIAccessibleRole.ROLE_BUTTONDROPDOWNGRID;
-const ROLE_LISTBOX = Ci.nsIAccessibleRole.ROLE_LISTBOX;
-const ROLE_OPTION = Ci.nsIAccessibleRole.ROLE_OPTION;
-const ROLE_SLIDER = Ci.nsIAccessibleRole.ROLE_SLIDER;
-const ROLE_HEADING = Ci.nsIAccessibleRole.ROLE_HEADING;
-const ROLE_HEADER = Ci.nsIAccessibleRole.ROLE_HEADER;
-const ROLE_TERM = Ci.nsIAccessibleRole.ROLE_TERM;
-const ROLE_SEPARATOR = Ci.nsIAccessibleRole.ROLE_SEPARATOR;
-const ROLE_TABLE = Ci.nsIAccessibleRole.ROLE_TABLE;
-const ROLE_INTERNAL_FRAME = Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME;
-const ROLE_PARAGRAPH = Ci.nsIAccessibleRole.ROLE_PARAGRAPH;
-const ROLE_SECTION = Ci.nsIAccessibleRole.ROLE_SECTION;
-const ROLE_LABEL = Ci.nsIAccessibleRole.ROLE_LABEL;
-
 this.EXPORTED_SYMBOLS = ['TraversalRules'];
 
 Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Roles',
+  'resource://gre/modules/accessibility/Constants.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Filters',
+  'resource://gre/modules/accessibility/Constants.jsm');
 
 let gSkipEmptyImages = new PrefCache('accessibility.accessfu.skip_empty_images');
 
 function BaseTraversalRule(aRoles, aMatchFunc) {
   this._explicitMatchRoles = new Set(aRoles);
   this._matchRoles = aRoles;
-  if (aRoles.indexOf(ROLE_LABEL) < 0) {
-    this._matchRoles.push(ROLE_LABEL);
+  if (aRoles.indexOf(Roles.LABEL) < 0) {
+    this._matchRoles.push(Roles.LABEL);
   }
-  this._matchFunc = aMatchFunc || function (acc) { return FILTER_MATCH; };
+  this._matchFunc = aMatchFunc || function (acc) { return Filters.MATCH; };
 }
 
 BaseTraversalRule.prototype = {
     getMatchRoles: function BaseTraversalRule_getmatchRoles(aRules) {
       aRules.value = this._matchRoles;
       return aRules.value.length;
     },
 
     preFilter: Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT |
     Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE |
     Ci.nsIAccessibleTraversalRule.PREFILTER_ARIA_HIDDEN |
     Ci.nsIAccessibleTraversalRule.PREFILTER_TRANSPARENT,
 
     match: function BaseTraversalRule_match(aAccessible)
     {
       let role = aAccessible.role;
-      if (role == ROLE_INTERNAL_FRAME) {
+      if (role == Roles.INTERNAL_FRAME) {
         return (Utils.getMessageManager(aAccessible.DOMNode)) ?
-          FILTER_MATCH  | FILTER_IGNORE_SUBTREE : FILTER_IGNORE;
+          Filters.MATCH  | Filters.IGNORE_SUBTREE : Filters.IGNORE;
       }
 
       let matchResult = this._explicitMatchRoles.has(role) ?
-          this._matchFunc(aAccessible) : FILTER_IGNORE;
+          this._matchFunc(aAccessible) : Filters.IGNORE;
 
       // If we are on a label that nests a checkbox/radio we should land on it.
       // It is a bigger touch target, and it reduces clutter.
-      if (role == ROLE_LABEL && !(matchResult & FILTER_IGNORE_SUBTREE)) {
+      if (role == Roles.LABEL && !(matchResult & Filters.IGNORE_SUBTREE)) {
         let control = Utils.getEmbeddedControl(aAccessible);
         if (control && this._explicitMatchRoles.has(control.role)) {
-          matchResult = this._matchFunc(control) | FILTER_IGNORE_SUBTREE;
+          matchResult = this._matchFunc(control) | Filters.IGNORE_SUBTREE;
         }
       }
 
       return matchResult;
     },
 
     QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessibleTraversalRule])
 };
 
 var gSimpleTraversalRoles =
-  [ROLE_MENUITEM,
-   ROLE_LINK,
-   ROLE_PAGETAB,
-   ROLE_GRAPHIC,
-   ROLE_STATICTEXT,
-   ROLE_TEXT_LEAF,
-   ROLE_PUSHBUTTON,
-   ROLE_CHECKBUTTON,
-   ROLE_RADIOBUTTON,
-   ROLE_COMBOBOX,
-   ROLE_PROGRESSBAR,
-   ROLE_BUTTONDROPDOWN,
-   ROLE_BUTTONMENU,
-   ROLE_CHECK_MENU_ITEM,
-   ROLE_PASSWORD_TEXT,
-   ROLE_RADIO_MENU_ITEM,
-   ROLE_TOGGLE_BUTTON,
-   ROLE_ENTRY,
-   ROLE_KEY,
-   ROLE_HEADER,
-   ROLE_HEADING,
-   ROLE_SLIDER,
-   ROLE_SPINBUTTON,
-   ROLE_OPTION,
+  [Roles.MENUITEM,
+   Roles.LINK,
+   Roles.PAGETAB,
+   Roles.GRAPHIC,
+   Roles.STATICTEXT,
+   Roles.TEXT_LEAF,
+   Roles.PUSHBUTTON,
+   Roles.CHECKBUTTON,
+   Roles.RADIOBUTTON,
+   Roles.COMBOBOX,
+   Roles.PROGRESSBAR,
+   Roles.BUTTONDROPDOWN,
+   Roles.BUTTONMENU,
+   Roles.CHECK_MENU_ITEM,
+   Roles.PASSWORD_TEXT,
+   Roles.RADIO_MENU_ITEM,
+   Roles.TOGGLE_BUTTON,
+   Roles.ENTRY,
+   Roles.KEY,
+   Roles.HEADER,
+   Roles.HEADING,
+   Roles.SLIDER,
+   Roles.SPINBUTTON,
+   Roles.OPTION,
    // Used for traversing in to child OOP frames.
-   ROLE_INTERNAL_FRAME];
+   Roles.INTERNAL_FRAME];
 
 this.TraversalRules = {
   Simple: new BaseTraversalRule(
     gSimpleTraversalRoles,
     function Simple_match(aAccessible) {
       function hasZeroOrSingleChildDescendants () {
         for (let acc = aAccessible; acc.childCount > 0; acc = acc.firstChild) {
           if (acc.childCount > 1) {
             return false;
           }
         }
 
         return true;
       }
 
       switch (aAccessible.role) {
-      case ROLE_COMBOBOX:
+      case Roles.COMBOBOX:
         // We don't want to ignore the subtree because this is often
         // where the list box hangs out.
-        return FILTER_MATCH;
-      case ROLE_TEXT_LEAF:
+        return Filters.MATCH;
+      case Roles.TEXT_LEAF:
         {
           // Nameless text leaves are boring, skip them.
           let name = aAccessible.name;
           if (name && name.trim())
-            return FILTER_MATCH;
+            return Filters.MATCH;
           else
-            return FILTER_IGNORE;
+            return Filters.IGNORE;
         }
-      case ROLE_STATICTEXT:
+      case Roles.STATICTEXT:
         {
           let parent = aAccessible.parent;
           // Ignore prefix static text in list items. They are typically bullets or numbers.
           if (parent.childCount > 1 && aAccessible.indexInParent == 0 &&
-              parent.role == ROLE_LISTITEM)
-            return FILTER_IGNORE;
+              parent.role == Roles.LISTITEM)
+            return Filters.IGNORE;
 
-          return FILTER_MATCH;
+          return Filters.MATCH;
         }
-      case ROLE_GRAPHIC:
+      case Roles.GRAPHIC:
         return TraversalRules._shouldSkipImage(aAccessible);
-      case ROLE_LINK:
-      case ROLE_HEADER:
-      case ROLE_HEADING:
+      case Roles.LINK:
+      case Roles.HEADER:
+      case Roles.HEADING:
         return hasZeroOrSingleChildDescendants() ?
-          (FILTER_MATCH | FILTER_IGNORE_SUBTREE) : (FILTER_IGNORE);
+          (Filters.MATCH | Filters.IGNORE_SUBTREE) : (Filters.IGNORE);
       default:
         // Ignore the subtree, if there is one. So that we don't land on
         // the same content that was already presented by its parent.
-        return FILTER_MATCH |
-          FILTER_IGNORE_SUBTREE;
+        return Filters.MATCH |
+          Filters.IGNORE_SUBTREE;
       }
     }
   ),
 
   Anchor: new BaseTraversalRule(
-    [ROLE_LINK],
+    [Roles.LINK],
     function Anchor_match(aAccessible)
     {
       // We want to ignore links, only focus named anchors.
       let state = {};
       let extraState = {};
       aAccessible.getState(state, extraState);
       if (state.value & Ci.nsIAccessibleStates.STATE_LINKED) {
-        return FILTER_IGNORE;
+        return Filters.IGNORE;
       } else {
-        return FILTER_MATCH;
+        return Filters.MATCH;
       }
     }),
 
   Button: new BaseTraversalRule(
-    [ROLE_PUSHBUTTON,
-     ROLE_SPINBUTTON,
-     ROLE_TOGGLE_BUTTON,
-     ROLE_BUTTONDROPDOWN,
-     ROLE_BUTTONDROPDOWNGRID]),
+    [Roles.PUSHBUTTON,
+     Roles.SPINBUTTON,
+     Roles.TOGGLE_BUTTON,
+     Roles.BUTTONDROPDOWN,
+     Roles.BUTTONDROPDOWNGRID]),
 
   Combobox: new BaseTraversalRule(
-    [ROLE_COMBOBOX,
-     ROLE_LISTBOX]),
+    [Roles.COMBOBOX,
+     Roles.LISTBOX]),
 
   Landmark: new BaseTraversalRule(
     [],
     function Landmark_match(aAccessible) {
-      return Utils.getLandmarkName(aAccessible) ? FILTER_MATCH :
-        FILTER_IGNORE;
+      return Utils.getLandmarkName(aAccessible) ? Filters.MATCH :
+        Filters.IGNORE;
     }
   ),
 
   Entry: new BaseTraversalRule(
-    [ROLE_ENTRY,
-     ROLE_PASSWORD_TEXT]),
+    [Roles.ENTRY,
+     Roles.PASSWORD_TEXT]),
 
   FormElement: new BaseTraversalRule(
-    [ROLE_PUSHBUTTON,
-     ROLE_SPINBUTTON,
-     ROLE_TOGGLE_BUTTON,
-     ROLE_BUTTONDROPDOWN,
-     ROLE_BUTTONDROPDOWNGRID,
-     ROLE_COMBOBOX,
-     ROLE_LISTBOX,
-     ROLE_ENTRY,
-     ROLE_PASSWORD_TEXT,
-     ROLE_PAGETAB,
-     ROLE_RADIOBUTTON,
-     ROLE_RADIO_MENU_ITEM,
-     ROLE_SLIDER,
-     ROLE_CHECKBUTTON,
-     ROLE_CHECK_MENU_ITEM]),
+    [Roles.PUSHBUTTON,
+     Roles.SPINBUTTON,
+     Roles.TOGGLE_BUTTON,
+     Roles.BUTTONDROPDOWN,
+     Roles.BUTTONDROPDOWNGRID,
+     Roles.COMBOBOX,
+     Roles.LISTBOX,
+     Roles.ENTRY,
+     Roles.PASSWORD_TEXT,
+     Roles.PAGETAB,
+     Roles.RADIOBUTTON,
+     Roles.RADIO_MENU_ITEM,
+     Roles.SLIDER,
+     Roles.CHECKBUTTON,
+     Roles.CHECK_MENU_ITEM]),
 
   Graphic: new BaseTraversalRule(
-    [ROLE_GRAPHIC],
+    [Roles.GRAPHIC],
     function Graphic_match(aAccessible) {
       return TraversalRules._shouldSkipImage(aAccessible);
     }),
 
   Heading: new BaseTraversalRule(
-    [ROLE_HEADING]),
+    [Roles.HEADING]),
 
   ListItem: new BaseTraversalRule(
-    [ROLE_LISTITEM,
-     ROLE_TERM]),
+    [Roles.LISTITEM,
+     Roles.TERM]),
 
   Link: new BaseTraversalRule(
-    [ROLE_LINK],
+    [Roles.LINK],
     function Link_match(aAccessible)
     {
       // We want to ignore anchors, only focus real links.
       let state = {};
       let extraState = {};
       aAccessible.getState(state, extraState);
       if (state.value & Ci.nsIAccessibleStates.STATE_LINKED) {
-        return FILTER_MATCH;
+        return Filters.MATCH;
       } else {
-        return FILTER_IGNORE;
+        return Filters.IGNORE;
       }
     }),
 
   List: new BaseTraversalRule(
-    [ROLE_LIST,
-     ROLE_DEFINITION_LIST]),
+    [Roles.LIST,
+     Roles.DEFINITION_LIST]),
 
   PageTab: new BaseTraversalRule(
-    [ROLE_PAGETAB]),
+    [Roles.PAGETAB]),
 
   Paragraph: new BaseTraversalRule(
-    [ROLE_PARAGRAPH,
-     ROLE_SECTION],
+    [Roles.PARAGRAPH,
+     Roles.SECTION],
     function Paragraph_match(aAccessible) {
       for (let child = aAccessible.firstChild; child; child = child.nextSibling) {
-        if (child.role === ROLE_TEXT_LEAF) {
-          return FILTER_MATCH | FILTER_IGNORE_SUBTREE;
+        if (child.role === Roles.TEXT_LEAF) {
+          return Filters.MATCH | Filters.IGNORE_SUBTREE;
         }
       }
 
-      return FILTER_IGNORE;
+      return Filters.IGNORE;
     }),
 
   RadioButton: new BaseTraversalRule(
-    [ROLE_RADIOBUTTON,
-     ROLE_RADIO_MENU_ITEM]),
+    [Roles.RADIOBUTTON,
+     Roles.RADIO_MENU_ITEM]),
 
   Separator: new BaseTraversalRule(
-    [ROLE_SEPARATOR]),
+    [Roles.SEPARATOR]),
 
   Table: new BaseTraversalRule(
-    [ROLE_TABLE]),
+    [Roles.TABLE]),
 
   Checkbox: new BaseTraversalRule(
-    [ROLE_CHECKBUTTON,
-     ROLE_CHECK_MENU_ITEM]),
+    [Roles.CHECKBUTTON,
+     Roles.CHECK_MENU_ITEM]),
 
   _shouldSkipImage: function _shouldSkipImage(aAccessible) {
     if (gSkipEmptyImages.value && aAccessible.name === '') {
-      return FILTER_IGNORE;
+      return Filters.IGNORE;
     }
-    return FILTER_MATCH;
+    return Filters.MATCH;
   }
 };
--- a/accessible/src/jsat/Utils.jsm
+++ b/accessible/src/jsat/Utils.jsm
@@ -3,29 +3,27 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 'use strict';
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
-const EVENT_STATE_CHANGE = Ci.nsIAccessibleEvent.EVENT_STATE_CHANGE;
-
-const ROLE_CELL = Ci.nsIAccessibleRole.ROLE_CELL;
-const ROLE_COLUMNHEADER = Ci.nsIAccessibleRole.ROLE_COLUMNHEADER;
-const ROLE_ROWHEADER = Ci.nsIAccessibleRole.ROLE_ROWHEADER;
-
-const RELATION_LABEL_FOR = Ci.nsIAccessibleRelation.RELATION_LABEL_FOR;
-
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, 'Services',
   'resource://gre/modules/Services.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Rect',
   'resource://gre/modules/Geometry.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Roles',
+  'resource://gre/modules/accessibility/Constants.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Events',
+  'resource://gre/modules/accessibility/Constants.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Relations',
+  'resource://gre/modules/accessibility/Constants.jsm');
 
 this.EXPORTED_SYMBOLS = ['Utils', 'Logger', 'PivotContext', 'PrefCache'];
 
 this.Utils = {
   _buildAppMap: {
     '{3c2e2abc-06d4-11e1-ac3b-374f68613e61}': 'b2g',
     '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': 'browser',
     '{aa3c5121-dab2-40e2-81ca-7ea25febc110}': 'mobile/android',
@@ -292,17 +290,17 @@ this.Utils = {
     }
 
     // Looking up a role that would match a landmark.
     return this.matchAttributeValue(roles, landmarks);
   },
 
   getEmbeddedControl: function getEmbeddedControl(aLabel) {
     if (aLabel) {
-      let relation = aLabel.getRelationByType(RELATION_LABEL_FOR);
+      let relation = aLabel.getRelationByType(Relations.LABEL_FOR);
       for (let i = 0; i < relation.targetsCount; i++) {
         let target = relation.getTarget(i);
         if (target.parent === aLabel) {
           return target;
         }
       }
     }
 
@@ -394,17 +392,17 @@ this.Logger = {
     } catch (x) {
     }
 
     return str;
   },
 
   eventToString: function eventToString(aEvent) {
     let str = Utils.AccRetrieval.getStringEventType(aEvent.eventType);
-    if (aEvent.eventType == EVENT_STATE_CHANGE) {
+    if (aEvent.eventType == Events.STATE_CHANGE) {
       let event = aEvent.QueryInterface(Ci.nsIAccessibleStateChangeEvent);
       let stateStrings = event.isExtraState ?
         Utils.AccRetrieval.getStringStates(0, event.state) :
         Utils.AccRetrieval.getStringStates(event.state, 0);
       str += ' (' + stateStrings.item(0) + ')';
     }
 
     return str;
@@ -628,17 +626,17 @@ PivotContext.prototype = {
       return this._cells.get(domNode);
     }
 
     let cellInfo = {};
     let getAccessibleCell = function getAccessibleCell(aAccessible) {
       if (!aAccessible) {
         return null;
       }
-      if ([ROLE_CELL, ROLE_COLUMNHEADER, ROLE_ROWHEADER].indexOf(
+      if ([Roles.CELL, Roles.COLUMNHEADER, Roles.ROWHEADER].indexOf(
         aAccessible.role) < 0) {
           return null;
       }
       try {
         return aAccessible.QueryInterface(Ci.nsIAccessibleTableCell);
       } catch (x) {
         Logger.logException(x);
         return null;
@@ -689,22 +687,22 @@ PivotContext.prototype = {
 
     cellInfo.rowExtent = cellInfo.current.rowExtent;
     cellInfo.columnExtent = cellInfo.current.columnExtent;
     cellInfo.columnIndex = cellInfo.current.columnIndex;
     cellInfo.rowIndex = cellInfo.current.rowIndex;
 
     cellInfo.columnHeaders = [];
     if (cellInfo.columnChanged && cellInfo.current.role !==
-      ROLE_COLUMNHEADER) {
+      Roles.COLUMNHEADER) {
       cellInfo.columnHeaders = [headers for (headers of getHeaders(
         cellInfo.current.columnHeaderCells))];
     }
     cellInfo.rowHeaders = [];
-    if (cellInfo.rowChanged && cellInfo.current.role === ROLE_CELL) {
+    if (cellInfo.rowChanged && cellInfo.current.role === Roles.CELL) {
       cellInfo.rowHeaders = [headers for (headers of getHeaders(
         cellInfo.current.rowHeaderCells))];
     }
 
     this._cells.set(domNode, cellInfo);
     return cellInfo;
   },
 
--- a/accessible/src/jsat/content-script.js
+++ b/accessible/src/jsat/content-script.js
@@ -1,18 +1,15 @@
 /* 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/. */
 
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 
-const ROLE_ENTRY = Ci.nsIAccessibleRole.ROLE_ENTRY;
-const ROLE_INTERNAL_FRAME = Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME;
-
 const MOVEMENT_GRANULARITY_CHARACTER = 1;
 const MOVEMENT_GRANULARITY_WORD = 2;
 const MOVEMENT_GRANULARITY_PARAGRAPH = 8;
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Presentation',
@@ -20,16 +17,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, 'TraversalRules',
   'resource://gre/modules/accessibility/TraversalRules.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'EventManager',
   'resource://gre/modules/accessibility/EventManager.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'ObjectWrapper',
   'resource://gre/modules/ObjectWrapper.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Roles',
+  'resource://gre/modules/accessibility/Constants.jsm');
 
 Logger.debug('content-script.js');
 
 let eventManager = null;
 
 function moveCursor(aMessage) {
   if (Logger.logLevel >= Logger.DEBUG) {
     Logger.debug(aMessage.name, JSON.stringify(aMessage.json, null, ' '));
@@ -132,17 +131,17 @@ function forwardToParent(aMessage) {
   let newJSON = JSON.parse(JSON.stringify(aMessage.json));
   newJSON.origin = 'child';
   sendAsyncMessage(aMessage.name, newJSON);
 }
 
 function forwardToChild(aMessage, aListener, aVCPosition) {
   let acc = aVCPosition || Utils.getVirtualCursor(content.document).position;
 
-  if (!Utils.isAliveAndVisible(acc) || acc.role != ROLE_INTERNAL_FRAME) {
+  if (!Utils.isAliveAndVisible(acc) || acc.role != Roles.INTERNAL_FRAME) {
     return false;
   }
 
   if (Logger.logLevel >= Logger.DEBUG) {
     Logger.debug('forwardToChild', Logger.accessibleToString(acc),
                  aMessage.name, JSON.stringify(aMessage.json, null, '  '));
   }
 
@@ -160,17 +159,17 @@ function forwardToChild(aMessage, aListe
   mm.sendAsyncMessage(aMessage.name, newJSON);
   return true;
 }
 
 function activateCurrent(aMessage) {
   Logger.debug('activateCurrent');
   function activateAccessible(aAccessible) {
     if (aMessage.json.activateIfKey &&
-        aAccessible.role != Ci.nsIAccessibleRole.ROLE_KEY) {
+        aAccessible.role != Roles.KEY) {
       // Only activate keys, don't do anything on other objects.
       return;
     }
 
     if (aAccessible.actionCount > 0) {
       aAccessible.doAction(0);
     } else {
       let control = Utils.getEmbeddedControl(aAccessible);
@@ -214,17 +213,17 @@ function activateCurrent(aMessage) {
     if (aOffset >= 0 && aOffset <= accText.characterCount) {
       accText.caretOffset = aOffset;
     }
 
     presentCaretChange(text, oldOffset, accText.caretOffset);
   }
 
   let focusedAcc = Utils.AccRetrieval.getAccessibleFor(content.document.activeElement);
-  if (focusedAcc && focusedAcc.role === ROLE_ENTRY) {
+  if (focusedAcc && focusedAcc.role === Roles.ENTRY) {
     moveCaretTo(focusedAcc, aMessage.json.offset);
     return;
   }
 
   let position = Utils.getVirtualCursor(content.document).position;
   if (!forwardToChild(aMessage, activateCurrent, position)) {
     activateAccessible(position);
   }
--- a/accessible/src/jsat/moz.build
+++ b/accessible/src/jsat/moz.build
@@ -1,5 +1,18 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JS_MODULES_PATH = 'modules/accessibility'
+
+EXTRA_JS_MODULES += [
+    'AccessFu.jsm',
+    'Constants.jsm',
+    'EventManager.jsm',
+    'OutputGenerator.jsm',
+    'Presentation.jsm',
+    'TouchAdapter.jsm',
+    'TraversalRules.jsm',
+    'Utils.jsm'
+]
--- a/accessible/src/windows/ia2/ia2AccessibleValue.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleValue.cpp
@@ -8,16 +8,18 @@
 #include "ia2AccessibleValue.h"
 
 #include "AccessibleValue_i.c"
 
 #include "AccessibleWrap.h"
 #include "Accessible-inl.h"
 #include "IUnknownImpl.h"
 
+#include "mozilla/FloatingPoint.h"
+
 using namespace mozilla::a11y;
 
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleValue::QueryInterface(REFIID iid, void** ppv)
 {
   if (!ppv)
@@ -50,20 +52,19 @@ ia2AccessibleValue::get_currentValue(VAR
     return E_INVALIDARG;
 
   VariantInit(aCurrentValue);
 
   AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
   if (valueAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
-  double currentValue = 0;
-  nsresult rv = valueAcc->GetCurrentValue(&currentValue);
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
+  double currentValue = valueAcc->CurValue();
+  if (IsNaN(currentValue))
+    return S_FALSE;
 
   aCurrentValue->vt = VT_R8;
   aCurrentValue->dblVal = currentValue;
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
@@ -74,18 +75,17 @@ ia2AccessibleValue::setCurrentValue(VARI
 
   AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
   if (valueAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   if (aValue.vt != VT_R8)
     return E_INVALIDARG;
 
-  nsresult rv = valueAcc->SetCurrentValue(aValue.dblVal);
-  return GetHRESULT(rv);
+  return valueAcc->SetCurValue(aValue.dblVal) ? S_OK : E_FAIL;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 ia2AccessibleValue::get_maximumValue(VARIANT* aMaximumValue)
 {
   A11Y_TRYBLOCK_BEGIN
@@ -94,20 +94,19 @@ ia2AccessibleValue::get_maximumValue(VAR
     return E_INVALIDARG;
 
   VariantInit(aMaximumValue);
 
   AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
   if (valueAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
-  double maximumValue = 0;
-  nsresult rv = valueAcc->GetMaximumValue(&maximumValue);
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
+  double maximumValue = valueAcc->MaxValue();
+  if (IsNaN(maximumValue))
+    return S_FALSE;
 
   aMaximumValue->vt = VT_R8;
   aMaximumValue->dblVal = maximumValue;
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
@@ -120,20 +119,19 @@ ia2AccessibleValue::get_minimumValue(VAR
     return E_INVALIDARG;
 
   VariantInit(aMinimumValue);
 
   AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
   if (valueAcc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
-  double minimumValue = 0;
-  nsresult rv = valueAcc->GetMinimumValue(&minimumValue);
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
+  double minimumValue = valueAcc->MinValue();
+  if (IsNaN(minimumValue))
+    return S_FALSE;
 
   aMinimumValue->vt = VT_R8;
   aMinimumValue->dblVal = minimumValue;
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
--- a/accessible/src/xpcom/moz.build
+++ b/accessible/src/xpcom/moz.build
@@ -2,24 +2,26 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXPORTS += [
     'xpcAccessibleHyperText.h',
     'xpcAccessibleSelectable.h',
+    'xpcAccessibleValue.h',
 ]
 
 UNIFIED_SOURCES += [
     'nsAccessibleRelation.cpp',
     'xpcAccessibleHyperText.cpp',
     'xpcAccessibleSelectable.cpp',
     'xpcAccessibleTable.cpp',
     'xpcAccessibleTableCell.cpp',
+    'xpcAccessibleValue.cpp',
 ]
 
 GENERATED_SOURCES += [
     'xpcAccEvents.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '../base',
new file mode 100644
--- /dev/null
+++ b/accessible/src/xpcom/xpcAccessibleValue.cpp
@@ -0,0 +1,90 @@
+/* -*- 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 "xpcAccessibleValue.h"
+#include "Accessible.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+NS_IMETHODIMP
+xpcAccessibleValue::GetMaximumValue(double* aValue)
+{
+  NS_ENSURE_ARG_POINTER(aValue);
+  *aValue = 0;
+
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  double value = acc->MaxValue();
+  if (!IsNaN(value))
+    *aValue = value;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+xpcAccessibleValue::GetMinimumValue(double* aValue)
+{
+  NS_ENSURE_ARG_POINTER(aValue);
+  *aValue = 0;
+
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  double value = acc->MinValue();
+  if (!IsNaN(value))
+    *aValue = value;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+xpcAccessibleValue::GetCurrentValue(double* aValue)
+{
+  NS_ENSURE_ARG_POINTER(aValue);
+  *aValue = 0;
+
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  double value = acc->CurValue();
+  if (!IsNaN(value))
+    *aValue = value;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+xpcAccessibleValue::SetCurrentValue(double aValue)
+{
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  acc->SetCurValue(aValue);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+xpcAccessibleValue::GetMinimumIncrement(double* aValue)
+{
+  NS_ENSURE_ARG_POINTER(aValue);
+  *aValue = 0;
+
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  double value = acc->Step();
+  if (!IsNaN(value))
+    *aValue = value;
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/xpcom/xpcAccessibleValue.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_xpcAccessibleValue_h_
+#define mozilla_a11y_xpcAccessibleValue_h_
+
+#include "nsIAccessibleValue.h"
+
+namespace mozilla {
+namespace a11y {
+
+class xpcAccessibleValue : public nsIAccessibleValue
+{
+public:
+  NS_IMETHOD GetMaximumValue(double* aValue) MOZ_FINAL MOZ_OVERRIDE;
+  NS_IMETHOD GetMinimumValue(double* aValue) MOZ_FINAL MOZ_OVERRIDE;
+  NS_IMETHOD GetCurrentValue(double* aValue) MOZ_FINAL MOZ_OVERRIDE;
+  NS_IMETHOD SetCurrentValue(double aValue) MOZ_FINAL MOZ_OVERRIDE;
+  NS_IMETHOD GetMinimumIncrement(double* aMinIncrement) MOZ_FINAL MOZ_OVERRIDE;
+
+private:
+  xpcAccessibleValue() { }
+  friend class Accessible;
+
+  xpcAccessibleValue(const xpcAccessibleValue&) MOZ_DELETE;
+  xpcAccessibleValue& operator =(const xpcAccessibleValue&) MOZ_DELETE;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
--- a/accessible/src/xul/XULSliderAccessible.cpp
+++ b/accessible/src/xul/XULSliderAccessible.cpp
@@ -6,36 +6,31 @@
 #include "XULSliderAccessible.h"
 
 #include "nsAccessibilityService.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsIFrame.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/FloatingPoint.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULSliderAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULSliderAccessible::
   XULSliderAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
   mStateFlags |= eHasNumericValue;
 }
 
-// nsISupports
-
-NS_IMPL_ISUPPORTS_INHERITED1(XULSliderAccessible,
-                             AccessibleWrap,
-                             nsIAccessibleValue)
-
 // Accessible
 
 role
 XULSliderAccessible::NativeRole()
 {
   return roles::SLIDER;
 }
 
@@ -94,74 +89,49 @@ XULSliderAccessible::DoAction(uint8_t aI
 
   nsIContent* sliderElm = GetSliderElement();
   if (sliderElm)
     DoCommand(sliderElm);
 
   return NS_OK;
 }
 
-// nsIAccessibleValue
-
-NS_IMETHODIMP
-XULSliderAccessible::GetMaximumValue(double* aValue)
+double
+XULSliderAccessible::MaxValue() const
 {
-  nsresult rv = AccessibleWrap::GetMaximumValue(aValue);
-
-  // ARIA redefined maximum value.
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
-
-  return GetSliderAttr(nsGkAtoms::maxpos, aValue);
+  double value = AccessibleWrap::MaxValue();
+  return IsNaN(value) ? GetSliderAttr(nsGkAtoms::maxpos) : value;
 }
 
-NS_IMETHODIMP
-XULSliderAccessible::GetMinimumValue(double* aValue)
+double
+XULSliderAccessible::MinValue() const
 {
-  nsresult rv = AccessibleWrap::GetMinimumValue(aValue);
-
-  // ARIA redefined minmum value.
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
-
-  return GetSliderAttr(nsGkAtoms::minpos, aValue);
+  double value = AccessibleWrap::MinValue();
+  return IsNaN(value) ? GetSliderAttr(nsGkAtoms::minpos) : value;
 }
 
-NS_IMETHODIMP
-XULSliderAccessible::GetMinimumIncrement(double* aValue)
+double
+XULSliderAccessible::Step() const
 {
-  nsresult rv = AccessibleWrap::GetMinimumIncrement(aValue);
-
-  // ARIA redefined minimum increment value.
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
-
-  return GetSliderAttr(nsGkAtoms::increment, aValue);
+  double value = AccessibleWrap::Step();
+  return IsNaN(value) ? GetSliderAttr(nsGkAtoms::increment) : value;
 }
 
-NS_IMETHODIMP
-XULSliderAccessible::GetCurrentValue(double* aValue)
+double
+XULSliderAccessible::CurValue() const
 {
-  nsresult rv = AccessibleWrap::GetCurrentValue(aValue);
-
-  // ARIA redefined current value.
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
-
-  return GetSliderAttr(nsGkAtoms::curpos, aValue);
+  double value = AccessibleWrap::CurValue();
+  return IsNaN(value) ? GetSliderAttr(nsGkAtoms::curpos) : value;
 }
 
-NS_IMETHODIMP
-XULSliderAccessible::SetCurrentValue(double aValue)
+bool
+XULSliderAccessible::SetCurValue(double aValue)
 {
-  nsresult rv = AccessibleWrap::SetCurrentValue(aValue);
-
-  // ARIA redefined current value.
-  if (rv != NS_OK_NO_ARIA_VALUE)
-    return rv;
+  if (AccessibleWrap::SetCurValue(aValue))
+    return true;
 
   return SetSliderAttr(nsGkAtoms::curpos, aValue);
 }
 
 bool
 XULSliderAccessible::CanHaveAnonChildren()
 {
   // Do not allow anonymous xul:slider be accessible.
@@ -179,17 +149,17 @@ XULSliderAccessible::GetSliderElement() 
       GetAnonymousElementByAttribute(mContent, nsGkAtoms::anonid,
                                      NS_LITERAL_STRING("slider"));
   }
 
   return mSliderNode;
 }
 
 nsresult
-XULSliderAccessible::GetSliderAttr(nsIAtom* aName, nsAString& aValue)
+XULSliderAccessible::GetSliderAttr(nsIAtom* aName, nsAString& aValue) const
 {
   aValue.Truncate();
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   nsIContent* sliderElm = GetSliderElement();
   if (sliderElm)
@@ -206,45 +176,36 @@ XULSliderAccessible::SetSliderAttr(nsIAt
 
   nsIContent* sliderElm = GetSliderElement();
   if (sliderElm)
     sliderElm->SetAttr(kNameSpaceID_None, aName, aValue, true);
 
   return NS_OK;
 }
 
-nsresult
-XULSliderAccessible::GetSliderAttr(nsIAtom* aName, double* aValue)
+double
+XULSliderAccessible::GetSliderAttr(nsIAtom* aName) const
 {
-  NS_ENSURE_ARG_POINTER(aValue);
-  *aValue = 0;
-
   nsAutoString attrValue;
   nsresult rv = GetSliderAttr(aName, attrValue);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Return zero value if there is no attribute or its value is empty.
-  if (attrValue.IsEmpty())
-    return NS_OK;
+  if (NS_FAILED(rv))
+    return UnspecifiedNaN();
 
   nsresult error = NS_OK;
   double value = attrValue.ToDouble(&error);
-  if (NS_SUCCEEDED(error))
-    *aValue = value;
-
-  return NS_OK;
+  return NS_FAILED(error) ? UnspecifiedNaN() : value;
 }
 
-nsresult
+bool
 XULSliderAccessible::SetSliderAttr(nsIAtom* aName, double aValue)
 {
   nsAutoString value;
   value.AppendFloat(aValue);
 
-  return SetSliderAttr(aName, value);
+  return NS_SUCCEEDED(SetSliderAttr(aName, value));
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULThumbAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULThumbAccessible::
--- a/accessible/src/xul/XULSliderAccessible.h
+++ b/accessible/src/xul/XULSliderAccessible.h
@@ -16,47 +16,48 @@ namespace a11y {
 /**
  * Used for XUL slider and scale elements.
  */
 class XULSliderAccessible : public AccessibleWrap
 {
 public:
   XULSliderAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
-  // nsISupports
-  NS_DECL_ISUPPORTS_INHERITED
-
   // nsIAccessible
   NS_IMETHOD GetActionName(uint8_t aIndex, nsAString& aName);
   NS_IMETHOD DoAction(uint8_t aIndex);
 
-  // nsIAccessibleValue
-  NS_DECL_NSIACCESSIBLEVALUE
-
   // Accessible
   virtual void Value(nsString& aValue);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeInteractiveState() const;
   virtual bool NativelyUnavailable() const;
   virtual bool CanHaveAnonChildren();
 
+  // Value
+  virtual double MaxValue() const MOZ_OVERRIDE;
+  virtual double MinValue() const MOZ_OVERRIDE;
+  virtual double CurValue() const MOZ_OVERRIDE;
+  virtual double Step() const MOZ_OVERRIDE;
+  virtual bool SetCurValue(double aValue) MOZ_OVERRIDE;
+
   // ActionAccessible
   virtual uint8_t ActionCount();
 
 protected:
   /**
    * Return anonymous slider element.
    */
   nsIContent* GetSliderElement() const;
 
-  nsresult GetSliderAttr(nsIAtom *aName, nsAString& aValue);
+  nsresult GetSliderAttr(nsIAtom *aName, nsAString& aValue) const;
   nsresult SetSliderAttr(nsIAtom *aName, const nsAString& aValue);
 
-  nsresult GetSliderAttr(nsIAtom *aName, double *aValue);
-  nsresult SetSliderAttr(nsIAtom *aName, double aValue);
+  double GetSliderAttr(nsIAtom *aName) const;
+  bool SetSliderAttr(nsIAtom *aName, double aValue);
 
 private:
   mutable nsCOMPtr<nsIContent> mSliderNode;
 };
 
 
 /**
  * Used for slider's thumb element.
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -87,16 +87,17 @@ var AccessFuTest = {
 
   waitForExplicitFinish: function AccessFuTest_waitForExplicitFinish() {
     this._waitForExplicitFinish = true;
   },
 
   finish: function AccessFuTest_finish() {
     // Disable the console service logging.
     Logger.test = false;
+    Logger.logLevel = Logger.INFO;
     AccessFu.doneCallback = function doneCallback() {
       // This is being called once AccessFu has been shut down.
       // Detach AccessFu from everything it attached itself to.
       AccessFu.detach();
       // and finish the test run.
       SimpleTest.finish();
     };
     // Tear down accessibility and make AccessFu stop.
@@ -131,16 +132,17 @@ var AccessFuTest = {
     // Start AccessFu and put it in stand-by.
     Components.utils.import("resource://gre/modules/accessibility/AccessFu.jsm");
 
     AccessFu.attach(getMainChromeWindow(window));
 
     AccessFu.readyCallback = function readyCallback() {
       // Enable logging to the console service.
       Logger.test = true;
+      Logger.logLevel = Logger.DEBUG;
       // This is being called once accessibility has been turned on.
 
       if (AccessFuTest._waitForExplicitFinish) {
         // Run all test functions asynchronously.
         AccessFuTest.nextTest();
       } else {
         // Run all test functions synchronously.
         [testFunc() for (testFunc of gTestFuncs)];
--- a/accessible/tests/mochitest/value/test_progress.html
+++ b/accessible/tests/mochitest/value/test_progress.html
@@ -16,17 +16,17 @@
 
   <script type="application/javascript"
           src="chrome://mochikit/content/chrome-harness.js"></script>
 
   <script type="application/javascript">
     function doTest()
     {
       // HTML5 progress element tests
-      testValue("pr_indeterminate", "0%", 0, 0, 1, 0);
+      testValue("pr_indeterminate", "", 0, 0, 1, 0);
       testValue("pr_zero", "0%", 0, 0, 1, 0);
       testValue("pr_zeropointfive", "50%", 0.5, 0, 1, 0);
       testValue("pr_one", "100%", 1, 0, 1, 0);
       testValue("pr_42", "100%", 42, 0, 1, 0);
       testValue("pr_21", "50%", 21, 0, 42, 0);
 
       SimpleTest.finish();
     }
--- a/accessible/tests/mochitest/value/test_progress.xul
+++ b/accessible/tests/mochitest/value/test_progress.xul
@@ -16,17 +16,17 @@
 
   <script type="application/javascript">
   <![CDATA[
     function doTest()
     {
       // progressmeter
       testValue("pm1", "50%", 50, 0, 100, 0);
       testValue("pm2", "50%", 500, 0, 1000, 0);
-      testValue("pm3", "0%", 0, 0, 100, 0);
+      testValue("pm3", "", 0, 0, 100, 0);
 
       // scale
       testValue("sc1", "500", 500, 0, 1000, 10);
       testValue("sc2", "", 0, 0, 0, 0);
 
       // aria progressbar
       testValue("ariapb1", "500", 500, 0, 1000, 0);
       testValue("ariapb2", "", 0, 0, 0, 0);
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -466,17 +466,17 @@ class Automation(object):
       if ext == ".client":
         self.Process([pk12util, "-i", os.path.join(certPath, item), "-w",
                     pwfilePath, "-d", profileDir], 
                     env = env).wait()
 
     os.unlink(pwfilePath)
     return 0
 
-  def environment(self, env = None, xrePath = None, crashreporter = True):
+  def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False):
     if xrePath == None:
       xrePath = self.DIST_BIN
     if env == None:
       env = dict(os.environ)
 
     ldLibraryPath = os.path.abspath(os.path.join(SCRIPT_DIR, xrePath))
     if self.UNIXISH or self.IS_MAC:
       envVar = "LD_LIBRARY_PATH"
@@ -485,17 +485,17 @@ class Automation(object):
       else: # unixish
         env['MOZILLA_FIVE_HOME'] = xrePath
       if envVar in env:
         ldLibraryPath = ldLibraryPath + ":" + env[envVar]
       env[envVar] = ldLibraryPath
     elif self.IS_WIN32:
       env["PATH"] = env["PATH"] + ";" + str(ldLibraryPath)
 
-    if crashreporter:
+    if crashreporter and not debugger:
       env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
       env['MOZ_CRASHREPORTER'] = '1'
     else:
       env['MOZ_CRASHREPORTER_DISABLE'] = '1'
 
     env['GNOME_DISABLE_CRASH_DIALOG'] = '1'
     env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
     env['NS_TRACE_MALLOC_DISABLE_STACKS'] = '1'
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -397,17 +397,17 @@ def parseKeyValue(strings, separator='='
 
 def systemMemory():
   """
   Returns total system memory in kilobytes.
   Works only on unix-like platforms where `free` is in the path.
   """
   return int(os.popen("free").readlines()[1].split()[1])
 
-def environment(xrePath, env=None, crashreporter=True):
+def environment(xrePath, env=None, crashreporter=True, debugger=False):
   """populate OS environment variables for mochitest"""
 
   env = os.environ.copy() if env is None else env
 
   assert os.path.isabs(xrePath)
 
   ldLibraryPath = xrePath
 
@@ -425,17 +425,17 @@ def environment(xrePath, env=None, crash
                 else (ldLibraryPath, env.get(envVar)))
     env[envVar] = os.path.pathsep.join([path for path in envValue if path])
 
   # crashreporter
   env['GNOME_DISABLE_CRASH_DIALOG'] = '1'
   env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
   env['NS_TRACE_MALLOC_DISABLE_STACKS'] = '1'
 
-  if crashreporter:
+  if crashreporter and not debugger:
     env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
     env['MOZ_CRASHREPORTER'] = '1'
   else:
     env['MOZ_CRASHREPORTER_DISABLE'] = '1'
 
   # Additional temporary logging while we try to debug some intermittent
   # WebRTC conditions. This is necessary to troubleshoot bugs 841496,
   # 841150, and 839677 (at least)
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -30,16 +30,18 @@ SEARCH_PATHS = [
     'python/mozbuild',
     'python/mozversioncontrol',
     'python/blessings',
     'python/configobj',
     'python/psutil',
     'python/which',
     'build/pymake',
     'config',
+    'dom/bindings',
+    'dom/bindings/parser',
     'other-licenses/ply',
     'xpcom/idl-parser',
     'testing',
     'testing/xpcshell',
     'testing/marionette/client',
     'testing/marionette/client/marionette',
     'testing/mozbase/mozcrash',
     'testing/mozbase/mozdevice',
@@ -55,16 +57,17 @@ SEARCH_PATHS = [
     'testing/mozbase/moztest',
     'testing/mozbase/manifestdestiny',
     'xpcom/idl-parser',
 ]
 
 # Individual files providing mach commands.
 MACH_MODULES = [
     'addon-sdk/mach_commands.py',
+    'dom/bindings/mach_commands.py',
     'layout/tools/reftest/mach_commands.py',
     'python/mach_commands.py',
     'python/mach/mach/commands/commandinfo.py',
     'python/mozboot/mozboot/mach_commands.py',
     'python/mozbuild/mozbuild/config.py',
     'python/mozbuild/mozbuild/mach_commands.py',
     'python/mozbuild/mozbuild/frontend/mach_commands.py',
     'testing/mach_commands.py',
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -43,29 +43,29 @@ class RemoteAutomation(Automation):
 
     def setProduct(self, product):
         self._product = product
 
     def setRemoteLog(self, logfile):
         self._remoteLog = logfile
 
     # Set up what we need for the remote environment
-    def environment(self, env = None, xrePath = None, crashreporter = True):
+    def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False):
         # Because we are running remote, we don't want to mimic the local env
         # so no copying of os.environ
         if env is None:
             env = {}
 
         # Except for the mochitest results table hiding option, which isn't
         # passed to runtestsremote.py as an actual option, but through the
-        # MOZ_CRASHREPORTER_DISABLE environment variable.
+        # MOZ_HIDE_RESULTS_TABLE environment variable.
         if 'MOZ_HIDE_RESULTS_TABLE' in os.environ:
             env['MOZ_HIDE_RESULTS_TABLE'] = os.environ['MOZ_HIDE_RESULTS_TABLE']
 
-        if crashreporter:
+        if crashreporter and not debugger:
             env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
             env['MOZ_CRASHREPORTER'] = '1'
         else:
             env['MOZ_CRASHREPORTER_DISABLE'] = '1'
 
         return env
 
     def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath):
--- a/build/mobile/robocop/moz.build
+++ b/build/mobile/robocop/moz.build
@@ -1,9 +1,5 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ANDROID_RESFILES = [
-    'res/values/strings.xml',
-]
--- a/build/mobile/sutagent/android/fencp/moz.build
+++ b/build/mobile/sutagent/android/fencp/moz.build
@@ -1,13 +1,5 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ANDROID_RESFILES = [
-    'res/drawable-hdpi/icon.png',
-    'res/drawable-ldpi/icon.png',
-    'res/drawable-mdpi/icon.png',
-    'res/layout/main.xml',
-    'res/values/strings.xml',
-]
--- a/build/mobile/sutagent/android/ffxcp/moz.build
+++ b/build/mobile/sutagent/android/ffxcp/moz.build
@@ -1,13 +1,5 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ANDROID_RESFILES = [
-    'res/drawable-hdpi/icon.png',
-    'res/drawable-ldpi/icon.png',
-    'res/drawable-mdpi/icon.png',
-    'res/layout/main.xml',
-    'res/values/strings.xml',
-]
--- a/build/mobile/sutagent/android/moz.build
+++ b/build/mobile/sutagent/android/moz.build
@@ -1,15 +1,5 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ANDROID_RESFILES = [
-    'res/drawable/ateamlogo.png',
-    'res/drawable/ic_stat_first.png',
-    'res/drawable/ic_stat_neterror.png',
-    'res/drawable/ic_stat_warning.png',
-    'res/drawable/icon.png',
-    'res/layout/main.xml',
-    'res/values/strings.xml',
-]
--- a/build/mobile/sutagent/android/watcher/moz.build
+++ b/build/mobile/sutagent/android/watcher/moz.build
@@ -1,16 +1,5 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ANDROID_RESFILES = [
-    'res/drawable-hdpi/ateamlogo.png',
-    'res/drawable-hdpi/icon.png',
-    'res/drawable-ldpi/ateamlogo.png',
-    'res/drawable-ldpi/icon.png',
-    'res/drawable-mdpi/ateamlogo.png',
-    'res/drawable-mdpi/icon.png',
-    'res/layout/main.xml',
-    'res/values/strings.xml',
-]
--- a/config/config.mk
+++ b/config/config.mk
@@ -30,17 +30,17 @@ endif
 -include $(DEPTH)/.mozconfig.mk
 
 # Integrate with mozbuild-generated make files. We first verify that no
 # variables provided by the automatically generated .mk files are
 # present. If they are, this is a violation of the separation of
 # responsibility between Makefile.in and mozbuild files.
 _MOZBUILD_EXTERNAL_VARIABLES := \
   ANDROID_GENERATED_RESFILES \
-  ANDROID_RESFILES \
+  ANDROID_RES_DIRS \
   CMSRCS \
   CMMSRCS \
   CPP_UNIT_TESTS \
   DIRS \
   EXTRA_PP_COMPONENTS \
   EXTRA_PP_JS_MODULES \
   FORCE_SHARED_LIB \
   FORCE_STATIC_LIB \
@@ -68,16 +68,17 @@ endif
   TEST_DIRS \
   TIERS \
   TOOL_DIRS \
   XPCSHELL_TESTS \
   XPIDL_MODULE \
   $(NULL)
 
 _DEPRECATED_VARIABLES := \
+  ANDROID_RESFILES \
   MOCHITEST_FILES_PARTS \
   MOCHITEST_BROWSER_FILES_PARTS \
   SHORT_LIBNAME \
   $(NULL)
 
 ifndef EXTERNALLY_MANAGED_MAKE_FILE
 # Using $(firstword) may not be perfect. But it should be good enough for most
 # scenarios.
@@ -472,19 +473,19 @@ JAVA_GEN_DIR  = _javagen
 JAVA_DIST_DIR = $(DEPTH)/$(JAVA_GEN_DIR)
 JAVA_IFACES_PKG_NAME = org/mozilla/interfaces
 
 OS_INCLUDES += $(MOZ_JPEG_CFLAGS) $(MOZ_PNG_CFLAGS) $(MOZ_ZLIB_CFLAGS)
 
 # NSPR_CFLAGS and NSS_CFLAGS must appear ahead of OS_INCLUDES to avoid Linux
 # builds wrongly picking up system NSPR/NSS header files.
 INCLUDES = \
-  $(LOCAL_INCLUDES) \
   -I$(srcdir) \
   -I. \
+  $(LOCAL_INCLUDES) \
   -I$(DIST)/include \
   $(if $(LIBXUL_SDK),-I$(LIBXUL_SDK)/include) \
   $(NSPR_CFLAGS) $(NSS_CFLAGS) \
   $(OS_INCLUDES) \
   $(NULL)
 
 include $(topsrcdir)/config/static-checking-config.mk
 
--- a/config/makefiles/java-build.mk
+++ b/config/makefiles/java-build.mk
@@ -2,49 +2,27 @@
 # vim:set ts=8 sw=8 sts=8 noet:
 #
 # 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 INCLUDED_JAVA_BUILD_MK #{
 
-ifdef ANDROID_RESFILES #{
-ifndef IGNORE_ANDROID_RESFILES #{
-res-dep := .deps-copy-java-res
-
-GENERATED_DIRS += res
-GARBAGE        += $(res-dep)
-
-export:: $(res-dep)
-
-res-dep-preqs := \
-  $(addprefix $(srcdir)/,$(ANDROID_RESFILES)) \
-  $(call mkdir_deps,res) \
-  $(if $(IS_LANGUAGE_REPACK),FORCE) \
-  $(NULL)
-
-# nop-build: only copy res/ files when needed
-$(res-dep): $(res-dep-preqs)
-	$(call copy_dir,$(srcdir)/res,$(CURDIR)/res)
-	@$(TOUCH) $@
-endif #} IGNORE_ANDROID_RESFILES
-endif #} ANDROID_RESFILES
-
-
 ifdef JAVAFILES #{
 GENERATED_DIRS += classes
 
 export:: classes
 classes: $(call mkdir_deps,classes)
 endif #} JAVAFILES
 
 
 ifdef ANDROID_APK_NAME #{
-_ANDROID_RES_FLAG := -S $(or $(ANDROID_RES_DIR),res)
+android_res_dirs := $(addprefix $(srcdir)/,$(or $(ANDROID_RES_DIRS),res))
+_ANDROID_RES_FLAG := $(addprefix -S ,$(android_res_dirs))
 _ANDROID_ASSETS_FLAG := $(addprefix -A ,$(ANDROID_ASSETS_DIR))
 
 GENERATED_DIRS += classes
 
 classes.dex: $(call mkdir_deps,classes)
 classes.dex: R.java
 classes.dex: $(ANDROID_APK_NAME).ap_
 classes.dex: $(JAVAFILES)
@@ -52,17 +30,21 @@ classes.dex: $(JAVAFILES)
 	$(DX) --dex --output=$@ classes $(ANDROID_EXTRA_JARS)
 
 # R.java and $(ANDROID_APK_NAME).ap_ are both produced by aapt.  To
 # save an aapt invocation, we produce them both at the same time.
 
 R.java: .aapt.deps
 $(ANDROID_APK_NAME).ap_: .aapt.deps
 
-.aapt.deps: AndroidManifest.xml $(wildcard $(ANDROID_RES_DIR)) $(wildcard $(ANDROID_ASSETS_DIR))
+# This uses the fact that Android resource directories list all
+# resource files one subdirectory below the parent resource directory.
+android_res_files := $(wildcard $(addsuffix /*,$(wildcard $(addsuffix /*,$(android_res_dirs)))))
+
+.aapt.deps: AndroidManifest.xml $(android_res_files) $(wildcard $(ANDROID_ASSETS_DIR))
 	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar $(_ANDROID_RES_FLAG) $(_ANDROID_ASSETS_FLAG) \
 		-J ${@D} \
 		-F $(ANDROID_APK_NAME).ap_
 	@$(TOUCH) $@
 
 $(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
 	cp $< $@
 	$(ZIP) -0 $@ classes.dex
--- a/config/mozunit.py
+++ b/config/mozunit.py
@@ -124,16 +124,29 @@ class MockedOpen(object):
             file = self.open(name, mode)
         if 'a' in mode:
             file.seek(0, os.SEEK_END)
         return file
 
     def __enter__(self):
         import __builtin__
         self.open = __builtin__.open
+        self._orig_path_exists = os.path.exists
         __builtin__.open = self
+        os.path.exists = self._wrapped_exists
 
     def __exit__(self, type, value, traceback):
         import __builtin__
         __builtin__.open = self.open
+        os.path.exists = self._orig_path_exists
+
+    def _wrapped_exists(self, p):
+        if p in self.files:
+            return True
+
+        abspath = os.path.abspath(p)
+        if abspath in self.files:
+            return True
+
+        return self._orig_path_exists(p)
 
 def main(*args):
     unittest.main(testRunner=MozTestRunner(),*args)
--- a/config/tests/unit-mozunit.py
+++ b/config/tests/unit-mozunit.py
@@ -10,46 +10,58 @@ from tempfile import mkstemp
 
 class TestMozUnit(unittest.TestCase):
     def test_mocked_open(self):
         # Create a temporary file on the file system.
         (fd, path) = mkstemp()
         with os.fdopen(fd, 'w') as file:
             file.write('foobar');
 
+        self.assertFalse(os.path.exists('file1'))
+        self.assertFalse(os.path.exists('file2'))
+
         with MockedOpen({'file1': 'content1',
                          'file2': 'content2'}):
+            self.assertTrue(os.path.exists('file1'))
+            self.assertTrue(os.path.exists('file2'))
+            self.assertFalse(os.path.exists('foo/file1'))
+
             # Check the contents of the files given at MockedOpen creation.
             self.assertEqual(open('file1', 'r').read(), 'content1')
             self.assertEqual(open('file2', 'r').read(), 'content2')
 
             # Check that overwriting these files alters their content.
             with open('file1', 'w') as file:
                 file.write('foo')
+            self.assertTrue(os.path.exists('file1'))
             self.assertEqual(open('file1', 'r').read(), 'foo')
 
             # ... but not until the file is closed.
             file = open('file2', 'w')
             file.write('bar')
             self.assertEqual(open('file2', 'r').read(), 'content2')
             file.close()
             self.assertEqual(open('file2', 'r').read(), 'bar')
 
             # Check that appending to a file does append
             with open('file1', 'a') as file:
                 file.write('bar')
             self.assertEqual(open('file1', 'r').read(), 'foobar')
 
+            self.assertFalse(os.path.exists('file3'))
+
             # Opening a non-existing file ought to fail.
             self.assertRaises(IOError, open, 'file3', 'r')
+            self.assertFalse(os.path.exists('file3'))
 
             # Check that writing a new file does create the file.
             with open('file3', 'w') as file:
                 file.write('baz')
             self.assertEqual(open('file3', 'r').read(), 'baz')
+            self.assertTrue(os.path.exists('file3'))
 
             # Check the content of the file created outside MockedOpen.
             self.assertEqual(open(path, 'r').read(), 'foobar')
 
             # Check that overwriting a file existing on the file system
             # does modify its content.
             with open(path, 'w') as file:
                 file.write('bazqux')
--- a/content/base/src/DirectionalityUtils.cpp
+++ b/content/base/src/DirectionalityUtils.cpp
@@ -215,17 +215,17 @@
 #include "nsUnicodeProperties.h"
 #include "nsTextFragment.h"
 #include "nsAttrValue.h"
 #include "nsTextNode.h"
 #include "nsCheapSets.h"
 
 namespace mozilla {
 
-typedef mozilla::dom::Element Element;
+using mozilla::dom::Element;
 
 /**
  * Returns true if aElement is one of the elements whose text content should not
  * affect its own direction, nor the direction of ancestors with dir=auto.
  *
  * Note that this does not include <bdi>, whose content does affect its own
  * direction when it has dir=auto (which it has by default), so one needs to
  * test for it separately, e.g. with DoesNotAffectDirectionOfAncestors.
--- a/content/base/src/moz.build
+++ b/content/base/src/moz.build
@@ -62,17 +62,17 @@ EXPORTS.mozilla.dom += [
     'DOMRect.h',
     'EventSource.h',
     'Link.h',
     'NodeIterator.h',
     'Text.h',
     'TreeWalker.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'Attr.cpp',
     'ChildIterator.cpp',
     'Comment.cpp',
     'DirectionalityUtils.cpp',
     'DocumentFragment.cpp',
     'DocumentType.cpp',
     'DOMImplementation.cpp',
     'DOMParser.cpp',
@@ -89,22 +89,20 @@ SOURCES += [
     'nsAttrValueOrString.cpp',
     'nsCCUncollectableMarker.cpp',
     'nsChannelPolicy.cpp',
     'nsContentAreaDragDrop.cpp',
     'nsContentIterator.cpp',
     'nsContentList.cpp',
     'nsContentPolicy.cpp',
     'nsContentSink.cpp',
-    'nsContentUtils.cpp',
     'nsCopySupport.cpp',
     'nsCrossSiteListenerProxy.cpp',
     'nsCSPService.cpp',
     'nsDataDocumentContentPolicy.cpp',
-    'nsDocument.cpp',
     'nsDocumentEncoder.cpp',
     'nsDOMAttributeMap.cpp',
     'nsDOMBlobBuilder.cpp',
     'nsDOMCaretPosition.cpp',
     'nsDOMFile.cpp',
     'nsDOMFileReader.cpp',
     'nsDOMLists.cpp',
     'nsDOMMutationObserver.cpp',
@@ -125,19 +123,17 @@ SOURCES += [
     'nsInProcessTabChildGlobal.cpp',
     'nsLineBreaker.cpp',
     'nsMappedAttributeElement.cpp',
     'nsMappedAttributes.cpp',
     'nsMixedContentBlocker.cpp',
     'nsNameSpaceManager.cpp',
     'nsNoDataProtocolContentPolicy.cpp',
     'nsNodeInfo.cpp',
-    'nsNodeInfoManager.cpp',
     'nsNodeUtils.cpp',
-    'nsObjectLoadingContent.cpp',
     'nsPlainTextSerializer.cpp',
     'nsPropertyTable.cpp',
     'nsRange.cpp',
     'nsReferencedElement.cpp',
     'nsScriptElement.cpp',
     'nsScriptLoader.cpp',
     'nsStubDocumentObserver.cpp',
     'nsStubMutationObserver.cpp',
@@ -154,16 +150,28 @@ SOURCES += [
     'nsXMLHttpRequest.cpp',
     'nsXMLNameSpaceMap.cpp',
     'Text.cpp',
     'ThirdPartyUtil.cpp',
     'TreeWalker.cpp',
     'WebSocket.cpp',
 ]
 
+# These files cannot be built in unified mode because they use FORCE_PR_LOG
+SOURCES += [
+    'nsDocument.cpp',
+    'nsNodeInfoManager.cpp',
+]
+
+# These files cannot be built in unified mode because of OS X headers.
+SOURCES += [
+    'nsContentUtils.cpp',
+    'nsObjectLoadingContent.cpp',
+]
+
 EXTRA_COMPONENTS += [
     'contentAreaDropListener.js',
     'contentAreaDropListener.manifest',
     'contentSecurityPolicy.manifest',
     'messageWakeupService.js',
     'messageWakeupService.manifest',
 ]
 
--- a/content/base/src/nsStyledElement.cpp
+++ b/content/base/src/nsStyledElement.cpp
@@ -17,17 +17,17 @@
 #include "mozilla/css/StyleRule.h"
 #include "nsCSSParser.h"
 #include "mozilla/css/Loader.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsXULElement.h"
 #include "nsContentUtils.h"
 #include "nsStyleUtil.h"
 
-namespace css = mozilla::css;
+using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
 nsIAtom*
 nsStyledElementNotElementCSSInlineStyle::GetClassAttributeName() const
 {
--- a/content/html/content/public/HTMLVideoElement.h
+++ b/content/html/content/public/HTMLVideoElement.h
@@ -111,14 +111,18 @@ protected:
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   virtual void WakeLockCreate();
   virtual void WakeLockRelease();
   void WakeLockUpdate();
 
   nsCOMPtr<nsIDOMMozWakeLock> mScreenWakeLock;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLVideoElement_h
--- a/content/html/content/src/HTMLBRElement.cpp
+++ b/content/html/content/src/HTMLBRElement.cpp
@@ -52,19 +52,19 @@ HTMLBRElement::ParseAttribute(int32_t aN
   if (aAttribute == nsGkAtoms::clear && aNamespaceID == kNameSpaceID_None) {
     return aResult.ParseEnumValue(aValue, kClearTable, false);
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLBRElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                     nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
     nsCSSValue* clear = aData->ValueForClear();
     if (clear->GetUnit() == eCSSUnit_Null) {
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::clear);
       if (value && value->Type() == nsAttrValue::eEnum)
         clear->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
     }
--- a/content/html/content/src/HTMLBRElement.h
+++ b/content/html/content/src/HTMLBRElement.h
@@ -41,15 +41,19 @@ public:
   }
   void SetClear(const nsAString& aClear, ErrorResult& aError)
   {
     return SetHTMLAttr(nsGkAtoms::clear, aClear, aError);
   }
 
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
 
--- a/content/html/content/src/HTMLBodyElement.cpp
+++ b/content/html/content/src/HTMLBodyElement.cpp
@@ -343,18 +343,19 @@ HTMLBodyElement::UnbindFromTree(bool aDe
   if (mContentStyleRule) {
     mContentStyleRule->mPart = nullptr;
     mContentStyleRule = nullptr;
   }
 
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);  
 }
 
-static 
-void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
+void
+HTMLBodyElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                       nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
     // When display if first asked for, go ahead and get our colors set up.
     nsIPresShell *presShell = aData->mPresContext->GetPresShell();
     if (presShell) {
       nsIDocument *doc = presShell->GetDocument();
       if (doc) {
         nsHTMLStyleSheet* styleSheet = doc->GetAttributeStyleSheet();
--- a/content/html/content/src/HTMLBodyElement.h
+++ b/content/html/content/src/HTMLBodyElement.h
@@ -131,14 +131,18 @@ public:
 
   virtual bool IsEventAttributeName(nsIAtom* aName) MOZ_OVERRIDE;
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   nsRefPtr<BodyRule> mContentStyleRule;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* HTMLBodyElement_h___ */
--- a/content/html/content/src/HTMLDivElement.cpp
+++ b/content/html/content/src/HTMLDivElement.cpp
@@ -57,18 +57,19 @@ HTMLDivElement::ParseAttribute(int32_t a
       return ParseDivAlignValue(aValue, aResult);
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
+void
+HTMLDivElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                      nsRuleData* aData)
 {
   nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
 static void
 MapMarqueeAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
 {
--- a/content/html/content/src/HTMLDivElement.h
+++ b/content/html/content/src/HTMLDivElement.h
@@ -55,14 +55,18 @@ public:
                               nsAttrValue& aResult) MOZ_OVERRIDE;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const MOZ_OVERRIDE;
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* HTMLDivElement_h___ */
--- a/content/html/content/src/HTMLFontElement.cpp
+++ b/content/html/content/src/HTMLFontElement.cpp
@@ -48,19 +48,19 @@ HTMLFontElement::ParseAttribute(int32_t 
       return aResult.ParseColor(aValue);
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLFontElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                       nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Font)) {
     // face: string list
     nsCSSValue* family = aData->ValueForFontFamily();
     if (family->GetUnit() == eCSSUnit_Null) {
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::face);
       if (value && value->Type() == nsAttrValue::eString &&
           !value->IsEmptyString()) {
--- a/content/html/content/src/HTMLFontElement.h
+++ b/content/html/content/src/HTMLFontElement.h
@@ -51,14 +51,18 @@ public:
                                 nsAttrValue& aResult) MOZ_OVERRIDE;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const MOZ_OVERRIDE;
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* HTMLFontElement_h___ */
--- a/content/html/content/src/HTMLFrameElement.cpp
+++ b/content/html/content/src/HTMLFrameElement.cpp
@@ -76,19 +76,19 @@ HTMLFrameElement::ParseAttribute(int32_t
       return ParseScrollingValue(aValue, aResult);
     }
   }
 
   return nsGenericHTMLFrameElement::ParseAttribute(aNamespaceID, aAttribute,
                                                    aValue, aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLFrameElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                        nsRuleData* aData)
 {
   nsGenericHTMLElement::MapScrollingAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLFrameElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
--- a/content/html/content/src/HTMLFrameElement.h
+++ b/content/html/content/src/HTMLFrameElement.h
@@ -94,14 +94,18 @@ public:
   }
 
   using nsGenericHTMLFrameElement::GetContentDocument;
   using nsGenericHTMLFrameElement::GetContentWindow;
 
 protected:
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLFrameElement_h
--- a/content/html/content/src/HTMLHRElement.cpp
+++ b/content/html/content/src/HTMLHRElement.cpp
@@ -27,29 +27,29 @@ NS_IMPL_ELEMENT_CLONE(HTMLHRElement)
 
 
 NS_IMPL_STRING_ATTR(HTMLHRElement, Align, align)
 NS_IMPL_BOOL_ATTR(HTMLHRElement, NoShade, noshade)
 NS_IMPL_STRING_ATTR(HTMLHRElement, Size, size)
 NS_IMPL_STRING_ATTR(HTMLHRElement, Width, width)
 NS_IMPL_STRING_ATTR(HTMLHRElement, Color, color)
 
-static const nsAttrValue::EnumTable kAlignTable[] = {
-  { "left", NS_STYLE_TEXT_ALIGN_LEFT },
-  { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
-  { "center", NS_STYLE_TEXT_ALIGN_CENTER },
-  { 0 }
-};
-
 bool
 HTMLHRElement::ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult)
 {
+  static const nsAttrValue::EnumTable kAlignTable[] = {
+    { "left", NS_STYLE_TEXT_ALIGN_LEFT },
+    { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
+    { "center", NS_STYLE_TEXT_ALIGN_CENTER },
+    { 0 }
+  };
+
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::width) {
       return aResult.ParseSpecialIntValue(aValue);
     }
     if (aAttribute == nsGkAtoms::size) {
       return aResult.ParseIntWithBounds(aValue, 1, 1000);
     }
     if (aAttribute == nsGkAtoms::align) {
@@ -59,19 +59,19 @@ HTMLHRElement::ParseAttribute(int32_t aN
       return aResult.ParseColor(aValue);
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLHRElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                     nsRuleData* aData)
 {
   bool noshade = false;
 
   const nsAttrValue* colorValue = aAttributes->GetAttr(nsGkAtoms::color);
   nscolor color;
   bool colorIsSet = colorValue && colorValue->GetColorValue(color);
 
   if (aData->mSIDs & (NS_STYLE_INHERIT_BIT(Position) |
--- a/content/html/content/src/HTMLHRElement.h
+++ b/content/html/content/src/HTMLHRElement.h
@@ -68,14 +68,18 @@ public:
   void SetWidth(const nsAString& aWidth, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::width, aWidth, aError);
   }
 
 protected:
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLHRElement_h
--- a/content/html/content/src/HTMLHeadingElement.cpp
+++ b/content/html/content/src/HTMLHeadingElement.cpp
@@ -45,18 +45,19 @@ HTMLHeadingElement::ParseAttribute(int32
   if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
     return ParseDivAlignValue(aValue, aResult);
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
+void
+HTMLHeadingElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                          nsRuleData* aData)
 {
   nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLHeadingElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
--- a/content/html/content/src/HTMLHeadingElement.h
+++ b/content/html/content/src/HTMLHeadingElement.h
@@ -38,14 +38,18 @@ public:
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // The XPCOM versions of GetAlign and SetAlign are fine for us for
   // use from WebIDL.
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace mozilla
 } // namespace dom
 
 #endif // mozilla_dom_HTMLHeadingElement_h
--- a/content/html/content/src/HTMLIFrameElement.cpp
+++ b/content/html/content/src/HTMLIFrameElement.cpp
@@ -101,19 +101,19 @@ HTMLIFrameElement::ParseAttribute(int32_
       return ParseAlignValue(aValue, aResult);
     }
   }
 
   return nsGenericHTMLFrameElement::ParseAttribute(aNamespaceID, aAttribute,
                                                    aValue, aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLIFrameElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                         nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Border)) {
     // frameborder: 0 | 1 (| NO | YES in quirks mode)
     // If frameborder is 0 or No, set border to 0
     // else leave it as the value set in html.css
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::frameborder);
     if (value && value->Type() == nsAttrValue::eEnum) {
       int32_t frameborder = value->GetEnumValue();
--- a/content/html/content/src/HTMLIFrameElement.h
+++ b/content/html/content/src/HTMLIFrameElement.h
@@ -169,14 +169,18 @@ public:
   // nsGenericHTMLFrameElement::GetAppManifestURL is fine
 
 protected:
   virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
 
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/content/html/content/src/HTMLImageElement.cpp
+++ b/content/html/content/src/HTMLImageElement.cpp
@@ -227,19 +227,19 @@ HTMLImageElement::ParseAttribute(int32_t
       return true;
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLImageElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                        nsRuleData* aData)
 {
   nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
--- a/content/html/content/src/HTMLImageElement.h
+++ b/content/html/content/src/HTMLImageElement.h
@@ -185,14 +185,18 @@ protected:
                                  bool aNotify) MOZ_OVERRIDE;
 
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) MOZ_OVERRIDE;
 
   // This is a weak reference that this element and the HTMLFormElement
   // cooperate in maintaining.
   HTMLFormElement* mForm;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLImageElement_h */
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -4451,19 +4451,19 @@ HTMLInputElement::ParseAttribute(int32_t
       return true;
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLInputElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                        nsRuleData* aData)
 {
   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
   if (value && value->Type() == nsAttrValue::eEnum &&
       value->GetEnumValue() == NS_FORM_INPUT_IMAGE) {
     nsGenericHTMLFormElementWithState::MapImageBorderAttributeInto(aAttributes, aData);
     nsGenericHTMLFormElementWithState::MapImageMarginAttributeInto(aAttributes, aData);
     nsGenericHTMLFormElementWithState::MapImageSizeAttributesInto(aAttributes, aData);
     // Images treat align as "float"
@@ -6817,8 +6817,10 @@ HTMLInputElement::UpdateHasRange()
 JSObject*
 HTMLInputElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return HTMLInputElementBinding::Wrap(aCx, aScope, this);
 }
 
 } // namespace dom
 } // namespace mozilla
+
+#undef NS_ORIGINAL_CHECKED_VALUE
--- a/content/html/content/src/HTMLInputElement.h
+++ b/content/html/content/src/HTMLInputElement.h
@@ -1214,16 +1214,18 @@ protected:
   bool                     mInhibitRestoration  : 1;
   bool                     mCanShowValidUI      : 1;
   bool                     mCanShowInvalidUI    : 1;
   bool                     mHasRange            : 1;
   bool                     mIsDraggingRange     : 1;
   bool                     mProgressTimerIsActive : 1;
 
 private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 
   /**
    * Returns true if this input's type will fire a DOM "change" event when it
    * loses focus if its value has changed since it gained focus.
    */
   bool MayFireChangeOnBlur() const {
     return MayFireChangeOnBlur(mType);
   }
--- a/content/html/content/src/HTMLLIElement.cpp
+++ b/content/html/content/src/HTMLLIElement.cpp
@@ -64,19 +64,19 @@ HTMLLIElement::ParseAttribute(int32_t aN
       return aResult.ParseIntValue(aValue);
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLLIElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                     nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(List)) {
     nsCSSValue* listStyleType = aData->ValueForListStyleType();
     if (listStyleType->GetUnit() == eCSSUnit_Null) {
       // type: enum
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
       if (value && value->Type() == nsAttrValue::eEnum)
         listStyleType->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
--- a/content/html/content/src/HTMLLIElement.h
+++ b/content/html/content/src/HTMLLIElement.h
@@ -54,14 +54,18 @@ public:
   void SetValue(int32_t aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLIntAttr(nsGkAtoms::value, aValue, rv);
   }
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLLIElement_h
--- a/content/html/content/src/HTMLLegendElement.cpp
+++ b/content/html/content/src/HTMLLegendElement.cpp
@@ -16,26 +16,16 @@ namespace dom {
 
 
 HTMLLegendElement::~HTMLLegendElement()
 {
 }
 
 NS_IMPL_ELEMENT_CLONE(HTMLLegendElement)
 
-// this contains center, because IE4 does
-static const nsAttrValue::EnumTable kAlignTable[] = {
-  { "left", NS_STYLE_TEXT_ALIGN_LEFT },
-  { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
-  { "center", NS_STYLE_TEXT_ALIGN_CENTER },
-  { "bottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
-  { "top", NS_STYLE_VERTICAL_ALIGN_TOP },
-  { 0 }
-};
-
 nsIContent*
 HTMLLegendElement::GetFieldSet()
 {
   nsIContent* parent = GetParent();
 
   if (parent && parent->IsHTML(nsGkAtoms::fieldset)) {
     return parent;
   }
@@ -44,16 +34,26 @@ HTMLLegendElement::GetFieldSet()
 }
 
 bool
 HTMLLegendElement::ParseAttribute(int32_t aNamespaceID,
                                   nsIAtom* aAttribute,
                                   const nsAString& aValue,
                                   nsAttrValue& aResult)
 {
+  // this contains center, because IE4 does
+  static const nsAttrValue::EnumTable kAlignTable[] = {
+    { "left", NS_STYLE_TEXT_ALIGN_LEFT },
+    { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
+    { "center", NS_STYLE_TEXT_ALIGN_CENTER },
+    { "bottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
+    { "top", NS_STYLE_VERTICAL_ALIGN_TOP },
+    { 0 }
+  };
+
   if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
     return aResult.ParseEnumValue(aValue, kAlignTable, false);
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
--- a/content/html/content/src/HTMLMenuItemElement.cpp
+++ b/content/html/content/src/HTMLMenuItemElement.cpp
@@ -485,8 +485,10 @@ HTMLMenuItemElement::InitChecked()
 JSObject*
 HTMLMenuItemElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return HTMLMenuItemElementBinding::Wrap(aCx, aScope, this);
 }
 
 } // namespace dom
 } // namespace mozilla
+
+#undef NS_ORIGINAL_CHECKED_VALUE
--- a/content/html/content/src/HTMLObjectElement.cpp
+++ b/content/html/content/src/HTMLObjectElement.cpp
@@ -361,19 +361,19 @@ HTMLObjectElement::ParseAttribute(int32_
       return true;
     }
   }
 
   return nsGenericHTMLFormElement::ParseAttribute(aNamespaceID, aAttribute,
                                                   aValue, aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes *aAttributes,
-                      nsRuleData *aData)
+void
+HTMLObjectElement::MapAttributesIntoRule(const nsMappedAttributes *aAttributes,
+                                         nsRuleData *aData)
 {
   nsGenericHTMLFormElement::MapImageAlignAttributeInto(aAttributes, aData);
   nsGenericHTMLFormElement::MapImageBorderAttributeInto(aAttributes, aData);
   nsGenericHTMLFormElement::MapImageMarginAttributeInto(aAttributes, aData);
   nsGenericHTMLFormElement::MapImageSizeAttributesInto(aAttributes, aData);
   nsGenericHTMLFormElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
--- a/content/html/content/src/HTMLObjectElement.h
+++ b/content/html/content/src/HTMLObjectElement.h
@@ -234,15 +234,18 @@ private:
   bool IsFocusableForTabIndex();
   
   virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
 
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
+
   bool mIsDoneAddingChildren;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLObjectElement_h
--- a/content/html/content/src/HTMLParagraphElement.cpp
+++ b/content/html/content/src/HTMLParagraphElement.cpp
@@ -36,18 +36,19 @@ HTMLParagraphElement::ParseAttribute(int
   if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
     return ParseDivAlignValue(aValue, aResult);
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
+void
+HTMLParagraphElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                            nsRuleData* aData)
 {
   nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLParagraphElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
--- a/content/html/content/src/HTMLParagraphElement.h
+++ b/content/html/content/src/HTMLParagraphElement.h
@@ -45,14 +45,18 @@ public:
   void SetAlign(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::align, aValue, rv);
   }
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLParagraphElement_h
--- a/content/html/content/src/HTMLPreElement.cpp
+++ b/content/html/content/src/HTMLPreElement.cpp
@@ -42,19 +42,19 @@ HTMLPreElement::ParseAttribute(int32_t a
       return aResult.ParseIntWithBounds(aValue, 0);
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLPreElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                      nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)) {
     nsCSSValue* width = aData->ValueForWidth();
     if (width->GetUnit() == eCSSUnit_Null) {
       // width: int (html4 attribute == nav4 cols)
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
       if (!value || value->Type() != nsAttrValue::eInteger) {
         // cols: int (nav4 attribute)
--- a/content/html/content/src/HTMLPreElement.h
+++ b/content/html/content/src/HTMLPreElement.h
@@ -49,14 +49,18 @@ public:
   void SetWidth(int32_t aWidth, mozilla::ErrorResult& rv)
   {
     rv = SetIntAttr(nsGkAtoms::width, aWidth);
   }
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLPreElement_h
--- a/content/html/content/src/HTMLSelectElement.cpp
+++ b/content/html/content/src/HTMLSelectElement.cpp
@@ -1421,19 +1421,19 @@ HTMLSelectElement::ParseAttribute(int32_
 {
   if (aAttribute == nsGkAtoms::size && kNameSpaceID_None == aNamespaceID) {
     return aResult.ParsePositiveIntValue(aValue);
   }
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLSelectElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                         nsRuleData* aData)
 {
   nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes, aData);
   nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aData);
 }
 
 nsChangeHint
 HTMLSelectElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                           int32_t aModType) const
--- a/content/html/content/src/HTMLSelectElement.h
+++ b/content/html/content/src/HTMLSelectElement.h
@@ -642,14 +642,18 @@ protected:
    * done adding options
    */
   nsCOMPtr<SelectState> mRestoreState;
 
   /**
    * The live list of selected options.
   */
   nsRefPtr<nsContentList> mSelectedOptions;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLSelectElement_h
--- a/content/html/content/src/HTMLSharedListElement.cpp
+++ b/content/html/content/src/HTMLSharedListElement.cpp
@@ -84,18 +84,19 @@ HTMLSharedListElement::ParseAttribute(in
       }
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
+void
+HTMLSharedListElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                             nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(List)) {
     nsCSSValue* listStyleType = aData->ValueForListStyleType();
     if (listStyleType->GetUnit() == eCSSUnit_Null) {
       // type: enum
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
       if (value) {
         if (value->Type() == nsAttrValue::eEnum)
--- a/content/html/content/src/HTMLSharedListElement.h
+++ b/content/html/content/src/HTMLSharedListElement.h
@@ -74,14 +74,18 @@ public:
   void SetCompact(bool aCompact, mozilla::ErrorResult& rv)
   {
     SetHTMLBoolAttr(nsGkAtoms::compact, aCompact, rv);
   }
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLSharedListElement_h
--- a/content/html/content/src/HTMLSharedObjectElement.cpp
+++ b/content/html/content/src/HTMLSharedObjectElement.cpp
@@ -255,19 +255,19 @@ MapAttributesIntoRuleBase(const nsMapped
 static void
 MapAttributesIntoRuleExceptHidden(const nsMappedAttributes *aAttributes,
                                   nsRuleData *aData)
 {
   MapAttributesIntoRuleBase(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesIntoExceptHidden(aAttributes, aData);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes *aAttributes,
-                      nsRuleData *aData)
+void
+HTMLSharedObjectElement::MapAttributesIntoRule(const nsMappedAttributes *aAttributes,
+                                               nsRuleData *aData)
 {
   MapAttributesIntoRuleBase(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLSharedObjectElement::IsAttributeMapped(const nsIAtom *aAttribute) const
 {
--- a/content/html/content/src/HTMLSharedObjectElement.h
+++ b/content/html/content/src/HTMLSharedObjectElement.h
@@ -218,14 +218,17 @@ private:
   // always true for <embed>, per the documentation in nsIContent.h.
   bool mIsDoneAddingChildren;
 
   virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
 
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLSharedObjectElement_h
--- a/content/html/content/src/HTMLTableCaptionElement.cpp
+++ b/content/html/content/src/HTMLTableCaptionElement.cpp
@@ -50,18 +50,19 @@ HTMLTableCaptionElement::ParseAttribute(
   if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
     return aResult.ParseEnumValue(aValue, kCaptionAlignTable, false);
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static 
-void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
+void
+HTMLTableCaptionElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                               nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(TableBorder)) {
     nsCSSValue* captionSide = aData->ValueForCaptionSide();
     if (captionSide->GetUnit() == eCSSUnit_Null) {
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
       if (value && value->Type() == nsAttrValue::eEnum)
         captionSide->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
     }
--- a/content/html/content/src/HTMLTableCaptionElement.h
+++ b/content/html/content/src/HTMLTableCaptionElement.h
@@ -44,14 +44,18 @@ public:
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const MOZ_OVERRIDE;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableCaptionElement_h */
--- a/content/html/content/src/HTMLTableCellElement.cpp
+++ b/content/html/content/src/HTMLTableCellElement.cpp
@@ -430,19 +430,19 @@ HTMLTableCellElement::ParseAttribute(int
 
   return nsGenericHTMLElement::ParseBackgroundAttribute(aNamespaceID,
                                                         aAttribute, aValue,
                                                         aResult) ||
          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static 
-void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                           nsRuleData* aData)
+void
+HTMLTableCellElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                            nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)) {
     // width: value
     nsCSSValue* width = aData->ValueForWidth();
     if (width->GetUnit() == eCSSUnit_Null) {
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
       if (value && value->Type() == nsAttrValue::eInteger) {
         if (value->GetIntegerValue() > 0)
--- a/content/html/content/src/HTMLTableCellElement.h
+++ b/content/html/content/src/HTMLTableCellElement.h
@@ -157,14 +157,18 @@ public:
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   HTMLTableElement* GetTable() const;
 
   HTMLTableRowElement* GetRow() const;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableCellElement_h */
--- a/content/html/content/src/HTMLTableColElement.cpp
+++ b/content/html/content/src/HTMLTableColElement.cpp
@@ -57,18 +57,19 @@ HTMLTableColElement::ParseAttribute(int3
       return ParseTableVAlignValue(aValue, aResult);
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static 
-void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
+void
+HTMLTableColElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                           nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Table)) {
     nsCSSValue *span = aData->ValueForSpan();
     if (span->GetUnit() == eCSSUnit_Null) {
       // span: int
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::span);
       if (value && value->Type() == nsAttrValue::eInteger) {
         int32_t val = value->GetIntegerValue();
--- a/content/html/content/src/HTMLTableColElement.h
+++ b/content/html/content/src/HTMLTableColElement.h
@@ -77,14 +77,18 @@ public:
   nsMapRuleToAttributesFunc GetAttributeMappingFunction() const MOZ_OVERRIDE;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableColElement_h */
--- a/content/html/content/src/HTMLTableElement.cpp
+++ b/content/html/content/src/HTMLTableElement.cpp
@@ -696,19 +696,19 @@ HTMLTableElement::ParseAttribute(int32_t
                                                         aAttribute, aValue,
                                                         aResult) ||
          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
 
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLTableElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                        nsRuleData* aData)
 {
   // XXX Bug 211636:  This function is used by a single style rule
   // that's used to match two different type of elements -- tables, and
   // table cells.  (nsHTMLTableCellElement overrides
   // WalkContentStyleRules so that this happens.)  This violates the
   // nsIStyleRule contract, since it's the same style rule object doing
   // the mapping in two different ways.  It's also incorrect since it's
   // testing the display type of the style context rather than checking
--- a/content/html/content/src/HTMLTableElement.h
+++ b/content/html/content/src/HTMLTableElement.h
@@ -217,14 +217,18 @@ protected:
 
   nsRefPtr<nsContentList> mTBodies;
   nsRefPtr<TableRowsCollection> mRows;
   // Sentinel value of TABLE_ATTRS_DIRTY indicates that this is dirty and needs
   // to be recalculated.
   nsMappedAttributes *mTableInheritedAttributes;
   void BuildInheritedAttributes();
   void ReleaseInheritedAttributes();
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableElement_h */
--- a/content/html/content/src/HTMLTableRowElement.cpp
+++ b/content/html/content/src/HTMLTableRowElement.cpp
@@ -256,18 +256,19 @@ HTMLTableRowElement::ParseAttribute(int3
 
   return nsGenericHTMLElement::ParseBackgroundAttribute(aNamespaceID,
                                                         aAttribute, aValue,
                                                         aResult) ||
          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static 
-void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
+void
+HTMLTableRowElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                           nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)) {
     // height: value
     nsCSSValue* height = aData->ValueForHeight();
     if (height->GetUnit() == eCSSUnit_Null) {
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
       if (value && value->Type() == nsAttrValue::eInteger)
         height->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
--- a/content/html/content/src/HTMLTableRowElement.h
+++ b/content/html/content/src/HTMLTableRowElement.h
@@ -91,14 +91,18 @@ public:
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   HTMLTableSectionElement* GetSection() const;
   HTMLTableElement* GetTable() const;
   nsRefPtr<nsContentList> mCells;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableRowElement_h */
--- a/content/html/content/src/HTMLTableSectionElement.cpp
+++ b/content/html/content/src/HTMLTableSectionElement.cpp
@@ -156,18 +156,19 @@ HTMLTableSectionElement::ParseAttribute(
 
   return nsGenericHTMLElement::ParseBackgroundAttribute(aNamespaceID,
                                                         aAttribute, aValue,
                                                         aResult) ||
          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static
-void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
+void
+HTMLTableSectionElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                               nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)) {
     // height: value
     nsCSSValue* height = aData->ValueForHeight();
     if (height->GetUnit() == eCSSUnit_Null) {
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
       if (value && value->Type() == nsAttrValue::eInteger)
         height->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
--- a/content/html/content/src/HTMLTableSectionElement.h
+++ b/content/html/content/src/HTMLTableSectionElement.h
@@ -72,14 +72,18 @@ public:
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(HTMLTableSectionElement,
                                                      nsGenericHTMLElement)
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   nsRefPtr<nsContentList> mRows;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableSectionElement_h */
--- a/content/html/content/src/HTMLTextAreaElement.cpp
+++ b/content/html/content/src/HTMLTextAreaElement.cpp
@@ -395,19 +395,19 @@ HTMLTextAreaElement::ParseAttribute(int3
                aAttribute == nsGkAtoms::rows) {
       return aResult.ParsePositiveIntValue(aValue);
     }
   }
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLTextAreaElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                           nsRuleData* aData)
 {
   nsGenericHTMLFormElementWithState::MapDivAlignAttributeInto(aAttributes, aData);
   nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aData);
 }
 
 nsChangeHint
 HTMLTextAreaElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                             int32_t aModType) const
--- a/content/html/content/src/HTMLTextAreaElement.h
+++ b/content/html/content/src/HTMLTextAreaElement.h
@@ -351,15 +351,19 @@ protected:
   bool IsMutable() const;
 
   /**
    * Returns whether the current value is the empty string.
    *
    * @return whether the current value is the empty string.
    */
   bool IsValueEmpty() const;
+
+private:
+  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                    nsRuleData* aData);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
 
--- a/content/html/content/src/HTMLVideoElement.cpp
+++ b/content/html/content/src/HTMLVideoElement.cpp
@@ -97,19 +97,19 @@ HTMLVideoElement::ParseAttribute(int32_t
    if (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height) {
      return aResult.ParseSpecialIntValue(aValue);
    }
 
    return HTMLMediaElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                            aResult);
 }
 
-static void
-MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                      nsRuleData* aData)
+void
+HTMLVideoElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                        nsRuleData* aData)
 {
   nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLVideoElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
--- a/content/html/content/src/moz.build
+++ b/content/html/content/src/moz.build
@@ -70,17 +70,17 @@ EXPORTS.mozilla.dom += [
     'HTMLUnknownElement.h',
     'MediaError.h',
     'TextTrackManager.h',
     'TimeRanges.h',
     'UndoManager.h',
     'ValidityState.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'HTMLAnchorElement.cpp',
     'HTMLAreaElement.cpp',
     'HTMLAudioElement.cpp',
     'HTMLBodyElement.cpp',
     'HTMLBRElement.cpp',
     'HTMLButtonElement.cpp',
     'HTMLCanvasElement.cpp',
     'HTMLDataElement.cpp',
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -1177,34 +1177,16 @@ nsGenericHTMLElement::GetPresContext()
     if (presShell) {
       return presShell->GetPresContext();
     }
   }
 
   return nullptr;
 }
 
-static const nsAttrValue::EnumTable kAlignTable[] = {
-  { "left",      NS_STYLE_TEXT_ALIGN_LEFT },
-  { "right",     NS_STYLE_TEXT_ALIGN_RIGHT },
-
-  { "top",       NS_STYLE_VERTICAL_ALIGN_TOP },
-  { "middle",    NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
-  { "bottom",    NS_STYLE_VERTICAL_ALIGN_BASELINE },
-
-  { "center",    NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
-  { "baseline",  NS_STYLE_VERTICAL_ALIGN_BASELINE },
-
-  { "texttop",   NS_STYLE_VERTICAL_ALIGN_TEXT_TOP },
-  { "absmiddle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
-  { "abscenter", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
-  { "absbottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
-  { 0 }
-};
-
 static const nsAttrValue::EnumTable kDivAlignTable[] = {
   { "left", NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
   { "right", NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
   { "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
   { "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
   { "justify", NS_STYLE_TEXT_ALIGN_JUSTIFY },
   { 0 }
 };
@@ -1235,16 +1217,34 @@ static const nsAttrValue::EnumTable kTab
   { "baseline",NS_STYLE_VERTICAL_ALIGN_BASELINE },
   { 0 }
 };
 
 bool
 nsGenericHTMLElement::ParseAlignValue(const nsAString& aString,
                                       nsAttrValue& aResult)
 {
+  static const nsAttrValue::EnumTable kAlignTable[] = {
+    { "left",      NS_STYLE_TEXT_ALIGN_LEFT },
+    { "right",     NS_STYLE_TEXT_ALIGN_RIGHT },
+
+    { "top",       NS_STYLE_VERTICAL_ALIGN_TOP },
+    { "middle",    NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
+    { "bottom",    NS_STYLE_VERTICAL_ALIGN_BASELINE },
+
+    { "center",    NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
+    { "baseline",  NS_STYLE_VERTICAL_ALIGN_BASELINE },
+
+    { "texttop",   NS_STYLE_VERTICAL_ALIGN_TEXT_TOP },
+    { "absmiddle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
+    { "abscenter", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
+    { "absbottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
+    { 0 }
+  };
+
   return aResult.ParseEnumValue(aString, kAlignTable, false);
 }
 
 //----------------------------------------
 
 static const nsAttrValue::EnumTable kTableHAlignTable[] = {
   { "left",   NS_STYLE_TEXT_ALIGN_LEFT },
   { "right",  NS_STYLE_TEXT_ALIGN_RIGHT },
--- a/content/html/document/src/moz.build
+++ b/content/html/document/src/moz.build
@@ -8,17 +8,17 @@ EXPORTS += [
     'nsIHTMLDocument.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'HTMLAllCollection.h',
     'ImageDocument.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'HTMLAllCollection.cpp',
     'ImageDocument.cpp',
     'MediaDocument.cpp',
     'nsHTMLContentSink.cpp',
     'nsHTMLDocument.cpp',
     'PluginDocument.cpp',
     'VideoDocument.cpp',
 ]
--- a/content/media/DecoderTraits.cpp
+++ b/content/media/DecoderTraits.cpp
@@ -471,17 +471,17 @@ DecoderTraits::CreateDecoder(const nsACS
     decoder = new WaveDecoder();
   }
 #endif
 #ifdef MOZ_OMX_DECODER
   if (IsOmxSupportedType(aType)) {
     // AMR audio is enabled for MMS, but we are discouraging Web and App
     // developers from using AMR, thus we only allow AMR to be played on WebApps.
     if (aType.EqualsASCII("audio/amr")) {
-      HTMLMediaElement* element = aOwner->GetMediaElement();
+      dom::HTMLMediaElement* element = aOwner->GetMediaElement();
       if (!element) {
         return nullptr;
       }
       nsIPrincipal* principal = element->NodePrincipal();
       if (!principal) {
         return nullptr;
       }
       if (principal->GetAppStatus() < nsIPrincipal::APP_STATUS_PRIVILEGED) {
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -565,17 +565,17 @@ nsresult MediaDecoder::Play()
 /**
  * Returns true if aValue is inside a range of aRanges, and put the range
  * index in aIntervalIndex if it is not null.
  * If aValue is not inside a range, false is returned, and aIntervalIndex, if
  * not null, is set to the index of the range which ends immediately before aValue
  * (and can be -1 if aValue is before aRanges.Start(0)).
  */
 static bool
-IsInRanges(TimeRanges& aRanges, double aValue, int32_t& aIntervalIndex)
+IsInRanges(dom::TimeRanges& aRanges, double aValue, int32_t& aIntervalIndex)
 {
   uint32_t length;
   aRanges.GetLength(&length);
   for (uint32_t i = 0; i < length; i++) {
     double start, end;
     aRanges.Start(i, &start);
     if (start > aValue) {
       aIntervalIndex = i - 1;
@@ -593,17 +593,17 @@ IsInRanges(TimeRanges& aRanges, double a
 
 nsresult MediaDecoder::Seek(double aTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
   NS_ABORT_IF_FALSE(aTime >= 0.0, "Cannot seek to a negative value.");
 
-  TimeRanges seekable;
+  dom::TimeRanges seekable;
   nsresult res;
   uint32_t length = 0;
   res = GetSeekable(&seekable);
   NS_ENSURE_SUCCESS(res, NS_OK);
 
   seekable.GetLength(&length);
   if (!length) {
     return NS_OK;
@@ -1321,17 +1321,17 @@ bool MediaDecoder::IsTransportSeekable()
 bool MediaDecoder::IsMediaSeekable()
 {
   NS_ENSURE_TRUE(GetStateMachine(), false);
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread());
   return mMediaSeekable;
 }
 
-nsresult MediaDecoder::GetSeekable(TimeRanges* aSeekable)
+nsresult MediaDecoder::GetSeekable(dom::TimeRanges* aSeekable)
 {
   double initialTime = 0.0;
 
   // We can seek in buffered range if the media is seekable. Also, we can seek
   // in unbuffered ranges if the transport level is seekable (local file or the
   // server supports range requests, etc.)
   if (!IsMediaSeekable()) {
     return NS_OK;
@@ -1487,17 +1487,17 @@ void MediaDecoder::Invalidate()
 {
   if (mVideoFrameContainer) {
     mVideoFrameContainer->Invalidate();
   }
 }
 
 // Constructs the time ranges representing what segments of the media
 // are buffered and playable.
-nsresult MediaDecoder::GetBuffered(TimeRanges* aBuffered) {
+nsresult MediaDecoder::GetBuffered(dom::TimeRanges* aBuffered) {
   if (mDecoderStateMachine) {
     return mDecoderStateMachine->GetBuffered(aBuffered);
   }
   return NS_ERROR_FAILURE;
 }
 
 int64_t MediaDecoder::VideoQueueMemoryInUse() {
   if (mDecoderStateMachine) {
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -196,18 +196,16 @@ class nsIPrincipal;
 class nsITimer;
 
 namespace mozilla {
 namespace dom {
 class TimeRanges;
 }
 }
 
-using namespace mozilla::dom;
-
 namespace mozilla {
 namespace layers {
 class Image;
 } //namespace layers
 
 class VideoFrameContainer;
 class MediaDecoderStateMachine;
 class MediaDecoderOwner;
@@ -227,18 +225,16 @@ static const uint32_t FRAMEBUFFER_LENGTH
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 
 class MediaDecoder : public nsIObserver,
                      public AbstractMediaDecoder
 {
 public:
-  typedef mozilla::layers::Image Image;
-
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   // Enumeration for the valid play states (see mPlayState)
   enum PlayState {
     PLAY_STATE_START,
     PLAY_STATE_LOADING,
     PLAY_STATE_PAUSED,
@@ -366,17 +362,17 @@ public:
     int64_t mInitialTime; // microseconds
     // mNextVideoTime is the end timestamp for the last packet sent to the stream.
     // Therefore video packets starting at or after this time need to be copied
     // to the output stream.
     int64_t mNextVideoTime; // microseconds
     MediaDecoder* mDecoder;
     // The last video image sent to the stream. Useful if we need to replicate
     // the image.
-    nsRefPtr<Image> mLastVideoImage;
+    nsRefPtr<layers::Image> mLastVideoImage;
     gfxIntSize mLastVideoImageDisplaySize;
     // This is set to true when the stream is initialized (audio and
     // video tracks added).
     bool mStreamInitialized;
     bool mHaveSentFinish;
     bool mHaveSentFinishAudio;
     bool mHaveSentFinishVideo;
 
@@ -518,17 +514,17 @@ public:
   // Returns true if this media supports seeking. False for example for WebM
   // files without an index and chained ogg files.
   virtual bool IsMediaSeekable() MOZ_FINAL MOZ_OVERRIDE;
   // Returns true if seeking is supported on a transport level (e.g. the server
   // supports range requests, we are playing a file, etc.).
   virtual bool IsTransportSeekable();
 
   // Return the time ranges that can be seeked into.
-  virtual nsresult GetSeekable(TimeRanges* aSeekable);
+  virtual nsresult GetSeekable(dom::TimeRanges* aSeekable);
 
   // Set the end time of the media resource. When playback reaches
   // this point the media pauses. aTime is in seconds.
   virtual void SetFragmentEndTime(double aTime);
 
   // Set the end time of the media. aTime is in microseconds.
   void SetMediaEndTime(int64_t aTime) MOZ_FINAL MOZ_OVERRIDE;
 
@@ -554,17 +550,17 @@ public:
   // Moves any existing channel loads into the background, so that they don't
   // block the load event. This is called when we stop delaying the load
   // event. Any new loads initiated (for example to seek) will also be in the
   // background. Implementations of this must call MoveLoadsToBackground() on
   // their MediaResource.
   virtual void MoveLoadsToBackground();
 
   // Returns a weak reference to the media decoder owner.
-  mozilla::MediaDecoderOwner* GetMediaOwner() const;
+  MediaDecoderOwner* GetMediaOwner() const;
 
   // Returns the current size of the framebuffer used in
   // MozAudioAvailable events.
   uint32_t GetFrameBufferLength() { return mFrameBufferLength; }
 
   void AudioAvailable(float* aFrameBuffer, uint32_t aFrameBufferLength, float aTime);
 
   // Called by the state machine to notify the decoder that the duration
@@ -579,28 +575,28 @@ public:
   // state.
   ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE;
 
   // Returns true if the decoder is shut down
   bool IsShutdown() const MOZ_FINAL MOZ_OVERRIDE;
 
   // Constructs the time ranges representing what segments of the media
   // are buffered and playable.
-  virtual nsresult GetBuffered(TimeRanges* aBuffered);
+  virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
 
   // Returns the size, in bytes, of the heap memory used by the currently
   // queued decoded video and audio data.
   virtual int64_t VideoQueueMemoryInUse();
   virtual int64_t AudioQueueMemoryInUse();
 
   VideoFrameContainer* GetVideoFrameContainer() MOZ_FINAL MOZ_OVERRIDE
   {
     return mVideoFrameContainer;
   }
-  mozilla::layers::ImageContainer* GetImageContainer() MOZ_OVERRIDE;
+  layers::ImageContainer* GetImageContainer() MOZ_OVERRIDE;
 
   // Sets the length of the framebuffer used in MozAudioAvailable events.
   // The new size must be between 512 and 16384.
   virtual nsresult RequestFrameBufferLength(uint32_t aLength);
 
   // Return the current state. Can be called on any thread. If called from
   // a non-main thread, the decoder monitor must be held.
   PlayState GetState() {
@@ -656,18 +652,18 @@ public:
   bool CanPlayThrough();
 
   // Make the decoder state machine update the playback position. Called by
   // the reader on the decoder thread (Assertions for this checked by
   // mDecoderStateMachine). This must be called with the decode monitor
   // held.
   void UpdatePlaybackPosition(int64_t aTime) MOZ_FINAL MOZ_OVERRIDE;
 
-  void SetAudioChannelType(AudioChannelType aType) { mAudioChannelType = aType; }
-  AudioChannelType GetAudioChannelType() { return mAudioChannelType; }
+  void SetAudioChannelType(dom::AudioChannelType aType) { mAudioChannelType = aType; }
+  dom::AudioChannelType GetAudioChannelType() { return mAudioChannelType; }
 
   // Send a new set of metadata to the state machine, to be dispatched to the
   // main thread to be presented when the |currentTime| of the media is greater
   // or equal to aPublishTime.
   void QueueMetadata(int64_t aPublishTime,
                      int aChannels,
                      int aRate,
                      bool aHasAudio,
@@ -922,16 +918,17 @@ public:
 
   // Increments the parsed and decoded frame counters by the passed in counts.
   // Can be called on any thread.
   virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_OVERRIDE
   {
     GetFrameStatistics().NotifyDecodedFrames(aParsed, aDecoded);
   }
 
+protected:
   /******
    * The following members should be accessed with the decoder lock held.
    ******/
 
   // Current decoding position in the stream. This is where the decoder
   // is up to consuming the stream. This is not adjusted during decoder
   // seek operations, but it's updated at the end when we start playing
   // back again.
@@ -1020,17 +1017,17 @@ private:
     }
   private:
     ReentrantMonitor mReentrantMonitor;
   };
 
   // The |RestrictedAccessMonitor| member object.
   RestrictedAccessMonitor mReentrantMonitor;
 
-public:
+protected:
   // Data about MediaStreams that are being fed by this decoder.
   nsTArray<OutputStreamData> mOutputStreams;
   // The SourceMediaStream we are using to feed the mOutputStreams. This stream
   // is never exposed outside the decoder.
   // Only written on the main thread while holding the monitor. Therefore it
   // can be read on any thread while holding the monitor, or on the main thread
   // without holding the monitor.
   nsAutoPtr<DecodedStreamData> mDecodedStream;
@@ -1082,18 +1079,16 @@ public:
 
   // True if the stream is infinite (e.g. a webradio).
   bool mInfiniteStream;
 
   // True if NotifyDecodedStreamMainThreadStateChanged should retrigger
   // PlaybackEnded when mDecodedStream->mStream finishes.
   bool mTriggerPlaybackEndedWhenSourceStreamFinishes;
 
-protected:
-
   // Start timer to update download progress information.
   nsresult StartProgress();
 
   // Stop progress information timer.
   nsresult StopProgress();
 
   // Ensures our media stream has been pinned.
   void PinForSeek();
@@ -1143,14 +1138,14 @@ protected:
   // Read/Write from the main thread only.
   bool mShuttingDown;
 
   // True if the playback is paused because the playback rate member is 0.0.
   bool mPausedForPlaybackRateNull;
 
   // Be assigned from media element during the initialization and pass to
   // AudioStream Class.
-  AudioChannelType mAudioChannelType;
+  dom::AudioChannelType mAudioChannelType;
 };
 
 } // namespace mozilla
 
 #endif
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -1600,17 +1600,17 @@ void MediaDecoderStateMachine::NotifyDat
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
 
   // While playing an unseekable stream of unknown duration, mEndTime is
   // updated (in AdvanceFrame()) as we play. But if data is being downloaded
   // faster than played, mEndTime won't reflect the end of playable data
   // since we haven't played the frame at the end of buffered data. So update
   // mEndTime here as new data is downloaded to prevent such a lag.
-  TimeRanges buffered;
+  dom::TimeRanges buffered;
   if (mDecoder->IsInfinite() &&
       NS_SUCCEEDED(mDecoder->GetBuffered(&buffered)))
   {
     uint32_t length = 0;
     buffered.GetLength(&length);
     if (length) {
       double end = 0;
       buffered.End(length - 1, &end);
@@ -2699,17 +2699,17 @@ void MediaDecoderStateMachine::StartBuff
   MediaDecoder::Statistics stats = mDecoder->GetStatistics();
 #endif
   LOG(PR_LOG_DEBUG, ("%p Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s",
     mDecoder.get(),
     stats.mPlaybackRate/1024, stats.mPlaybackRateReliable ? "" : " (unreliable)",
     stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)"));
 }
 
-nsresult MediaDecoderStateMachine::GetBuffered(TimeRanges* aBuffered) {
+nsresult MediaDecoderStateMachine::GetBuffered(dom::TimeRanges* aBuffered) {
   MediaResource* resource = mDecoder->GetResource();
   NS_ENSURE_TRUE(resource, NS_ERROR_FAILURE);
   resource->Pin();
   nsresult res = mReader->GetBuffered(aBuffered, mStartTime);
   resource->Unpin();
   return res;
 }
 
--- a/content/media/MediaDecoderStateMachine.h
+++ b/content/media/MediaDecoderStateMachine.h
@@ -250,17 +250,17 @@ public:
 
   // Must be called with the decode monitor held.
   bool IsSeeking() const {
     AssertCurrentThreadInMonitor();
 
     return mState == DECODER_STATE_SEEKING;
   }
 
-  nsresult GetBuffered(TimeRanges* aBuffered);
+  nsresult GetBuffered(dom::TimeRanges* aBuffered);
 
   void SetPlaybackRate(double aPlaybackRate);
   void SetPreservesPitch(bool aPreservesPitch);
 
   int64_t VideoQueueMemoryInUse() {
     if (mReader) {
       return mReader->VideoQueueMemoryInUse();
     }
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -142,17 +142,17 @@ ChannelMediaResource::Listener::GetInter
 
 nsresult
 ChannelMediaResource::OnStartRequest(nsIRequest* aRequest)
 {
   NS_ASSERTION(mChannel.get() == aRequest, "Wrong channel!");
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
-  HTMLMediaElement* element = owner->GetMediaElement();
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
   NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
   nsresult status;
   nsresult rv = aRequest->GetStatus(&status);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (element->ShouldCheckAllowOrigin()) {
     // If the request was cancelled by nsCORSListenerProxy due to failing
     // the CORS security check, send an error through to the media element.
@@ -578,17 +578,17 @@ nsresult ChannelMediaResource::OpenChann
     mChannel->SetNotificationCallbacks(mListener.get());
 
     nsCOMPtr<nsIStreamListener> listener = mListener.get();
 
     // Ensure that if we're loading cross domain, that the server is sending
     // an authorizing Access-Control header.
     MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
     NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
-    HTMLMediaElement* element = owner->GetMediaElement();
+    dom::HTMLMediaElement* element = owner->GetMediaElement();
     NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
     if (element->ShouldCheckAllowOrigin()) {
       nsRefPtr<nsCORSListenerProxy> crossSiteListener =
         new nsCORSListenerProxy(mListener,
                                 element->NodePrincipal(),
                                 false);
       nsresult rv = crossSiteListener->Init(mChannel);
       listener = crossSiteListener;
@@ -637,17 +637,17 @@ void ChannelMediaResource::SetupChannelH
     hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);
 
     // Send Accept header for video and audio types only (Bug 489071)
     NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
     MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
     if (!owner) {
       return;
     }
-    HTMLMediaElement* element = owner->GetMediaElement();
+    dom::HTMLMediaElement* element = owner->GetMediaElement();
     if (!element) {
       return;
     }
     element->SetRequestHeaders(hc);
   } else {
     NS_ASSERTION(mOffset == 0, "Don't know how to seek on this channel type");
   }
 }
@@ -800,17 +800,17 @@ void ChannelMediaResource::Suspend(bool 
 {
   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   if (!owner) {
     // Shutting down; do nothing.
     return;
   }
-  HTMLMediaElement* element = owner->GetMediaElement();
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
   if (!element) {
     // Shutting down; do nothing.
     return;
   }
 
   if (mChannel) {
     if (aCloseImmediately && mCacheStream.IsTransportSeekable()) {
       // Kill off our channel right now, but don't tell anyone about it.
@@ -835,17 +835,17 @@ void ChannelMediaResource::Resume()
   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
   NS_ASSERTION(mSuspendCount > 0, "Too many resumes!");
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   if (!owner) {
     // Shutting down; do nothing.
     return;
   }
-  HTMLMediaElement* element = owner->GetMediaElement();
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
   if (!element) {
     // Shutting down; do nothing.
     return;
   }
 
   NS_ASSERTION(mSuspendCount > 0, "Resume without previous Suspend!");
   --mSuspendCount;
   if (mSuspendCount == 0) {
@@ -884,17 +884,17 @@ ChannelMediaResource::RecreateChannel()
     nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
     (mLoadInBackground ? nsIRequest::LOAD_BACKGROUND : 0);
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   if (!owner) {
     // The decoder is being shut down, so don't bother opening a new channel
     return NS_OK;
   }
-  HTMLMediaElement* element = owner->GetMediaElement();
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
   if (!element) {
     // The decoder is being shut down, so don't bother opening a new channel
     return NS_OK;
   }
   nsCOMPtr<nsILoadGroup> loadGroup = element->GetDocumentLoadGroup();
   NS_ENSURE_TRUE(loadGroup, NS_ERROR_NULL_POINTER);
 
   nsresult rv = NS_NewChannel(getter_AddRefs(mChannel),
@@ -1304,17 +1304,17 @@ nsresult FileMediaResource::Open(nsIStre
     } else if (IsBlobURI(mURI)) {
       rv = NS_GetStreamForBlobURI(mURI, getter_AddRefs(mInput));
     }
   } else {
     // Ensure that we never load a local file from some page on a
     // web server.
     MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
     NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
-    HTMLMediaElement* element = owner->GetMediaElement();
+    dom::HTMLMediaElement* element = owner->GetMediaElement();
     NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
 
     rv = nsContentUtils::GetSecurityManager()->
            CheckLoadURIWithPrincipal(element->NodePrincipal(),
                                      mURI,
                                      nsIScriptSecurityManager::STANDARD);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1369,17 +1369,17 @@ already_AddRefed<MediaResource> FileMedi
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   if (!owner) {
     // The decoder is being shut down, so we can't clone
     return nullptr;
   }
-  HTMLMediaElement* element = owner->GetMediaElement();
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
   if (!element) {
     // The decoder is being shut down, so we can't clone
     return nullptr;
   }
   nsCOMPtr<nsILoadGroup> loadGroup = element->GetDocumentLoadGroup();
   NS_ENSURE_TRUE(loadGroup, nullptr);
 
   nsCOMPtr<nsIChannel> channel;
@@ -1528,17 +1528,17 @@ void BaseMediaResource::MoveLoadsToBackg
     return;
   }
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   if (!owner) {
     NS_WARNING("Null owner in MediaResource::MoveLoadsToBackground()");
     return;
   }
-  HTMLMediaElement* element = owner->GetMediaElement();
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
   if (!element) {
     NS_WARNING("Null element in MediaResource::MoveLoadsToBackground()");
     return;
   }
 
   bool isPending = false;
   if (NS_SUCCEEDED(mChannel->IsPending(&isPending)) &&
       isPending) {
--- a/content/media/RtspMediaResource.cpp
+++ b/content/media/RtspMediaResource.cpp
@@ -499,17 +499,17 @@ RtspMediaResource::OnConnected(uint8_t a
     }
   }
   // Fires an initial progress event and sets up the stall counter so stall events
   // fire if no download occurs within the required time frame.
   mDecoder->Progress(false);
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
-  HTMLMediaElement* element = owner->GetMediaElement();
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
   NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
 
   element->FinishDecoderSetup(mDecoder, this);
   mIsConnected = true;
 
   return NS_OK;
 }
 
@@ -530,30 +530,30 @@ RtspMediaResource::OnDisconnected(uint8_
 }
 
 void RtspMediaResource::Suspend(bool aCloseImmediately)
 {
   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   NS_ENSURE_TRUE_VOID(owner);
-  HTMLMediaElement* element = owner->GetMediaElement();
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
   NS_ENSURE_TRUE_VOID(element);
 
   mMediaStreamController->Suspend();
   element->DownloadSuspended();
 }
 
 void RtspMediaResource::Resume()
 {
   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   NS_ENSURE_TRUE_VOID(owner);
-  HTMLMediaElement* element = owner->GetMediaElement();
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
   NS_ENSURE_TRUE_VOID(element);
 
   if (mChannel) {
     element->DownloadResumed();
   }
   mMediaStreamController->Resume();
 }
 
--- a/content/media/gstreamer/GStreamerReader.cpp
+++ b/content/media/gstreamer/GStreamerReader.cpp
@@ -649,17 +649,17 @@ nsresult GStreamerReader::Seek(int64_t a
     LOG(PR_LOG_ERROR, ("seek failed"));
     return NS_ERROR_FAILURE;
   }
   LOG(PR_LOG_DEBUG, ("seek succeeded"));
 
   return DecodeToTarget(aTarget);
 }
 
-nsresult GStreamerReader::GetBuffered(TimeRanges* aBuffered,
+nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered,
                                       int64_t aStartTime)
 {
   if (!mInfo.HasValidMedia()) {
     return NS_OK;
   }
 
   GstFormat format = GST_FORMAT_TIME;
   MediaResource* resource = mDecoder->GetResource();
--- a/content/media/mediasource/MediaSource.h
+++ b/content/media/mediasource/MediaSource.h
@@ -30,17 +30,16 @@ namespace mozilla {
 class ErrorResult;
 template <typename T> class AsyncEventRunner;
 
 namespace dom {
 
 class GlobalObject;
 class SourceBuffer;
 class SourceBufferList;
-class TimeRanges;
 template <typename T> class Optional;
 
 #define MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID \
   { 0x3839d699, 0x22c5, 0x439f, \
   { 0x94, 0xca, 0x0e, 0x0b, 0x26, 0xf9, 0xca, 0xbf } }
 
 class MediaSource MOZ_FINAL : public nsDOMEventTargetHelper
 {
--- a/content/media/mediasource/MediaSourceDecoder.cpp
+++ b/content/media/mediasource/MediaSourceDecoder.cpp
@@ -115,17 +115,17 @@ private:
 
   MediaDecoderReader* GetAudioReader()
   {
     MediaSourceDecoder* decoder = static_cast<MediaSourceDecoder*>(mDecoder);
     return decoder->GetAudioReader();
   }
 };
 
-MediaSourceDecoder::MediaSourceDecoder(HTMLMediaElement* aElement)
+MediaSourceDecoder::MediaSourceDecoder(dom::HTMLMediaElement* aElement)
   : mMediaSource(nullptr)
   , mVideoReader(nullptr),
     mAudioReader(nullptr)
 {
   Init(aElement);
 }
 
 MediaDecoder*
@@ -143,33 +143,33 @@ MediaSourceDecoder::CreateStateMachine()
 
 nsresult
 MediaSourceDecoder::Load(nsIStreamListener**, MediaDecoder*)
 {
   return NS_OK;
 }
 
 nsresult
-MediaSourceDecoder::GetSeekable(TimeRanges* aSeekable)
+MediaSourceDecoder::GetSeekable(dom::TimeRanges* aSeekable)
 {
   double duration = mMediaSource->Duration();
   if (IsNaN(duration)) {
     // Return empty range.
   } else if (duration > 0 && mozilla::IsInfinite(duration)) {
-    nsRefPtr<TimeRanges> bufferedRanges = new TimeRanges();
+    nsRefPtr<dom::TimeRanges> bufferedRanges = new dom::TimeRanges();
     GetBuffered(bufferedRanges);
     aSeekable->Add(0, bufferedRanges->GetFinalEndTime());
   } else {
     aSeekable->Add(0, duration);
   }
   return NS_OK;
 }
 
 void
-MediaSourceDecoder::AttachMediaSource(MediaSource* aMediaSource)
+MediaSourceDecoder::AttachMediaSource(dom::MediaSource* aMediaSource)
 {
   MOZ_ASSERT(!mMediaSource && !mDecoderStateMachine);
   mMediaSource = aMediaSource;
   mDecoderStateMachine = CreateStateMachine();
 }
 
 void
 MediaSourceDecoder::DetachMediaSource()
--- a/content/media/mediasource/MediaSourceDecoder.h
+++ b/content/media/mediasource/MediaSourceDecoder.h
@@ -31,24 +31,24 @@ namespace dom {
 class HTMLMediaElement;
 class MediaSource;
 
 } // namespace dom
 
 class MediaSourceDecoder : public MediaDecoder
 {
 public:
-  MediaSourceDecoder(HTMLMediaElement* aElement);
+  MediaSourceDecoder(dom::HTMLMediaElement* aElement);
 
   virtual MediaDecoder* Clone() MOZ_OVERRIDE;
   virtual MediaDecoderStateMachine* CreateStateMachine() MOZ_OVERRIDE;
   virtual nsresult Load(nsIStreamListener**, MediaDecoder*) MOZ_OVERRIDE;
-  virtual nsresult GetSeekable(TimeRanges* aSeekable) MOZ_OVERRIDE;
+  virtual nsresult GetSeekable(dom::TimeRanges* aSeekable) MOZ_OVERRIDE;
 
-  void AttachMediaSource(MediaSource* aMediaSource);
+  void AttachMediaSource(dom::MediaSource* aMediaSource);
   void DetachMediaSource();
 
   SubBufferDecoder* CreateSubDecoder(const nsACString& aType);
 
   const nsTArray<MediaDecoderReader*>& GetReaders()
   {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     while (mReaders.Length() == 0) {
@@ -75,17 +75,17 @@ public:
   }
 
   MediaDecoderReader* GetAudioReader()
   {
     return mAudioReader;
   }
 
 private:
-  MediaSource* mMediaSource;
+  dom::MediaSource* mMediaSource;
 
   nsTArray<nsRefPtr<SubBufferDecoder> > mDecoders;
   nsTArray<MediaDecoderReader*> mReaders; // Readers owned by Decoders.
 
   MediaDecoderReader* mVideoReader;
   MediaDecoderReader* mAudioReader;
 };
 
--- a/content/media/mediasource/SubBufferDecoder.h
+++ b/content/media/mediasource/SubBufferDecoder.h
@@ -43,17 +43,17 @@ public:
   void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
   {
     mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
 
     // XXX: aOffset makes no sense here, need view of "data timeline".
     mParentDecoder->NotifyDataArrived(aBuffer, aLength, aOffset);
   }
 
-  nsresult GetBuffered(TimeRanges* aBuffered)
+  nsresult GetBuffered(dom::TimeRanges* aBuffered)
   {
     // XXX: Need mStartTime (from StateMachine) instead of passing 0.
     return mReader->GetBuffered(aBuffered, 0);
   }
 
 private:
   MediaSourceDecoder* mParentDecoder;
   nsAutoPtr<MediaDecoderReader> mReader;
--- a/content/media/ogg/OggReader.cpp
+++ b/content/media/ogg/OggReader.cpp
@@ -1767,17 +1767,17 @@ nsresult OggReader::SeekBisection(int64_
     NS_ASSERTION(endTime >= seekTarget, "End must be after seek target");
   }
 
   SEEK_LOG(PR_LOG_DEBUG, ("Seek complete in %d bisections.", hops));
 
   return NS_OK;
 }
 
-nsresult OggReader::GetBuffered(TimeRanges* aBuffered, int64_t aStartTime)
+nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
 {
   {
     mozilla::ReentrantMonitorAutoEnter mon(mMonitor);
     if (mIsChained)
       return NS_ERROR_FAILURE;
   }
 #ifdef OGG_ESTIMATE_BUFFERED
   return MediaDecoderReader::GetBuffered(aBuffered, aStartTime);
--- a/content/media/webaudio/blink/moz.build
+++ b/content/media/webaudio/blink/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'Biquad.cpp',
     'DirectConvolver.cpp',
     'DynamicsCompressor.cpp',
     'DynamicsCompressorKernel.cpp',
     'FFTConvolver.cpp',
     'HRTFDatabase.cpp',
     'HRTFDatabaseLoader.cpp',
     'HRTFElevation.cpp',
--- a/content/media/webaudio/moz.build
+++ b/content/media/webaudio/moz.build
@@ -43,17 +43,17 @@ EXPORTS.mozilla.dom += [
     'OfflineAudioCompletionEvent.h',
     'OscillatorNode.h',
     'PannerNode.h',
     'PeriodicWave.h',
     'ScriptProcessorNode.h',
     'WaveShaperNode.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'AnalyserNode.cpp',
     'AudioBuffer.cpp',
     'AudioBufferSourceNode.cpp',
     'AudioContext.cpp',
     'AudioDestinationNode.cpp',
     'AudioListener.cpp',
     'AudioNode.cpp',
     'AudioParam.cpp',
--- a/content/media/wmf/WMFReader.cpp
+++ b/content/media/wmf/WMFReader.cpp
@@ -109,17 +109,17 @@ WMFReader::InitializeDXVA()
   // Extract the layer manager backend type so that we can determine
   // whether it's worthwhile using DXVA. If we're not running with a D3D
   // layer manager then the readback of decoded video frames from GPU to
   // CPU memory grinds painting to a halt, and makes playback performance
   // *worse*.
   MediaDecoderOwner* owner = mDecoder->GetOwner();
   NS_ENSURE_TRUE(owner, false);
 
-  HTMLMediaElement* element = owner->GetMediaElement();
+  dom::HTMLMediaElement* element = owner->GetMediaElement();
   NS_ENSURE_TRUE(element, false);
 
   nsRefPtr<LayerManager> layerManager =
     nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
   NS_ENSURE_TRUE(layerManager, false);
 
   if (layerManager->GetBackendType() != LayersBackend::LAYERS_D3D9 &&
       layerManager->GetBackendType() != LayersBackend::LAYERS_D3D10) {
--- a/content/xslt/src/base/moz.build
+++ b/content/xslt/src/base/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'txDouble.cpp',
     'txExpandedNameMap.cpp',
     'txList.cpp',
     'txNamespaceMap.cpp',
     'txURIUtils.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
--- a/content/xslt/src/base/txLog.h
+++ b/content/xslt/src/base/txLog.h
@@ -2,17 +2,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 txLog_h__
 #define txLog_h__
 
 #include "prlog.h"
-#endif
 
 #ifdef PR_LOGGING
 class txLog
 {
 public:
     static PRLogModuleInfo *xpath;
     static PRLogModuleInfo *xslt;
 };
@@ -26,8 +25,9 @@ public:
     txLog::xslt  = PR_NewLogModule("xslt")
 
 #else
 
 #define TX_LG_IMPL
 #define TX_LG_CREATE
 
 #endif
+#endif
--- a/content/xslt/src/xml/moz.build
+++ b/content/xslt/src/xml/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'txXMLParser.cpp',
     'txXMLUtils.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
     '../base',
--- a/content/xslt/src/xpath/moz.build
+++ b/content/xslt/src/xpath/moz.build
@@ -3,17 +3,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/.
 
 EXPORTS.mozilla.dom += [
     'XPathEvaluator.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'nsXPathExpression.cpp',
     'nsXPathNSResolver.cpp',
     'nsXPathResult.cpp',
     'txBooleanExpr.cpp',
     'txBooleanResult.cpp',
     'txCoreFunctionCall.cpp',
     'txErrorExpr.cpp',
     'txExpr.cpp',
--- a/content/xslt/src/xslt/moz.build
+++ b/content/xslt/src/xslt/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'txBufferingHandler.cpp',
     'txCurrentFunctionCall.cpp',
     'txDocumentFunctionCall.cpp',
     'txExecutionState.cpp',
     'txEXSLTFunctions.cpp',
     'txFormatNumberFunctionCall.cpp',
     'txGenerateIdFunctionCall.cpp',
     'txInstructions.cpp',
--- a/dom/audiochannel/moz.build
+++ b/dom/audiochannel/moz.build
@@ -14,17 +14,17 @@ XPIDL_MODULE = 'dom_audiochannel'
 
 EXPORTS += [
     'AudioChannelAgent.h',
     'AudioChannelCommon.h',
     'AudioChannelService.h',
     'AudioChannelServiceChild.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'AudioChannelAgent.cpp',
     'AudioChannelService.cpp',
     'AudioChannelServiceChild.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/base/IndexedDBHelper.jsm
+++ b/dom/base/IndexedDBHelper.jsm
@@ -15,16 +15,17 @@ if (DEBUG) {
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 this.EXPORTED_SYMBOLS = ["IndexedDBHelper"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.importGlobalProperties(["indexedDB"]);
 
 this.IndexedDBHelper = function IndexedDBHelper() {}
 
 IndexedDBHelper.prototype = {
 
   // Cache the database
   _db: null,
 
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -52,16 +52,17 @@ EXPORTS.mozilla.dom += [
     'BarProps.h',
     'DOMCursor.h',
     'DOMError.h',
     'DOMException.h',
     'DOMRequest.h',
     'MessageChannel.h',
     'MessagePort.h',
     'MessagePortList.h',
+    'Navigator.h',
     'ScreenOrientation.h',
     'StructuredCloneTags.h',
     'URL.h',
 ]
 
 SOURCES += [
     'BarProps.cpp',
     'CompositionStringSynthesizer.cpp',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1884,17 +1884,17 @@ class CGCreateInterfaceObjectsMethod(CGA
                 (pref, ptr) in prefCacheData]
             prefCache = CGWrapper(CGIndenter(CGList(prefCacheData, "\n")),
                                   pre=("static bool sPrefCachesInited = false;\n"
                                        "if (!sPrefCachesInited) {\n"
                                        "  sPrefCachesInited = true;\n"),
                                   post="\n}")
         else:
             prefCache = None
-            
+
         if UseHolderForUnforgeable(self.descriptor):
             createUnforgeableHolder = CGGeneric("""JS::Rooted<JSObject*> unforgeableHolder(aCx,
   JS_NewObjectWithGivenProto(aCx, nullptr, nullptr, nullptr));
 if (!unforgeableHolder) {
   return;
 }""")
             defineUnforgeables = InitUnforgeablePropertiesOnObject(self.descriptor,
                                                                    "unforgeableHolder",
@@ -2012,17 +2012,17 @@ class CGGetPerInterfaceObject(CGAbstract
     return JS::NullPtr();
   }
   /* Check to see whether the interface objects are already installed */
   JS::Heap<JSObject*>* protoAndIfaceArray = GetProtoAndIfaceArray(aGlobal);
   if (!protoAndIfaceArray[%s]) {
     CreateInterfaceObjects(aCx, aGlobal, protoAndIfaceArray, aDefineOnGlobal);
   }
 
-  /* 
+  /*
    * The object might _still_ be null, but that's OK.
    *
    * Calling fromMarkedLocation() is safe because protoAndIfaceArray is
    * traced by TraceProtoAndIfaceCache() and its contents are never
    * changed after they have been set.
    */
   return JS::Handle<JSObject*>::fromMarkedLocation(protoAndIfaceArray[%s].address());""" %
                 (self.id, self.id))
@@ -3536,17 +3536,17 @@ for (uint32_t i = 0; i < length; ++i) {
             # have a non-default exceptionCode here unless attribute "arg
             # conversion" code starts passing in an exceptionCode.  At which
             # point we'll need to figure out what that even means.
             assert exceptionCode == "return false;"
             handleInvalidEnumValueCode = (
                 "  if (index < 0) {\n"
                 "    return true;\n"
                 "  }\n")
-            
+
         template = (
             "{\n"
             "  bool ok;\n"
             '  int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, "%(enumtype)s", "%(sourceDescription)s", &ok);\n'
             "  if (!ok) {\n"
             "%(exceptionCode)s\n"
             "  }\n"
             "%(handleInvalidEnumValueCode)s"
@@ -4103,17 +4103,17 @@ def getWrapTemplateForType(type, descrip
                     "}\n" +
                     successCode)
         return ("${jsvalRef}.set(%s);\n" +
                 tail) % (value)
 
     def wrapAndSetPtr(wrapCall, failureCode=None):
         """
         Returns the code to set the jsval by calling "wrapCall". "failureCode"
-        is the code to run if calling "wrapCall" fails 
+        is the code to run if calling "wrapCall" fails
         """
         if failureCode is None:
             failureCode = exceptionCode
         str = ("if (!%s) {\n" +
                CGIndenter(CGGeneric(failureCode)).define() + "\n" +
                "}\n" +
                successCode) % (wrapCall)
         return str
@@ -5031,17 +5031,17 @@ class CGSwitch(CGList):
                 CGIndenter(
                     CGWrapper(
                         CGIndenter(default),
                         pre="default: {\n",
                         post="\n  break;\n}"
                         )
                     )
                 )
-                        
+
         self.append(CGGeneric("}"))
 
 class CGCase(CGList):
     """
     A class to generate code for a case statement.
 
     Takes three constructor arguments: an expression, a CGThing for
     the body (allowed to be None if there is no body), and an optional
@@ -5080,17 +5080,17 @@ class CGMethodCall(CGThing):
             return requiredArgs
 
         def getPerSignatureCall(signature, argConversionStartsAt=0):
             return CGPerSignatureCall(signature[0], signature[1],
                                       nativeMethodName, static, descriptor,
                                       method,
                                       argConversionStartsAt=argConversionStartsAt,
                                       isConstructor=isConstructor)
-            
+
 
         signatures = method.signatures()
         if len(signatures) == 1:
             # Special case: we can just do a per-signature method call
             # here for our one signature and not worry about switching
             # on anything.
             signature = signatures[0]
             self.cgRoot = CGList([ CGIndenter(getPerSignatureCall(signature)) ])
@@ -6783,20 +6783,20 @@ class ClassUsingDeclaration(ClassItem):
                   'name': self.name })
 
     def define(self, cgClass):
         return ''
 
 class ClassConstructor(ClassItem):
     """
     Used for adding a constructor to a CGClass.
-    
+
     args is a list of Argument objects that are the arguments taken by the
     constructor.
-    
+
     inline should be True if the constructor should be marked inline.
 
     bodyInHeader should be True if the body should be placed in the class
     declaration in the header.
 
     visibility determines the visibility of the constructor (public,
     protected, private), defaults to private.
 
@@ -6830,17 +6830,17 @@ class ClassConstructor(ClassItem):
 
     def getInitializationList(self, cgClass):
         items = [str(c) for c in self.baseConstructors]
         for m in cgClass.members:
             if not m.static:
                 initialize = m.body
                 if initialize:
                     items.append(m.name + "(" + initialize + ")")
-            
+
         if len(items) > 0:
             return '\n  : ' + ',\n    '.join(items)
         return ''
 
     def getBody(self):
         return self.body
 
     def declare(self, cgClass):
@@ -7841,17 +7841,17 @@ class CGDOMJSProxyHandler_hasOwn(ClassMe
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'proxy'),
                 Argument('JS::Handle<jsid>', 'id'),
                 Argument('bool*', 'bp')]
         ClassMethod.__init__(self, "hasOwn", "bool", args)
         self.descriptor = descriptor
     def getBody(self):
         if self.descriptor.supportsIndexedProperties():
-            indexed = ("int32_t index = GetArrayIndexFromId(cx, id);\n" + 
+            indexed = ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
                        "if (IsArrayIndex(index)) {\n" +
                        CGIndenter(CGProxyIndexedPresenceChecker(self.descriptor)).define() + "\n" +
                        "  *bp = found;\n" +
                        "  return true;\n" +
                        "}\n\n") % (self.descriptor.nativeType)
         else:
             indexed = ""
 
@@ -8737,17 +8737,17 @@ if (""",
         else:
             conversion += (
                 "if (!isNull && !temp.ref().isUndefined()) {\n"
                 "  ${prop}.Construct();\n"
                 "${convert}\n"
                 "}")
             conversionReplacements["convert"] = CGIndenter(
                 CGGeneric(conversionReplacements["convert"])).define()
-        
+
         return CGGeneric(
             string.Template(conversion).substitute(conversionReplacements)
             )
 
     def getMemberDefinition(self, memberInfo):
         member = memberInfo[0]
         declType = memberInfo[1].declType
         memberLoc = self.makeMemberName(member.identifier.name)
@@ -11344,9 +11344,8 @@ class CGEventRoot(CGThing):
 
 """)
 
     def declare(self):
         return self.root.declare()
 
     def define(self):
         return self.root.define()
-
new file mode 100644
--- /dev/null
+++ b/dom/bindings/mach_commands.py
@@ -0,0 +1,30 @@
+# 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/.
+
+from __future__ import unicode_literals
+
+import os
+import sys
+
+from mach.decorators import (
+    CommandArgument,
+    CommandProvider,
+    Command,
+)
+
+from mozbuild.base import MachCommandBase
+
+
+@CommandProvider
+class WebIDLProvider(MachCommandBase):
+    @Command('webidl-parser-test', category='testing',
+        description='Run WebIDL tests.')
+    @CommandArgument('--verbose', '-v', action='store_true',
+        help='Run tests in verbose mode.')
+    def webidl_test(self, verbose=False):
+        sys.path.insert(0, os.path.join(self.topsrcdir, 'other-licenses',
+            'ply'))
+
+        from runtests import run_tests
+        return run_tests(None, verbose=verbose)
--- a/dom/bindings/test/Makefile.in
+++ b/dom/bindings/test/Makefile.in
@@ -60,20 +60,16 @@ include $(topsrcdir)/config/rules.mk
 	# $(CPPSRCS) in dom/bindings/Makefile.in.
 	$(MAKE) -C .. export TestExampleInterface-example TestExampleProxyInterface-example
 	@$(TOUCH) $@
 
 check::
 	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
 	  $(PLY_INCLUDE) $(srcdir)/../parser/runtests.py
 
-check-interactive:
-	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
-	  $(PLY_INCLUDE) $(srcdir)/../parser/runtests.py -q
-
 # Since we define MOCHITEST_FILES, config/makefiles/mochitest.mk goes ahead and
 # sets up a rule with libs:: in itm which makes our .DEFAULT_TARGET be "libs".
 # Then ruls.mk does |.DEFAULT_TARGET ?= default| which leaves it as "libs".  So
 # if we make without an explicit target in this directory, we try to make
 # "libs", but with a $(MAKECMDGOALS) of empty string.  And then rules.mk
 # helpfully does not include our *.o.pp files, since it includes them only if
 # filtering some stuff out from $(MAKECMDGOALS) leaves it nonempty.  The upshot
 # is that if some headers change and we run make in this dir without an explicit
--- a/dom/browser-element/BrowserElementPanning.js
+++ b/dom/browser-element/BrowserElementPanning.js
@@ -449,17 +449,17 @@ const ContentPanning = {
 
   get _activeDurationMs() {
     let duration = Services.prefs.getIntPref('ui.touch_activation.duration_ms');
     delete this._activeDurationMs;
     return this._activeDurationMs = duration;
   },
 
   _resetActive: function cp_resetActive() {
-    let elt = this.target || this.pointerDownTarget;
+    let elt = this.pointerDownTarget || this.target;
     let root = elt.ownerDocument || elt.document;
     this._setActive(root.documentElement);
   },
 
   _resetHover: function cp_resetHover() {
     const kStateHover = 0x00000004;
     let element = content.document.createElement('foo');
     this._domUtils.setContentState(element, kStateHover);
--- a/dom/contacts/fallback/ContactDB.jsm
+++ b/dom/contacts/fallback/ContactDB.jsm
@@ -13,16 +13,17 @@ function debug(s) { dump("-*- ContactDB 
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
 Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
+Cu.importGlobalProperties(["indexedDB"]);
 
 const DB_NAME = "contacts";
 const DB_VERSION = 18;
 const STORE_NAME = "contacts";
 const SAVED_GETALL_STORE_NAME = "getallcache";
 const CHUNK_SIZE = 20;
 const REVISION_STORE = "revision";
 const REVISION_KEY = "revision";
--- a/dom/contacts/tests/chrome.ini
+++ b/dom/contacts/tests/chrome.ini
@@ -1,3 +1,3 @@
 [DEFAULT]
 
-[test_contacts_upgrade.html]
+[test_contacts_upgrade.xul]
rename from dom/contacts/tests/test_contacts_upgrade.html
rename to dom/contacts/tests/test_contacts_upgrade.xul
--- a/dom/contacts/tests/test_contacts_upgrade.html
+++ b/dom/contacts/tests/test_contacts_upgrade.xul
@@ -1,278 +1,279 @@
-<!DOCTYPE html>
-<html>
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
 <!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=889239
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
 -->
-<head>
-  <title>Test for Bug 889239</title>
-  <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
 
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=889239">Mozilla Bug 889239</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-<script class="testbody" type="application/javascript;version=1.7">
-"use strict";
-
-var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
+<window title="Mozilla Bug 889239"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
-function checkStr(str1, str2, msg) {
-  if (str1 ^ str2) {
-    ok(false, "Expected both strings to be either present or absent");
-    return;
-  }
-  is(str1, str2, msg);
-}
+  <script type="application/javascript;version=1.7">
+  <![CDATA[
+  "use strict";
+
+  var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
 
-function checkStrArray(str1, str2, msg) {
-  // comparing /[null(,null)+]/ and undefined should pass
-  function nonNull(e) {
-    return e != null;
-  }
-  if ((Array.isArray(str1) && str1.filter(nonNull).length == 0 && str2 == undefined)
-     ||(Array.isArray(str2) && str2.filter(nonNull).length == 0 && str1 == undefined)) {
-    ok(true, msg);
-  } else if (str1) {
-    is(JSON.stringify(typeof str1 == "string" ? [str1] : str1), JSON.stringify(typeof str2 == "string" ? [str2] : str2), msg);
-  }
-}
-
-function checkAddress(adr1, adr2) {
-  if (adr1 ^ adr2) {
-    ok(false, "Expected both adrs to be either present or absent");
-    return;
+  function checkStr(str1, str2, msg) {
+    if (str1 ^ str2) {
+      ok(false, "Expected both strings to be either present or absent");
+      return;
+    }
+    is(str1, str2, msg);
   }
-  checkStrArray(adr1.type, adr2.type, "Same type");
-  checkStrArray(adr1.streetAddress, adr2.streetAddress, "Same streetAddress");
-  checkStrArray(adr1.locality, adr2.locality, "Same locality");
-  checkStrArray(adr1.region, adr2.region, "Same region");
-  checkStrArray(adr1.postalCode, adr2.postalCode, "Same postalCode");
-  checkStrArray(adr1.countryName, adr2.countryName, "Same countryName");
-  is(adr1.pref, adr2.pref, "Same pref");
-}
 
-function checkTel(tel1, tel2) {
-  if (tel1 ^ tel2) {
-    ok(false, "Expected both tels to be either present or absent");
-    return;
-  }
-  checkStrArray(tel1.type, tel2.type, "Same type");
-  checkStrArray(tel1.value, tel2.value, "Same value");
-  checkStrArray(tel1.carrier, tel2.carrier, "Same carrier");
-  is(tel1.pref, tel2.pref, "Same pref");
-}
-
-function checkField(field1, field2) {
-  if (field1 ^ field2) {
-    ok(false, "Expected both fields to be either present or absent");
-    return;
+  function checkStrArray(str1, str2, msg) {
+    // comparing /[null(,null)+]/ and undefined should pass
+    function nonNull(e) {
+      return e != null;
+    }
+    if ((Array.isArray(str1) && str1.filter(nonNull).length == 0 && str2 == undefined)
+       ||(Array.isArray(str2) && str2.filter(nonNull).length == 0 && str1 == undefined)) {
+      ok(true, msg);
+    } else if (str1) {
+      is(JSON.stringify(typeof str1 == "string" ? [str1] : str1), JSON.stringify(typeof str2 == "string" ? [str2] : str2), msg);
+    }
   }
-  checkStrArray(field1.type, field2.type, "Same type");
-  checkStrArray(field1.value, field2.value, "Same value");
-  is(field1.pref, field2.pref, "Same pref");
-}
-
-function checkDBContacts(dbContact1, dbContact2) {
-  let contact1 = dbContact1.properties;
-  let contact2 = dbContact2.properties;
 
-  checkStrArray(contact1.name, contact2.name, "Same name");
-  checkStrArray(contact1.honorificPrefix, contact2.honorificPrefix, "Same honorificPrefix");
-  checkStrArray(contact1.givenName, contact2.givenName, "Same givenName");
-  checkStrArray(contact1.additionalName, contact2.additionalName, "Same additionalName");
-  checkStrArray(contact1.familyName, contact2.familyName, "Same familyName");
-  checkStrArray(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
-  checkStrArray(contact1.nickname, contact2.nickname, "Same nickname");
-  checkStrArray(contact1.category, contact2.category, "Same category");
-  checkStrArray(contact1.org, contact2.org, "Same org");
-  checkStrArray(contact1.jobTitle, contact2.jobTitle, "Same jobTitle");
-  is(contact1.bday ? contact1.bday.valueOf() : null, contact2.bday ? contact2.bday.valueOf() : null, "Same birthday");
-  checkStrArray(contact1.note, contact2.note, "Same note");
-  is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
-  checkStr(contact1.sex, contact2.sex, "Same sex");
-  checkStr(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
-  checkStrArray(contact1.key, contact2.key, "Same key");
+  function checkAddress(adr1, adr2) {
+    if (adr1 ^ adr2) {
+      ok(false, "Expected both adrs to be either present or absent");
+      return;
+    }
+    checkStrArray(adr1.type, adr2.type, "Same type");
+    checkStrArray(adr1.streetAddress, adr2.streetAddress, "Same streetAddress");
+    checkStrArray(adr1.locality, adr2.locality, "Same locality");
+    checkStrArray(adr1.region, adr2.region, "Same region");
+    checkStrArray(adr1.postalCode, adr2.postalCode, "Same postalCode");
+    checkStrArray(adr1.countryName, adr2.countryName, "Same countryName");
+    is(adr1.pref, adr2.pref, "Same pref");
+  }
 
-  is(contact1.email.length, contact2.email.length, "Same number of emails");
-  for (let i = 0; i < contact1.email.length; ++i) {
-    checkField(contact1.email[i], contact2.email[i]);
+  function checkTel(tel1, tel2) {
+    if (tel1 ^ tel2) {
+      ok(false, "Expected both tels to be either present or absent");
+      return;
+    }
+    checkStrArray(tel1.type, tel2.type, "Same type");
+    checkStrArray(tel1.value, tel2.value, "Same value");
+    checkStrArray(tel1.carrier, tel2.carrier, "Same carrier");
+    is(tel1.pref, tel2.pref, "Same pref");
   }
 
-  is(contact1.adr.length, contact2.adr.length, "Same number of adrs");
-  for (var i in contact1.adr) {
-    checkAddress(contact1.adr[i], contact2.adr[i]);
+  function checkField(field1, field2) {
+    if (field1 ^ field2) {
+      ok(false, "Expected both fields to be either present or absent");
+      return;
+    }
+    checkStrArray(field1.type, field2.type, "Same type");
+    checkStrArray(field1.value, field2.value, "Same value");
+    is(field1.pref, field2.pref, "Same pref");
   }
 
-  is(contact1.tel.length, contact2.tel.length, "Same number of tels");
-  for (var i in contact1.tel) {
-    checkTel(contact1.tel[i], contact2.tel[i]);
-  }
+  function checkDBContacts(dbContact1, dbContact2) {
+    let contact1 = dbContact1.properties;
+    let contact2 = dbContact2.properties;
+
+    checkStrArray(contact1.name, contact2.name, "Same name");
+    checkStrArray(contact1.honorificPrefix, contact2.honorificPrefix, "Same honorificPrefix");
+    checkStrArray(contact1.givenName, contact2.givenName, "Same givenName");
+    checkStrArray(contact1.additionalName, contact2.additionalName, "Same additionalName");
+    checkStrArray(contact1.familyName, contact2.familyName, "Same familyName");
+    checkStrArray(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
+    checkStrArray(contact1.nickname, contact2.nickname, "Same nickname");
+    checkStrArray(contact1.category, contact2.category, "Same category");
+    checkStrArray(contact1.org, contact2.org, "Same org");
+    checkStrArray(contact1.jobTitle, contact2.jobTitle, "Same jobTitle");
+    is(contact1.bday ? contact1.bday.valueOf() : null, contact2.bday ? contact2.bday.valueOf() : null, "Same birthday");
+    checkStrArray(contact1.note, contact2.note, "Same note");
+    is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
+    checkStr(contact1.sex, contact2.sex, "Same sex");
+    checkStr(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
+    checkStrArray(contact1.key, contact2.key, "Same key");
+
+    is(contact1.email.length, contact2.email.length, "Same number of emails");
+    for (let i = 0; i < contact1.email.length; ++i) {
+      checkField(contact1.email[i], contact2.email[i]);
+    }
 
-  is(contact1.url.length, contact2.url.length, "Same number of urls");
-  for (var i in contact1.url) {
-    checkField(contact1.url[i], contact2.url[i]);
-  }
+    is(contact1.adr.length, contact2.adr.length, "Same number of adrs");
+    for (var i in contact1.adr) {
+      checkAddress(contact1.adr[i], contact2.adr[i]);
+    }
+
+    is(contact1.tel.length, contact2.tel.length, "Same number of tels");
+    for (var i in contact1.tel) {
+      checkTel(contact1.tel[i], contact2.tel[i]);
+    }
+
+    is(contact1.url.length, contact2.url.length, "Same number of urls");
+    for (var i in contact1.url) {
+      checkField(contact1.url[i], contact2.url[i]);
+    }
 
-  is(contact1.impp.length, contact2.impp.length, "Same number of impps");
-  for (var i in contact1.impp) {
-    checkField(contact1.impp[i], contact2.impp[i]);
+    is(contact1.impp.length, contact2.impp.length, "Same number of impps");
+    for (var i in contact1.impp) {
+      checkField(contact1.impp[i], contact2.impp[i]);
+    }
+
+    // test search indexes
+    contact1 = dbContact1.search;
+    contact2 = dbContact2.search;
+    checkStrArray(contact1.category, contact2.category, "Same cateogry index");
+    checkStrArray(contact1.email, contact2.email, "Same email index");
+    checkStrArray(contact1.emailLowerCase, contact2.emailLowerCase, "Same emailLowerCase index");
+    checkStrArray(contact1.familyName, contact2.familyName, "Same familyName index");
+    checkStrArray(contact1.familyNameLowerCase, contact2.familyNameLowerCase, "Same familyNameLowerCase index");
+    checkStrArray(contact1.givenName, contact2.givenName, "Same givenName index");
+    checkStrArray(contact1.givenNameLowerCase, contact2.givenNameLowerCase, "Same givenNameLowerCase index");
+    checkStrArray(contact1.name, contact2.name, "Same name index");
+    checkStrArray(contact1.tel, contact2.tel, "Same tel index");
+    checkStrArray(contact1.telLowerCase, contact2.telLowerCase, "Same telLowerCase index");
+    checkStrArray(contact1.telMatch, contact2.telMatch, "Same telMatch index");
   }
 
-  // test search indexes
-  contact1 = dbContact1.search;
-  contact2 = dbContact2.search;
-  checkStrArray(contact1.category, contact2.category, "Same cateogry index");
-  checkStrArray(contact1.email, contact2.email, "Same email index");
-  checkStrArray(contact1.emailLowerCase, contact2.emailLowerCase, "Same emailLowerCase index");
-  checkStrArray(contact1.familyName, contact2.familyName, "Same familyName index");
-  checkStrArray(contact1.familyNameLowerCase, contact2.familyNameLowerCase, "Same familyNameLowerCase index");
-  checkStrArray(contact1.givenName, contact2.givenName, "Same givenName index");
-  checkStrArray(contact1.givenNameLowerCase, contact2.givenNameLowerCase, "Same givenNameLowerCase index");
-  checkStrArray(contact1.name, contact2.name, "Same name index");
-  checkStrArray(contact1.tel, contact2.tel, "Same tel index");
-  checkStrArray(contact1.telLowerCase, contact2.telLowerCase, "Same telLowerCase index");
-  checkStrArray(contact1.telMatch, contact2.telMatch, "Same telMatch index");
-}
-
-function makeFailure(reason) {
-  return function() {
-    ok(false, reason);
-    SimpleTest.finish();
-  };
-};
-
-const {Cc, Ci, Cu} = SpecialPowers;
-Cu.import("resource://gre/modules/ContactDB.jsm", window);
-
-let cdb = new ContactDB();
-cdb.init();
-
-let CONTACT_PROPS = {
-  id: "ab74671e36be41b680f8f030e7e24ea2",
-  properties: {
-    name: ["Magnificentest foo bar the third"],
-    givenName: ["foo"],
-    familyName: ["bar"],
-    honorificPrefix: ["magnificentest"],
-    honorificSuffix: ["the third"],
-    additionalName: ["addl"],
-    nickname: ["foo"],
-    tel: [
-      {type: ["mobile"], value: "+12345678901", carrier: "ACME Telecommunications", pref: true},
-      {type: ["home", "custom"], value: "7932012346", pref: false},
-    ],
-    email: [{type: ["work"], value: "a@b.c"}, {value: "b@c.d", pref: true}],
-    adr: [
-      {
-        type: ["home"],
-        streetAddress: "street 1",
-        locality: "locality 1",
-        region: "region 1",
-        postalCode: "postal code 1",
-        countryName: "country 1",
-      }
-    ],
-    impp: [{type: ["aim"], value:"im1", pref: true}, {value: "im2"}],
-    org: ["org1", "org2"],
-    jobTitle: ["boss", "superboss"],
-    bday: new Date("1980, 12, 01"),
-    note: ["bla bla bla"],
-    category: ["cat1", "cat2"],
-    url: [{type: ["work", "work2"], value: "www.1.com", pref: true}, {value: "www2.com"}],
-    anniversary: new Date("2000, 12, 01"),
-    sex: "male",
-    genderIdentity: "trisexual",
-    key: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAC4jAAAuIwF4pT92AAACrElEQVQozwXBTW8bRRgA4Hfemf1er7/iJI4Tq7VFlEZN1VZIlapy4MQBTkXcuSH+G/APKnGAAyCVCqmtCHETp64db5zdtdf7NbMzw/OQH378HkCZpmmapqYMy8yrNnadS6026HC/Z7k+SCkEBwKEEKaUQtQAmlDqrucH23nH4BRkJVRcwmod5gcn6LehFgCaEIIalFZaEcLCq73w355RdvY7nfGQGVTlmRXfqMlrUaSUMUQkhCISJIggKj3/YBHt7PRbpy+cwbF7dN/0vEqTMoo3s0tmGAAAoJAgImMq3xZ5WTPbHj4Mho8Nf+QcPtZBLxEkqeQ2WmklkRCtNdNaI1KpVCnqOC3j5ZK++4vnm6xSWZpzwQtRV2mOiBoRpEKtNQAQggjQcCwqinRxJeKlWW93dlqEsa2QRZbF85nWBAAZY4YUgl9fRJWKVuWgmhwHhpD1+ZrfVjAN867rMCne//rq7OuXjWaLCVHnOWHgFDwMw+Tvi09PdhtJXoVC7bWDIi8Lg8qyMk3rYjLzvJh2O30hwK6TpiG7zWDcck9GR17D9wxDcH7/oNtElRa1aZuLDJN4S7/87tssLVg0/eZs/3h0D5R89vR0v+1AVT0YHX31ZDy9uv7IeJrryeyu2+nS50/PqOXM5qt8Nf/jv08UwTfN27vkchldLpPf/nx/nqSz5sbzhkTYzLRppzNYre/ycrMIZwqsHdf96fd/Xr354AYBr/jESWhgGb6zVSuGrrQS1j4Zk8nc2Hs7frFb3Phc6+fOKDGLKOJTHvlj2u85N4t6vbw7OM4YRVquboPdsPNZ9eb8pvfAOf2iN4dN3EzWadnoO5JY19Oo0TYtw1t8TBqBR9v7wbOXROLWtZ3PH937+ZfXrb6BUHEbXL+FCIfDw92e5zebg8GR54r/AaMVcBxE6hgPAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDEyLTA3LTIxVDEwOjUzOjE5LTA0OjAwYyXbYgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMi0wNy0yMVQxMDo1MzoxOS0wNDowMBJ4Y94AAAARdEVYdGpwZWc6Y29sb3JzcGFjZQAyLHVVnwAAACB0RVh0anBlZzpzYW1wbGluZy1mYWN0b3IAMXgxLDF4MSwxeDHplfxwAAAAAElFTkSuQmCC"
-  }
-};
-
-function deleteDatabase(then) {
-  cdb.close();
-  let req = indexedDB.deleteDatabase(DB_NAME);
-  req.onsuccess = then;
-  req.onblocked = makeFailure("blocked");
-  req.onupgradeneeded = makeFailure("onupgradeneeded");
-  req.onerror = makeFailure("onerror");
-}
-
-function saveContact() {
-  // takes fast upgrade path
-  cdb.saveContact(CONTACT_PROPS,
-    function() {
-      ok(true, "Saved contact successfully");
-      next();
-    }
-  );
-}
-
-function getContact(callback) {
-  return function() {
-    let req = indexedDB.open(STORE_NAME, DB_VERSION);
-    req.onsuccess = function(event) {
-      let db = event.target.result;
-      let txn = db.transaction([STORE_NAME], "readonly");
-      txn.onabort = makeFailure("Failed to open transaction");
-      let r2 = txn.objectStore(STORE_NAME).get(CONTACT_PROPS.id);
-      r2.onsuccess = function() {
-        db.close();
-        callback(r2.result);
-      };
-      r2.onerror = makeFailure("Failed to get contact");
+  function makeFailure(reason) {
+    return function() {
+      ok(false, reason);
+      SimpleTest.finish();
     };
   };
-}
 
-let savedContact;
+  const { 'utils': Cu } = Components;
+  Cu.import("resource://gre/modules/ContactDB.jsm", window);
+  Cu.importGlobalProperties(["indexedDB"]);
+
+  let cdb = new ContactDB();
+  cdb.init();
 
-let Tests = [
-  saveContact,
+  let CONTACT_PROPS = {
+    id: "ab74671e36be41b680f8f030e7e24ea2",
+    properties: {
+      name: ["Magnificentest foo bar the third"],
+      givenName: ["foo"],
+      familyName: ["bar"],
+      honorificPrefix: ["magnificentest"],
+      honorificSuffix: ["the third"],
+      additionalName: ["addl"],
+      nickname: ["foo"],
+      tel: [
+        {type: ["mobile"], value: "+12345678901", carrier: "ACME Telecommunications", pref: true},
+        {type: ["home", "custom"], value: "7932012346", pref: false},
+      ],
+      email: [{type: ["work"], value: "a@b.c"}, {value: "b@c.d", pref: true}],
+      adr: [
+        {
+          type: ["home"],
+          streetAddress: "street 1",
+          locality: "locality 1",
+          region: "region 1",
+          postalCode: "postal code 1",
+          countryName: "country 1",
+        }
+      ],
+      impp: [{type: ["aim"], value:"im1", pref: true}, {value: "im2"}],
+      org: ["org1", "org2"],
+      jobTitle: ["boss", "superboss"],
+      bday: new Date("1980, 12, 01"),
+      note: ["bla bla bla"],
+      category: ["cat1", "cat2"],
+      url: [{type: ["work", "work2"], value: "www.1.com", pref: true}, {value: "www2.com"}],
+      anniversary: new Date("2000, 12, 01"),
+      sex: "male",
+      genderIdentity: "trisexual",
+      key: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAC4jAAAuIwF4pT92AAACrElEQVQozwXBTW8bRRgA4Hfemf1er7/iJI4Tq7VFlEZN1VZIlapy4MQBTkXcuSH+G/APKnGAAyCVCqmtCHETp64db5zdtdf7NbMzw/OQH378HkCZpmmapqYMy8yrNnadS6026HC/Z7k+SCkEBwKEEKaUQtQAmlDqrucH23nH4BRkJVRcwmod5gcn6LehFgCaEIIalFZaEcLCq73w355RdvY7nfGQGVTlmRXfqMlrUaSUMUQkhCISJIggKj3/YBHt7PRbpy+cwbF7dN/0vEqTMoo3s0tmGAAAoJAgImMq3xZ5WTPbHj4Mho8Nf+QcPtZBLxEkqeQ2WmklkRCtNdNaI1KpVCnqOC3j5ZK++4vnm6xSWZpzwQtRV2mOiBoRpEKtNQAQggjQcCwqinRxJeKlWW93dlqEsa2QRZbF85nWBAAZY4YUgl9fRJWKVuWgmhwHhpD1+ZrfVjAN867rMCne//rq7OuXjWaLCVHnOWHgFDwMw+Tvi09PdhtJXoVC7bWDIi8Lg8qyMk3rYjLzvJh2O30hwK6TpiG7zWDcck9GR17D9wxDcH7/oNtElRa1aZuLDJN4S7/87tssLVg0/eZs/3h0D5R89vR0v+1AVT0YHX31ZDy9uv7IeJrryeyu2+nS50/PqOXM5qt8Nf/jv08UwTfN27vkchldLpPf/nx/nqSz5sbzhkTYzLRppzNYre/ycrMIZwqsHdf96fd/Xr354AYBr/jESWhgGb6zVSuGrrQS1j4Zk8nc2Hs7frFb3Phc6+fOKDGLKOJTHvlj2u85N4t6vbw7OM4YRVquboPdsPNZ9eb8pvfAOf2iN4dN3EzWadnoO5JY19Oo0TYtw1t8TBqBR9v7wbOXROLWtZ3PH937+ZfXrb6BUHEbXL+FCIfDw92e5zebg8GR54r/AaMVcBxE6hgPAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDEyLTA3LTIxVDEwOjUzOjE5LTA0OjAwYyXbYgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMi0wNy0yMVQxMDo1MzoxOS0wNDowMBJ4Y94AAAARdEVYdGpwZWc6Y29sb3JzcGFjZQAyLHVVnwAAACB0RVh0anBlZzpzYW1wbGluZy1mYWN0b3IAMXgxLDF4MSwxeDHplfxwAAAAAElFTkSuQmCC"
+    }
+  };
 
-  getContact(function(contact) {
-    savedContact = contact;
-    next();
-  }),
+  function deleteDatabase(then) {
+    cdb.close();
+    let req = indexedDB.deleteDatabase(DB_NAME);
+    req.onsuccess = then;
+    req.onblocked = makeFailure("blocked");
+    req.onupgradeneeded = makeFailure("onupgradeneeded");
+    req.onerror = makeFailure("onerror");
+  }
 
-  function() {
-    deleteDatabase(function() {
-      info("slow upgrade");
-      cdb.useFastUpgrade = false;
-      cdb.init();
+  function saveContact() {
+    // takes fast upgrade path
+    cdb.saveContact(CONTACT_PROPS,
+      function() {
+        ok(true, "Saved contact successfully");
+        next();
+      }
+    );
+  }
+
+  function getContact(callback) {
+    return function() {
+      let req = indexedDB.open(STORE_NAME, DB_VERSION);
+      req.onsuccess = function(event) {
+        let db = event.target.result;
+        let txn = db.transaction([STORE_NAME], "readonly");
+        txn.onabort = makeFailure("Failed to open transaction");
+        let r2 = txn.objectStore(STORE_NAME).get(CONTACT_PROPS.id);
+        r2.onsuccess = function() {
+          db.close();
+          callback(r2.result);
+        };
+        r2.onerror = makeFailure("Failed to get contact");
+      };
+    };
+  }
+
+  let savedContact;
+
+  let Tests = [
+    saveContact,
+
+    getContact(function(contact) {
+      savedContact = contact;
       next();
-    });
-  },
+    }),
+
+    function() {
+      deleteDatabase(function() {
+        info("slow upgrade");
+        cdb.useFastUpgrade = false;
+        cdb.init();
+        next();
+      });
+    },
+
+    saveContact,
 
-  saveContact,
+    getContact(function(contact) {
+      checkDBContacts(savedContact, contact);
+      next();
+    }),
+  ];
 
-  getContact(function(contact) {
-    checkDBContacts(savedContact, contact);
+  function next() {
+    let step = Tests.shift();
+    if (step) {
+      step();
+    } else {
+      info("All done");
+      SimpleTest.finish();
+    }
+  }
+
+  // Skip tests on Android
+  if (!isAndroid) {
+    SimpleTest.waitForExplicitFinish();
     next();
-  }),
-];
-
-function next() {
-  let step = Tests.shift();
-  if (step) {
-    step();
   } else {
-    info("All done");
-    SimpleTest.finish();
+    ok(true, "Skip test on Android");
   }
-}
 
-// Skip tests on Android
-if (!isAndroid) {
-  SimpleTest.waitForExplicitFinish();
-  next();
-} else {
-  ok(true, "Skip test on Android");
-}
+  ]]>
+  </script>
 
-</script>
-</pre>
-</body>
-</html>
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=889239"
+     target="_blank">Mozilla Bug 889239</a>
+  </body>
+</window>
--- a/dom/datastore/DataStore.jsm
+++ b/dom/datastore/DataStore.jsm
@@ -23,16 +23,17 @@ const REVISION_VOID = "void";
 // and yet we don't know if it's too low or too high.
 const MAX_REQUESTS = 25;
 
 Cu.import("resource://gre/modules/DataStoreCursor.jsm");
 Cu.import("resource://gre/modules/DataStoreDB.jsm");
 Cu.import("resource://gre/modules/ObjectWrapper.jsm");
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.importGlobalProperties(["indexedDB"]);
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
 /* Helper functions */
 function createDOMError(aWindow, aEvent) {
   return new aWindow.DOMError(aEvent.target.error.name);
--- a/dom/datastore/DataStoreDB.jsm
+++ b/dom/datastore/DataStoreDB.jsm
@@ -14,16 +14,17 @@ function debug(s) {
 
 const DATASTOREDB_VERSION = 1;
 const DATASTOREDB_OBJECTSTORE_NAME = 'DataStoreDB';
 const DATASTOREDB_REVISION = 'revision';
 const DATASTOREDB_REVISION_INDEX = 'revisionIndex';
 
 Cu.import('resource://gre/modules/IndexedDBHelper.jsm');
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.importGlobalProperties(["indexedDB"]);
 
 XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
 
 this.DataStoreDB = function DataStoreDB() {}
 
 DataStoreDB.prototype = {
--- a/dom/encoding/moz.build
+++ b/dom/encoding/moz.build
@@ -11,16 +11,19 @@ EXPORTS.mozilla.dom += [
     'FallbackEncoding.h',
     'TextDecoder.h',
     'TextEncoder.h',
 ]
 
 SOURCES += [
     'EncodingUtils.cpp',
     'FallbackEncoding.cpp',
+]
+
+UNIFIED_SOURCES += [
     'TextDecoder.cpp',
     'TextEncoder.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'gklayout'
 LOCAL_INCLUDES += [
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -106,45 +106,16 @@ END_INDEXEDDB_NAMESPACE
 
 namespace {
 
 mozilla::StaticRefPtr<IndexedDatabaseManager> gInstance;
 
 mozilla::Atomic<int32_t> gInitialized(0);
 mozilla::Atomic<int32_t> gClosed(0);
 
-// See ResolveConstructors below.
-struct ConstructorInfo {
-  const char* const name;
-  JS::Handle<JSObject*> (* const resolve)(JSContext*, JS::Handle<JSObject*>,
-                                          bool);
-  jsid id;
-};
-
-ConstructorInfo gConstructorInfo[] = {
-
-#define BINDING_ENTRY(_name) \
-  { #_name, _name##Binding::GetConstructorObject, JSID_VOID },
-
-  BINDING_ENTRY(IDBCursor)
-  BINDING_ENTRY(IDBCursorWithValue)
-  BINDING_ENTRY(IDBDatabase)
-  BINDING_ENTRY(IDBFactory)
-  BINDING_ENTRY(IDBFileHandle)
-  BINDING_ENTRY(IDBIndex)
-  BINDING_ENTRY(IDBKeyRange)
-  BINDING_ENTRY(IDBObjectStore)
-  BINDING_ENTRY(IDBOpenDBRequest)
-  BINDING_ENTRY(IDBRequest)
-  BINDING_ENTRY(IDBTransaction)
-  BINDING_ENTRY(IDBVersionChangeEvent)
-
-#undef BINDING_ENTRY
-};
-
 class AsyncDeleteFileRunnable MOZ_FINAL : public nsIRunnable
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
   AsyncDeleteFileRunnable(FileManager* aFileManager, int64_t aFileId);
 
@@ -202,63 +173,16 @@ struct MOZ_STACK_CLASS InvalidateInfo
   InvalidateInfo(PersistenceType aPersistenceType, const nsACString& aPattern)
   : persistenceType(aPersistenceType), pattern(aPattern)
   { }
 
   PersistenceType persistenceType;
   const nsACString& pattern;
 };
 
-bool
-GetIndexedDB(JSContext* aCx, JS::Handle<JSObject*> aGlobal,
-             JS::MutableHandle<JS::Value> aResult)
-{
-  MOZ_ASSERT(nsContentUtils::IsCallerChrome(), "Only for chrome!");
-  MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
-             "Not a global object!");
-
-  nsRefPtr<IDBFactory> factory;
-  if (NS_FAILED(IDBFactory::Create(aCx, aGlobal, nullptr,
-                                   getter_AddRefs(factory)))) {
-    return false;
-  }
-
-  MOZ_ASSERT(factory, "This should never fail for chrome!");
-
-  return !!WrapNewBindingObject(aCx, aGlobal, factory, aResult);
-}
-
-bool
-IndexedDBLazyGetter(JSContext* aCx, JS::Handle<JSObject*> aGlobal,
-                    JS::Handle<jsid> aId, JS::MutableHandle<JS::Value> aVp)
-{
-  MOZ_ASSERT(nsContentUtils::IsCallerChrome(), "Only for chrome!");
-  MOZ_ASSERT(JSID_IS_STRING(aId), "Bad id!");
-  MOZ_ASSERT(JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(aId), IDB_STR),
-             "Bad id!");
-
-  JS::Rooted<JSObject*> global(aCx, CheckedUnwrap(aGlobal,
-                                                  /* stopAtOuter = */ false));
-  NS_ENSURE_TRUE(global, false);
-  NS_ENSURE_TRUE(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL, false);
-
-  JS::Rooted<JS::Value> indexedDB(aCx);
-  if (!GetIndexedDB(aCx, global, &indexedDB)) {
-    return false;
-  }
-
-  if (!JS_DefinePropertyById(aCx, global, aId, indexedDB, nullptr, nullptr,
-                             JSPROP_ENUMERATE)) {
-    return false;
-  }
-
-  aVp.set(indexedDB);
-  return true;
-}
-
 } // anonymous namespace
 
 IndexedDatabaseManager::IndexedDatabaseManager()
 : mFileMutex("IndexedDatabaseManager.mFileMutex")
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
@@ -477,65 +401,59 @@ IndexedDatabaseManager::TabContextMayAcc
                                                 aContext.IsBrowserElement(),
                                                 pattern);
 
   return PatternMatchesOrigin(pattern, aOrigin);
 }
 
 // static
 bool
-IndexedDatabaseManager::DefineConstructors(JSContext* aCx,
-                                           JS::Handle<JSObject*> aGlobal)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  for (uint32_t i = 0; i < mozilla::ArrayLength(gConstructorInfo); i++) {
-    if (!gConstructorInfo[i].resolve(aCx, aGlobal, true)) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-// static
-bool
-IndexedDatabaseManager::DefineIndexedDBGetter(JSContext* aCx,
-                                              JS::Handle<JSObject*> aGlobal)
+IndexedDatabaseManager::DefineIndexedDB(JSContext* aCx,
+                                        JS::Handle<JSObject*> aGlobal)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(nsContentUtils::IsCallerChrome(), "Only for chrome!");
   MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
              "Passed object is not a global object!");
 
+  if (!IDBCursorBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBCursorWithValueBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBDatabaseBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBFactoryBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBFileHandleBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBIndexBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBKeyRangeBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBObjectStoreBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBOpenDBRequestBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBRequestBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBTransactionBinding::GetConstructorObject(aCx, aGlobal) ||
+      !IDBVersionChangeEventBinding::GetConstructorObject(aCx, aGlobal))
+  {
+    return false;
+  }
+
+  nsRefPtr<IDBFactory> factory;
+  if (NS_FAILED(IDBFactory::Create(aCx, aGlobal, nullptr,
+                                   getter_AddRefs(factory)))) {
+    return false;
+  }
+
+  MOZ_ASSERT(factory, "This should never fail for chrome!");
+
   JS::Rooted<JS::Value> indexedDB(aCx);
-  if (!GetIndexedDB(aCx, aGlobal, &indexedDB)) {
+  if (!WrapNewBindingObject(aCx, aGlobal, factory, &indexedDB)) {
     return false;
   }
 
   return JS_DefineProperty(aCx, aGlobal, IDB_STR, indexedDB, nullptr, nullptr,
                            JSPROP_ENUMERATE);
 }
 
 // static
 bool
-IndexedDatabaseManager::DefineIndexedDBLazyGetter(JSContext* aCx,
-                                                  JS::Handle<JSObject*> aGlobal)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(nsContentUtils::IsCallerChrome(), "Only for chrome!");
-  MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
-             "Passed object is not a global object!");
-
-  return JS_DefineProperty(aCx, aGlobal, IDB_STR, JSVAL_VOID,
-                           IndexedDBLazyGetter, nullptr, 0);
-}
-
-// static
-bool
 IndexedDatabaseManager::IsClosed()
 {
   return !!gClosed;
 }
 
 #ifdef DEBUG
 // static
 bool
@@ -744,17 +662,17 @@ IndexedDatabaseManager::InitWindowless(c
     return NS_ERROR_FAILURE;
   }
 
   if (hasIndexedDB) {
     NS_WARNING("Passed object already has an 'indexedDB' property!");
     return NS_ERROR_FAILURE;
   }
 
-  if (!DefineConstructors(aCx, global) || !DefineIndexedDBGetter(aCx, global)) {
+  if (!DefineIndexedDB(aCx, global)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic,
@@ -996,54 +914,8 @@ GetFileReferencesHelper::Run()
   mozilla::MutexAutoLock lock(mMutex);
   NS_ASSERTION(mWaiting, "Huh?!");
 
   mWaiting = false;
   mCondVar.Notify();
 
   return NS_OK;
 }
-
-BEGIN_INDEXEDDB_NAMESPACE
-
-bool
-ResolveConstructors(JSContext* aCx, JS::Handle<JSObject*> aObj,
-                    JS::Handle<jsid> aId, JS::MutableHandle<JSObject*> aObjp)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // The first time this function is called we need to intern all the strings we
-  // care about.
-  if (JSID_IS_VOID(gConstructorInfo[0].id)) {
-    for (uint32_t i = 0; i < mozilla::ArrayLength(gConstructorInfo); i++) {
-      JS::Rooted<JSString*> str(aCx,
-                                JS_InternString(aCx, gConstructorInfo[i].name));
-      if (!str) {
-        NS_WARNING("Failed to intern string!");
-        while (i) {
-          gConstructorInfo[--i].id = JSID_VOID;
-        }
-        return false;
-      }
-      gConstructorInfo[i].id = INTERNED_STRING_TO_JSID(aCx, str);
-    }
-  }
-
-  // Now resolve.
-  for (uint32_t i = 0; i < mozilla::ArrayLength(gConstructorInfo); i++) {
-    if (gConstructorInfo[i].id == aId) {
-      JS::Rooted<JSObject*> constructor(aCx,
-        gConstructorInfo[i].resolve(aCx, aObj, true));
-      if (!constructor) {
-        return false;
-      }
-
-      aObjp.set(aObj);
-      return true;
-    }
-  }
-
-  // Not resolved.
-  aObjp.set(nullptr);
-  return true;
-}
-
-END_INDEXEDDB_NAMESPACE
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -135,23 +135,17 @@ public:
   FireWindowOnError(nsPIDOMWindow* aOwner,
                     nsEventChainPostVisitor& aVisitor);
 
   static bool
   TabContextMayAccessOrigin(const mozilla::dom::TabContext& aContext,
                             const nsACString& aOrigin);
 
   static bool
-  DefineConstructors(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
-
-  static bool
-  DefineIndexedDBGetter(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
-
-  static bool
-  DefineIndexedDBLazyGetter(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
+  DefineIndexedDB(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
 
 private:
   IndexedDatabaseManager();
   ~IndexedDatabaseManager();
 
   nsresult
   Init();
 
@@ -171,15 +165,11 @@ private:
   // It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt
   // and FileInfo.mSliceRefCnt
   mozilla::Mutex mFileMutex;
 
   static bool sIsMainProcess;
   static mozilla::Atomic<int32_t> sLowDiskSpaceMode;
 };
 
-bool
-ResolveConstructors(JSContext* aCx, JS::Handle<JSObject*> aObj,
-                    JS::Handle<jsid> aId, JS::MutableHandle<JSObject*> aObjp);
-
 END_INDEXEDDB_NAMESPACE
 
 #endif /* mozilla_dom_indexeddb_indexeddatabasemanager_h__ */
--- a/dom/indexedDB/test/chrome.ini
+++ b/dom/indexedDB/test/chrome.ini
@@ -1,4 +1,5 @@
 [DEFAULT]
 support-files = chromeHelpers.js
 
-[test_globalObjects.xul]
+[test_globalObjects_chrome.xul]
+[test_globalObjects_other.xul]
--- a/dom/indexedDB/test/chromeHelpers.js
+++ b/dom/indexedDB/test/chromeHelpers.js
@@ -2,21 +2,25 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 const { 'classes': Cc, 'interfaces': Ci, 'utils': Cu } = Components;
 
 let testGenerator = testSteps();
 
-function runTest()
-{
-  SimpleTest.waitForExplicitFinish();
+if (!window.runTest) {
+  window.runTest = function()
+  {
+    Cu.importGlobalProperties(["indexedDB"]);
 
-  testGenerator.next();
+    SimpleTest.waitForExplicitFinish();
+
+    testGenerator.next();
+  }
 }
 
 function finishTest()
 {
   SimpleTest.executeSoon(function() {
     testGenerator.close();
     SimpleTest.finish();
   });
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -55,17 +55,17 @@ support-files =
 [test_file_resurrection_transaction_abort.html]
 [test_file_sharing.html]
 [test_file_transaction_abort.html]
 [test_filehandle_quota.html]
 [test_filehandle_serialization.html]
 [test_filehandle_store_snapshot.html]
 [test_getAll.html]
 [test_get_filehandle.html]
-[test_globalObjects.html]
+[test_globalObjects_content.html]
 [test_global_data.html]
 [test_index_empty_keyPath.html]
 [test_index_getAll.html]
 [test_index_getAllObjects.html]
 [test_index_object_cursors.html]
 [test_index_update_delete.html]
 [test_indexes.html]
 [test_indexes_bad_values.html]
rename from dom/indexedDB/test/test_globalObjects.xul
rename to dom/indexedDB/test/test_globalObjects_chrome.xul
--- a/dom/indexedDB/test/test_globalObjects.xul
+++ b/dom/indexedDB/test/test_globalObjects_chrome.xul
@@ -23,45 +23,16 @@
     var request = indexedDB.open(name, 1);
     request.onerror = errorHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield undefined;
 
     let db = event.target.result;
     ok(db, "Got database");
 
-    // Test for IDBKeyRange and indexedDB availability in bootstrap files.
-    let test = Cc["@mozilla.org/dom/indexeddb/GlobalObjectsComponent;1"].
-               createInstance(Ci.nsISupports).wrappedJSObject;
-    test.ok = ok;
-    test.finishTest = continueToNextStep;
-    test.runTest();
-    yield undefined;
-
-    Cu.import("resource://gre/modules/AddonManager.jsm");
-    AddonManager.getAddonByID("indexedDB-test@mozilla.org",
-                              grabEventAndContinueHandler);
-    let addon = yield undefined;
-    addon.uninstall();
-
-    Cu.import("resource://gre/modules/Services.jsm");
-    for each (var stage in [ "install", "startup", "shutdown", "uninstall" ]) {
-      for each (var symbol in [ "IDBKeyRange", "indexedDB" ]) {
-        let pref;
-        try {
-          pref = Services.prefs.getBoolPref("indexeddbtest.bootstrap." + stage +
-                                            "." + symbol);
-        }
-        catch(ex) {
-          pref = false;
-        }
-        ok(pref, "Symbol '" + symbol + "' present during '" + stage + "'");
-      }
-    }
-
     finishTest();
     yield undefined;
   }
   ]]>
   </script>
 
   <script type="text/javascript;version=1.7" src="chromeHelpers.js"></script>
 
rename from dom/indexedDB/test/test_globalObjects.html
rename to dom/indexedDB/test/test_globalObjects_content.html
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_globalObjects_other.xul
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<window title="Mozilla Bug 832883"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="runTest();">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <script type="application/javascript;version=1.7">
+  <![CDATA[
+  function testSteps() {
+    // Test for IDBKeyRange and indexedDB availability in bootstrap files.
+    let test = Cc["@mozilla.org/dom/indexeddb/GlobalObjectsComponent;1"].
+               createInstance(Ci.nsISupports).wrappedJSObject;
+    test.ok = ok;
+    test.finishTest = continueToNextStep;
+    test.runTest();
+    yield undefined;
+
+    Cu.import("resource://gre/modules/AddonManager.jsm");
+    AddonManager.getAddonByID("indexedDB-test@mozilla.org",
+                              grabEventAndContinueHandler);
+    let addon = yield undefined;
+    addon.uninstall();
+
+    Cu.import("resource://gre/modules/Services.jsm");
+    for each (var stage in [ "install", "startup", "shutdown", "uninstall" ]) {
+      for each (var symbol in [ "IDBKeyRange", "indexedDB" ]) {
+        let pref;
+        try {
+          pref = Services.prefs.getBoolPref("indexeddbtest.bootstrap." + stage +
+                                            "." + symbol);
+        }
+        catch(ex) {
+          pref = false;
+        }
+        ok(pref, "Symbol '" + symbol + "' present during '" + stage + "'");
+      }
+    }
+
+    finishTest();
+    yield undefined;
+  }
+
+  window.runTest = function() {
+    SimpleTest.waitForExplicitFinish();
+
+    testGenerator.next();
+  }
+  ]]>
+  </script>
+
+  <script type="text/javascript;version=1.7" src="chromeHelpers.js"></script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=832883"
+     target="_blank">Mozilla Bug 832883</a>
+  </body>
+</window>
--- a/dom/indexedDB/test/unit/GlobalObjectsChild.js
+++ b/dom/indexedDB/test/unit/GlobalObjectsChild.js
@@ -13,16 +13,18 @@ function finishTest()
   do_execute_soon(function() {
     do_test_finished();
   });
 }
 
 function run_test() {
   const name = "Splendid Test";
 
+  Cu.importGlobalProperties(["indexedDB"]);
+
   do_test_pending();
 
   let keyRange = IDBKeyRange.only(42);
   ok(keyRange, "Got keyRange");
 
   let request = indexedDB.open(name, 1);
   request.onerror = function(event) {
     ok(false, "indexedDB error, '" + event.target.error.name + "'");
--- a/dom/indexedDB/test/unit/GlobalObjectsComponent.js
+++ b/dom/indexedDB/test/unit/GlobalObjectsComponent.js
@@ -1,14 +1,17 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.importGlobalProperties(["indexedDB"]);
 
 function GlobalObjectsComponent() {
   this.wrappedJSObject = this;
 }
 
 GlobalObjectsComponent.prototype =
 {
   classID: Components.ID("{949ebf50-e0da-44b9-8335-cbfd4febfdcc}"),
--- a/dom/indexedDB/test/unit/GlobalObjectsModule.jsm
+++ b/dom/indexedDB/test/unit/GlobalObjectsModule.jsm
@@ -1,13 +1,15 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+Components.utils.importGlobalProperties(["indexedDB"]);
+
 this.EXPORTED_SYMBOLS = [
   "GlobalObjectsModule"
 ];
 
 this.GlobalObjectsModule = function GlobalObjectsModule() {
 }
 
 GlobalObjectsModule.prototype = {
--- a/dom/indexedDB/test/unit/head.js
+++ b/dom/indexedDB/test/unit/head.js
@@ -33,25 +33,29 @@ function todo(condition, name, diag) {
 function info(name, message) {
   do_print(name);
 }
 
 function run_test() {
   runTest();
 };
 
-function runTest()
-{
-  // XPCShell does not get a profile by default.
-  do_get_profile();
+if (!this.runTest) {
+  this.runTest = function()
+  {
+    // XPCShell does not get a profile by default.
+    do_get_profile();
 
-  enableExperimental();
+    enableExperimental();
+
+    Cu.importGlobalProperties(["indexedDB"]);
 
-  do_test_pending();
-  testGenerator.next();
+    do_test_pending();
+    testGenerator.next();
+  }
 }
 
 function finishTest()
 {
   resetExperimental();
   SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
                                                "free");
 
--- a/dom/indexedDB/test/unit/mochitest.ini
+++ b/dom/indexedDB/test/unit/mochitest.ini
@@ -13,18 +13,19 @@
 [test_create_objectStore.js]
 [test_cursor_mutation.js]
 [test_cursor_update_updates_indexes.js]
 [test_cursors.js]
 [test_deleteDatabase.js]
 [test_deleteDatabase_interactions.js]
 [test_event_source.js]
 [test_getAll.js]
-[test_globalObjects.js]
 [test_globalObjects_ipc.js]
+[test_globalObjects_other.js]
+[test_globalObjects_xpc.js]
 [test_global_data.js]
 [test_index_empty_keyPath.js]
 [test_index_getAll.js]
 [test_index_getAllObjects.js]
 [test_index_object_cursors.js]
 [test_index_update_delete.js]
 [test_indexes.js]
 [test_indexes_bad_values.js]
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_globalObjects_other.js
@@ -0,0 +1,60 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function testSteps()
+{
+  let ioService =
+    Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+
+  function getSpec(filename) {
+    let file = do_get_file(filename);
+    let uri = ioService.newFileURI(file);
+    return uri.spec;
+  }
+
+  // Test for IDBKeyRange and indexedDB availability in JS modules.
+  Cu.import(getSpec("GlobalObjectsModule.jsm"));
+  let test = new GlobalObjectsModule();
+  test.ok = ok;
+  test.finishTest = continueToNextStep;
+  test.runTest();
+  yield undefined;
+
+  // Test for IDBKeyRange and indexedDB availability in JS components.
+  do_load_manifest("GlobalObjectsComponent.manifest");
+  test = Cc["@mozilla.org/dom/indexeddb/GlobalObjectsComponent;1"].
+         createInstance(Ci.nsISupports).wrappedJSObject;
+  test.ok = ok;
+  test.finishTest = continueToNextStep;
+  test.runTest();
+  yield undefined;
+
+  // Test for IDBKeyRange and indexedDB availability in JS sandboxes.
+  let principal = Cc["@mozilla.org/systemprincipal;1"].
+                  createInstance(Ci.nsIPrincipal);
+  let sandbox = new Cu.Sandbox(principal,
+                               { wantGlobalProperties: ["indexedDB"] });
+  sandbox.__SCRIPT_URI_SPEC__ = getSpec("GlobalObjectsSandbox.js");
+  Cu.evalInSandbox(
+    "Components.classes['@mozilla.org/moz/jssubscript-loader;1'] \
+               .createInstance(Components.interfaces.mozIJSSubScriptLoader) \
+               .loadSubScript(__SCRIPT_URI_SPEC__);", sandbox, "1.7");
+  sandbox.ok = ok;
+  sandbox.finishTest = continueToNextStep;
+  Cu.evalInSandbox("runTest();", sandbox);
+  yield undefined;
+
+  finishTest();
+  yield undefined;
+}
+
+this.runTest = function() {
+  do_get_profile();
+
+  do_test_pending();
+  testGenerator.next();
+}
rename from dom/indexedDB/test/unit/test_globalObjects.js
rename to dom/indexedDB/test/unit/test_globalObjects_xpc.js
--- a/dom/indexedDB/test/unit/test_globalObjects.js
+++ b/dom/indexedDB/test/unit/test_globalObjects_xpc.js
@@ -4,64 +4,23 @@
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = "Splendid Test";
 
-  let ioService =
-    Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
-
-  function getSpec(filename) {
-    let file = do_get_file(filename);
-    let uri = ioService.newFileURI(file);
-    return uri.spec;
-  }
-
   // Test for IDBKeyRange and indexedDB availability in xpcshell.
   let keyRange = IDBKeyRange.only(42);
   ok(keyRange, "Got keyRange");
 
   let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield undefined;
 
   let db = event.target.result;
   ok(db, "Got database");
 
-  // Test for IDBKeyRange and indexedDB availability in JS modules.
-  Cu.import(getSpec("GlobalObjectsModule.jsm"));
-  let test = new GlobalObjectsModule();
-  test.ok = ok;
-  test.finishTest = continueToNextStep;
-  test.runTest();
-  yield undefined;
-
-  // Test for IDBKeyRange and indexedDB availability in JS components.
-  do_load_manifest("GlobalObjectsComponent.manifest");
-  test = Cc["@mozilla.org/dom/indexeddb/GlobalObjectsComponent;1"].
-         createInstance(Ci.nsISupports).wrappedJSObject;
-  test.ok = ok;
-  test.finishTest = continueToNextStep;
-  test.runTest();
-  yield undefined;
-
-  // Test for IDBKeyRange and indexedDB availability in JS sandboxes.
-  let principal = Cc["@mozilla.org/systemprincipal;1"].
-                  createInstance(Ci.nsIPrincipal);
-  let sandbox = new Cu.Sandbox(principal,
-                               { wantGlobalProperties: ["indexedDB"] });
-  sandbox.__SCRIPT_URI_SPEC__ = getSpec("GlobalObjectsSandbox.js");
-  Cu.evalInSandbox(
-    "Components.classes['@mozilla.org/moz/jssubscript-loader;1'] \
-               .createInstance(Components.interfaces.mozIJSSubScriptLoader) \
-               .loadSubScript(__SCRIPT_URI_SPEC__);", sandbox, "1.7");
-  sandbox.ok = ok;
-  sandbox.finishTest = continueToNextStep;
-  Cu.evalInSandbox("runTest();", sandbox);
-  yield undefined;
-
   finishTest();
   yield undefined;
 }
--- a/dom/indexedDB/test/unit/xpcshell.ini
+++ b/dom/indexedDB/test/unit/xpcshell.ini
@@ -23,20 +23,21 @@ support-files =
 [test_create_objectStore.js]
 [test_cursor_mutation.js]
 [test_cursor_update_updates_indexes.js]
 [test_cursors.js]
 [test_deleteDatabase.js]
 [test_deleteDatabase_interactions.js]
 [test_event_source.js]
 [test_getAll.js]
-[test_globalObjects.js]
 [test_globalObjects_ipc.js]
 # FIXME/bug 575918: out-of-process xpcshell is broken on OS X
 skip-if = os == "mac" || os == "android"
+[test_globalObjects_other.js]
+[test_globalObjects_xpc.js]
 [test_global_data.js]
 [test_index_empty_keyPath.js]
 [test_index_getAll.js]
 [test_index_getAllObjects.js]
 [test_index_object_cursors.js]
 [test_index_update_delete.js]
 [test_indexes.js]
 [test_indexes_bad_values.js]
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -221,19 +221,22 @@ parent:
 
     PContentDialog(uint32_t aType, nsCString aName, nsCString aFeatures,
                    int32_t[] aIntParams, nsString[] aStringParams);
 
     /**
      * Create a layout frame (encapsulating a remote layer tree) for
      * the page that is currently loaded in the <browser>.
      */
-    sync PRenderFrame()
+    sync PRenderFrame();
+
+    sync InitRenderFrame(PRenderFrame aFrame)
         returns (ScrollingBehavior scrolling,
-                 TextureFactoryIdentifier textureFactoryIdentifier, uint64_t layersId);
+                 TextureFactoryIdentifier textureFactoryIdentifier, uint64_t layersId,
+                 bool success);
 
     /** 
      * Starts an offline application cache update.
      * @param manifestURI
      *   URI of the manifest to fetch, the application cache group ID
      * @param documentURI
      *   URI of the document that referred the manifest
      * @param stickDocument
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2161,19 +2161,17 @@ TabChild::RecvDestroy()
 bool
 TabChild::RecvSetUpdateHitRegion(const bool& aEnabled)
 {
     mUpdateHitRegion = aEnabled;
     return true;
 }
 
 PRenderFrameChild*
-TabChild::AllocPRenderFrameChild(ScrollingBehavior* aScrolling,
-                            TextureFactoryIdentifier* aTextureFactoryIdentifier,
-                            uint64_t* aLayersId)
+TabChild::AllocPRenderFrameChild()
 {
     return new RenderFrameChild();
 }
 
 bool
 TabChild::DeallocPRenderFrameChild(PRenderFrameChild* aFrame)
 {
     delete aFrame;
@@ -2221,21 +2219,27 @@ TabChild::InitTabChildGlobal(FrameScript
 }
 
 bool
 TabChild::InitRenderingState()
 {
     static_cast<PuppetWidget*>(mWidget.get())->InitIMEState();
 
     uint64_t id;
+    bool success;
     RenderFrameChild* remoteFrame =
-        static_cast<RenderFrameChild*>(SendPRenderFrameConstructor(
-                                         &mScrolling, &mTextureFactoryIdentifier, &id));
+        static_cast<RenderFrameChild*>(SendPRenderFrameConstructor());
     if (!remoteFrame) {
+        NS_WARNING("failed to construct RenderFrame");
+        return false;
+    }
+    SendInitRenderFrame(remoteFrame, &mScrolling, &mTextureFactoryIdentifier, &id, &success);
+    if (!success) {
       NS_WARNING("failed to construct RenderFrame");
+      PRenderFrameChild::Send__delete__(remoteFrame);
       return false;
     }
 
     PLayerTransactionChild* shadowManager = nullptr;
     if (id != 0) {
         // Pushing layers transactions directly to a separate
         // compositor context.
         PCompositorChild* compositorChild = CompositorChild::Get();
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -357,19 +357,17 @@ public:
     GetFrom(nsIDOMWindow* aWindow)
     {
       nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
       nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
       return GetFrom(docShell);
     }
 
 protected:
-    virtual PRenderFrameChild* AllocPRenderFrameChild(ScrollingBehavior* aScrolling,
-                                                      TextureFactoryIdentifier* aTextureFactoryIdentifier,
-                                                      uint64_t* aLayersId) MOZ_OVERRIDE;
+    virtual PRenderFrameChild* AllocPRenderFrameChild() MOZ_OVERRIDE;
     virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) MOZ_OVERRIDE;
     virtual bool RecvDestroy() MOZ_OVERRIDE;
     virtual bool RecvSetUpdateHitRegion(const bool& aEnabled) MOZ_OVERRIDE;
 
     nsEventStatus DispatchWidgetEvent(WidgetGUIEvent& event);
 
     virtual PIndexedDBChild* AllocPIndexedDBChild(const nsCString& aGroup,
                                                   const nsCString& aASCIIOrigin,
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1440,33 +1440,46 @@ TabParent::HandleDelayedDialogs()
   }
   if (ShouldDelayDialogs() && mDelayedDialogs.Length()) {
     nsContentUtils::DispatchTrustedEvent(mFrameElement->OwnerDoc(), mFrameElement,
                                          NS_LITERAL_STRING("MozDelayedModalDialog"),
                                          true, true);
   }
 }
 
-PRenderFrameParent*
-TabParent::AllocPRenderFrameParent(ScrollingBehavior* aScrolling,
-                                   TextureFactoryIdentifier* aTextureFactoryIdentifier,
-                                   uint64_t* aLayersId)
+bool
+TabParent::RecvInitRenderFrame(PRenderFrameParent* aFrame,
+                               ScrollingBehavior* aScrolling,
+                               TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                               uint64_t* aLayersId,
+                               bool *aSuccess)
 {
-  MOZ_ASSERT(ManagedPRenderFrameParent().IsEmpty());
+  *aScrolling = UseAsyncPanZoom() ? ASYNC_PAN_ZOOM : DEFAULT_SCROLLING;
+  *aTextureFactoryIdentifier = TextureFactoryIdentifier();
+  *aLayersId = 0;
 
   nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
   if (!frameLoader) {
-    NS_WARNING("Can't allocate graphics resources, aborting subprocess");
-    return nullptr;
+    NS_WARNING("Can't allocate graphics resources. May already be shutting down.");
+    *aSuccess = false;
+    return true;
   }
 
-  *aScrolling = UseAsyncPanZoom() ? ASYNC_PAN_ZOOM : DEFAULT_SCROLLING;
-  return new RenderFrameParent(frameLoader,
-                               *aScrolling,
-                               aTextureFactoryIdentifier, aLayersId);
+  static_cast<RenderFrameParent*>(aFrame)->Init(frameLoader, *aScrolling,
+                                                aTextureFactoryIdentifier, aLayersId);
+
+  *aSuccess = true;
+  return true;
+}
+
+PRenderFrameParent*
+TabParent::AllocPRenderFrameParent()
+{
+  MOZ_ASSERT(ManagedPRenderFrameParent().IsEmpty());
+  return new RenderFrameParent();
 }
 
 bool
 TabParent::DeallocPRenderFrameParent(PRenderFrameParent* aFrame)
 {
   delete aFrame;
   return true;
 }
@@ -1595,20 +1608,17 @@ TabParent::RecvBrowserFrameOpenWindow(PB
   BrowserElementParent::OpenWindowResult opened =
     BrowserElementParent::OpenWindowOOP(static_cast<TabParent*>(aOpener),
                                         this, aURL, aName, aFeatures);
   *aOutWindowOpened = (opened != BrowserElementParent::OPEN_WINDOW_CANCELLED);
   return true;
 }
 
 bool
-TabParent::RecvPRenderFrameConstructor(PRenderFrameParent* actor,
-                                       ScrollingBehavior* scrolling,
-                                       TextureFactoryIdentifier* factoryIdentifier,
-                                       uint64_t* layersId)
+TabParent::RecvPRenderFrameConstructor(PRenderFrameParent* actor)
 {
   RenderFrameParent* rfp = GetRenderFrame();
   if (mDimensions != nsIntSize() && rfp) {
     rfp->NotifyDimensionsChanged(ScreenIntSize::FromUnknownSize(
       gfx::IntSize(mDimensions.width, mDimensions.height)));
   }
 
   return true;
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -104,20 +104,22 @@ public:
      * capturer.
      */
     bool TryCapture(const WidgetGUIEvent& aEvent);
 
     void Destroy();
 
     virtual bool RecvMoveFocus(const bool& aForward);
     virtual bool RecvEvent(const RemoteDOMEvent& aEvent);
-    virtual bool RecvPRenderFrameConstructor(PRenderFrameParent* actor,
-                                             ScrollingBehavior* scrolling,
-                                             TextureFactoryIdentifier* identifier,
-                                             uint64_t* layersId);
+    virtual bool RecvPRenderFrameConstructor(PRenderFrameParent* aFrame);
+    virtual bool RecvInitRenderFrame(PRenderFrameParent* aFrame,
+                                     ScrollingBehavior* aScrolling,
+                                     TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                     uint64_t* aLayersId,
+                                     bool *aSuccess);
     virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
                                             const nsString& aURL,
                                             const nsString& aName,
                                             const nsString& aFeatures,
                                             bool* aOutWindowOpened);
     virtual bool AnswerCreateWindow(PBrowserParent** retval);
     virtual bool RecvSyncMessage(const nsString& aMessage,
                                  const ClonedMessageData& aData,
@@ -302,19 +304,17 @@ protected:
       nsCString mFeatures;
       nsCOMPtr<nsIDialogParamBlock> mParams;
     };
     InfallibleTArray<DelayedDialogData*> mDelayedDialogs;
 
     bool ShouldDelayDialogs();
     bool AllowContentIME();
 
-    virtual PRenderFrameParent* AllocPRenderFrameParent(ScrollingBehavior* aScrolling,
-                                                        TextureFactoryIdentifier* aTextureFactoryIdentifier,
-                                                        uint64_t* aLayersId) MOZ_OVERRIDE;
+    virtual PRenderFrameParent* AllocPRenderFrameParent() MOZ_OVERRIDE;
     virtual bool DeallocPRenderFrameParent(PRenderFrameParent* aFrame) MOZ_OVERRIDE;
 
     // IME
     static TabParent *mIMETabParent;
     nsString mIMECacheText;
     uint32_t mIMESelectionAnchor;
     uint32_t mIMESelectionFocus;
     bool mIMEComposing;
--- a/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
+++ b/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
@@ -4,16 +4,17 @@
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
+Cu.importGlobalProperties(["indexedDB"]);
 
 var RIL = {};
 Cu.import("resource://gre/modules/ril_consts.js", RIL);
 
 const RIL_MOBILEMESSAGEDATABASESERVICE_CONTRACTID =
   "@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1";
 const RIL_MOBILEMESSAGEDATABASESERVICE_CID =
   Components.ID("{29785f90-6b5b-11e2-9201-3b280170b2ec}");
--- a/dom/network/src/NetworkStatsDB.jsm
+++ b/dom/network/src/NetworkStatsDB.jsm
@@ -8,16 +8,17 @@ this.EXPORTED_SYMBOLS = ['NetworkStatsDB
 
 const DEBUG = false;
 function debug(s) { dump("-*- NetworkStatsDB: " + s + "\n"); }
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
+Cu.importGlobalProperties(["indexedDB"]);
 
 const DB_NAME = "net_stats";
 const DB_VERSION = 3;
 const STORE_NAME = "net_stats";
 
 // Constant defining the maximum values allowed per interface. If more, older
 // will be erased.
 const VALUES_MAX_LENGTH = 6 * 30;
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -6,27 +6,30 @@
 
 #include "mozilla/dom/Promise.h"
 
 #include "jsfriendapi.h"
 #include "mozilla/dom/OwningNonNull.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/Preferences.h"
 #include "PromiseCallback.h"
+#include "PromiseNativeHandler.h"
 #include "nsContentUtils.h"
 #include "nsPIDOMWindow.h"
 #include "WorkerPrivate.h"
 #include "nsJSPrincipals.h"
 #include "nsJSUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsJSEnvironment.h"
 
 namespace mozilla {
 namespace dom {
 
+NS_IMPL_ISUPPORTS0(PromiseNativeHandler)
+
 // PromiseTask
 
 // This class processes the promise's callbacks with promise's result.
 class PromiseTask MOZ_FINAL : public nsRunnable
 {
 public:
   PromiseTask(Promise* aPromise)
     : mPromise(aPromise)
@@ -186,35 +189,35 @@ Promise::EnabledForScope(JSContext* aCx,
 
   nsIPrincipal* prin = nsContentUtils::GetSubjectPrincipal();
   return nsContentUtils::IsSystemPrincipal(prin) ||
     prin->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
 }
 
 void
 Promise::MaybeResolve(JSContext* aCx,
-                      const Optional<JS::Handle<JS::Value> >& aValue)
+                      JS::Handle<JS::Value> aValue)
 {
   MaybeResolveInternal(aCx, aValue);
 }
 
 void
 Promise::MaybeReject(JSContext* aCx,
-                     const Optional<JS::Handle<JS::Value> >& aValue)
+                     JS::Handle<JS::Value> aValue)
 {
   MaybeRejectInternal(aCx, aValue);
 }
 
 static void
 EnterCompartment(Maybe<JSAutoCompartment>& aAc, JSContext* aCx,
-                 const Optional<JS::Handle<JS::Value> >& aValue)
+                 JS::Handle<JS::Value> aValue)
 {
   // FIXME Bug 878849
-  if (aValue.WasPassed() && aValue.Value().isObject()) {
-    JS::Rooted<JSObject*> rooted(aCx, &aValue.Value().toObject());
+  if (aValue.isObject()) {
+    JS::Rooted<JSObject*> rooted(aCx, &aValue.toObject());
     aAc.construct(aCx, rooted);
   }
 }
 
 enum {
   SLOT_PROMISE = 0,
   SLOT_TASK
 };
@@ -229,28 +232,23 @@ Promise::JSCallback(JSContext *aCx, unsi
                                                         SLOT_PROMISE));
   MOZ_ASSERT(v.isObject());
 
   Promise* promise;
   if (NS_FAILED(UNWRAP_OBJECT(Promise, aCx, &v.toObject(), promise))) {
     return Throw(aCx, NS_ERROR_UNEXPECTED);
   }
 
-  Optional<JS::Handle<JS::Value> > value(aCx);
-  if (aArgc) {
-    value.Value() = args[0];
-  }
-
   v = js::GetFunctionNativeReserved(&args.callee(), SLOT_TASK);
   PromiseCallback::Task task = static_cast<PromiseCallback::Task>(v.toInt32());
 
   if (task == PromiseCallback::Resolve) {
-    promise->MaybeResolveInternal(aCx, value);
+    promise->MaybeResolveInternal(aCx, args.get(0));
   } else {
-    promise->MaybeRejectInternal(aCx, value);
+    promise->MaybeRejectInternal(aCx, args.get(0));
   }
 
   return true;
 }
 
 /* static */ JSObject*
 Promise::CreateFunction(JSContext* aCx, JSObject* aParent, Promise* aPromise,
                         int32_t aTask)
@@ -304,18 +302,18 @@ Promise::Constructor(const GlobalObject&
     return nullptr;
   }
 
   aInit.Call(promise, resolveFunc, rejectFunc, aRv,
              CallbackObject::eRethrowExceptions);
   aRv.WouldReportJSException();
 
   if (aRv.IsJSException()) {
-    Optional<JS::Handle<JS::Value> > value(cx);
-    aRv.StealJSException(cx, &value.Value());
+    JS::Rooted<JS::Value> value(cx);
+    aRv.StealJSException(cx, &value);
 
     Maybe<JSAutoCompartment> ac;
     EnterCompartment(ac, cx, value);
     promise->MaybeRejectInternal(cx, value);
   }
 
   return promise.forget();
 }
@@ -327,35 +325,33 @@ Promise::Resolve(const GlobalObject& aGl
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<Promise> promise = new Promise(window);
 
-  Optional<JS::Handle<JS::Value> > value(aCx, aValue);
-  promise->MaybeResolveInternal(aCx, value);
+  promise->MaybeResolveInternal(aCx, aValue);
   return promise.forget();
 }
 
 /* static */ already_AddRefed<Promise>
 Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx,
                 JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<Promise> promise = new Promise(window);
 
-  Optional<JS::Handle<JS::Value> > value(aCx, aValue);
-  promise->MaybeRejectInternal(aCx, value);
+  promise->MaybeRejectInternal(aCx, aValue);
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 Promise::Then(const Optional<OwningNonNull<AnyCallback> >& aResolveCallback,
               const Optional<OwningNonNull<AnyCallback> >& aRejectCallback)
 {
   nsRefPtr<Promise> promise = new Promise(GetParentObject());
@@ -382,16 +378,28 @@ Promise::Then(const Optional<OwningNonNu
 already_AddRefed<Promise>
 Promise::Catch(const Optional<OwningNonNull<AnyCallback> >& aRejectCallback)
 {
   Optional<OwningNonNull<AnyCallback> > resolveCb;
   return Then(resolveCb, aRejectCallback);
 }
 
 void
+Promise::AppendNativeHandler(PromiseNativeHandler* aRunnable)
+{
+  nsRefPtr<PromiseCallback> resolveCb =
+  new NativePromiseCallback(aRunnable, Resolved);
+
+  nsRefPtr<PromiseCallback> rejectCb =
+  new NativePromiseCallback(aRunnable, Rejected);
+
+  AppendCallbacks(resolveCb, rejectCb);
+}
+
+void
 Promise::AppendCallbacks(PromiseCallback* aResolveCallback,
                          PromiseCallback* aRejectCallback)
 {
   if (aResolveCallback) {
     mResolveCallbacks.AppendElement(aResolveCallback);
   }
 
   if (aRejectCallback) {
@@ -415,18 +423,19 @@ Promise::RunTask()
   MOZ_ASSERT(mState != Pending);
 
   nsTArray<nsRefPtr<PromiseCallback> > callbacks;
   callbacks.SwapElements(mState == Resolved ? mResolveCallbacks
                                             : mRejectCallbacks);
   mResolveCallbacks.Clear();
   mRejectCallbacks.Clear();
 
-  JSAutoRequest ar(nsContentUtils::GetSafeJSContext());
-  Optional<JS::Handle<JS::Value> > value(nsContentUtils::GetSafeJSContext(), mResult);
+  JSContext* cx = nsContentUtils::GetSafeJSContext();
+  JSAutoRequest ar(cx);
+  JS::Rooted<JS::Value> value(cx, mResult);
 
   for (uint32_t i = 0; i < callbacks.Length(); ++i) {
     callbacks[i]->Call(value);
   }
 }
 
 void
 Promise::MaybeReportRejected()
@@ -452,79 +461,77 @@ Promise::MaybeReportRejected()
                            report,
                            nullptr,
                            nsContentUtils::IsSystemPrincipal(principal),
                            win));
 }
 
 void
 Promise::MaybeResolveInternal(JSContext* aCx,
-                              const Optional<JS::Handle<JS::Value> >& aValue,
+                              JS::Handle<JS::Value> aValue,
                               PromiseTaskSync aAsynchronous)
 {
   if (mResolvePending) {
     return;
   }
 
   ResolveInternal(aCx, aValue, aAsynchronous);
 }
 
 void
 Promise::MaybeRejectInternal(JSContext* aCx,
-                             const Optional<JS::Handle<JS::Value> >& aValue,
+                             JS::Handle<JS::Value> aValue,
                              PromiseTaskSync aAsynchronous)
 {
   if (mResolvePending) {
     return;
   }
 
   RejectInternal(aCx, aValue, aAsynchronous);
 }
 
 void
 Promise::ResolveInternal(JSContext* aCx,
-                         const Optional<JS::Handle<JS::Value> >& aValue,
+                         JS::Handle<JS::Value> aValue,
                          PromiseTaskSync aAsynchronous)
 {
   mResolvePending = true;
 
   // TODO: Bug 879245 - Then-able objects
-  if (aValue.WasPassed() && aValue.Value().isObject()) {
-    JS::Rooted<JSObject*> valueObj(aCx, &aValue.Value().toObject());
+  if (aValue.isObject()) {
+    JS::Rooted<JSObject*> valueObj(aCx, &aValue.toObject());
     Promise* nextPromise;
     nsresult rv = UNWRAP_OBJECT(Promise, aCx, valueObj, nextPromise);
 
     if (NS_SUCCEEDED(rv)) {
       nsRefPtr<PromiseCallback> resolveCb = new ResolvePromiseCallback(this);
       nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(this);
       nextPromise->AppendCallbacks(resolveCb, rejectCb);
       return;
     }
   }
 
   // If the synchronous flag is set, process our resolve callbacks with
   // value. Otherwise, the synchronous flag is unset, queue a task to process
   // own resolve callbacks with value. Otherwise, the synchronous flag is
   // unset, queue a task to process our resolve callbacks with value.
-  RunResolveTask(aValue.WasPassed() ? aValue.Value() : JS::UndefinedHandleValue,
-                 Resolved, aAsynchronous);
+  RunResolveTask(aValue, Resolved, aAsynchronous);
 }
 
 void
 Promise::RejectInternal(JSContext* aCx,
-                        const Optional<JS::Handle<JS::Value> >& aValue,
+                        JS::Handle<JS::Value> aValue,
                         PromiseTaskSync aAsynchronous)
 {
   mResolvePending = true;
 
   // If the synchronous flag is set, process our reject callbacks with
   // value. Otherwise, the synchronous flag is unset, queue a task to process
   // promise's reject callbacks with value.
-  RunResolveTask(aValue.WasPassed() ? aValue.Value() : JS::UndefinedHandleValue,
-                 Rejected, aAsynchronous);
+  RunResolveTask(aValue, Rejected, aAsynchronous);
 }
 
 void
 Promise::RunResolveTask(JS::Handle<JS::Value> aValue,
                         PromiseState aState,
                         PromiseTaskSync aAsynchronous)
 {
   // If the synchronous flag is unset, queue a task to process our
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -15,23 +15,25 @@
 #include "nsWrapperCache.h"
 #include "nsAutoPtr.h"
 #include "nsPIDOMWindow.h"
 #include "js/TypeDecls.h"
 
 namespace mozilla {
 namespace dom {
 
-class PromiseInit;
+class AnyCallback;
 class PromiseCallback;
-class AnyCallback;
+class PromiseInit;
+class PromiseNativeHandler;
 
 class Promise MOZ_FINAL : public nsISupports,
                           public nsWrapperCache
 {
+  friend class NativePromiseCallback;
   friend class PromiseTask;
   friend class PromiseResolverTask;
   friend class ResolvePromiseCallback;
   friend class RejectPromiseCallback;
   friend class WrapperPromiseCallback;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -39,19 +41,19 @@ public:
 
   Promise(nsPIDOMWindow* aWindow);
   ~Promise();
 
   static bool PrefEnabled();
   static bool EnabledForScope(JSContext* aCx, JSObject* /* unused */);
 
   void MaybeResolve(JSContext* aCx,
-                    const Optional<JS::Handle<JS::Value> >& aValue);
+                    JS::Handle<JS::Value> aValue);
   void MaybeReject(JSContext* aCx,
-                   const Optional<JS::Handle<JS::Value> >& aValue);
+                   JS::Handle<JS::Value> aValue);
 
   // WebIDL
 
   nsPIDOMWindow* GetParentObject() const
   {
     return mWindow;
   }
 
@@ -73,16 +75,18 @@ public:
   already_AddRefed<Promise>
   Then(const Optional<OwningNonNull<AnyCallback> >& aResolveCallback,
        const Optional<OwningNonNull<AnyCallback> >& aRejectCallback);
 
 
   already_AddRefed<Promise>
   Catch(const Optional<OwningNonNull<AnyCallback> >& aRejectCallback);
 
+  void AppendNativeHandler(PromiseNativeHandler* aRunnable);
+
 private:
   enum PromiseState {
     Pending,
     Resolved,
     Rejected
   };
 
   enum PromiseTaskSync {
@@ -115,28 +119,28 @@ private:
   void AppendCallbacks(PromiseCallback* aResolveCallback,
                        PromiseCallback* aRejectCallback);
 
   // If we have been rejected and our mResult is a JS exception,
   // report it to the error console.
   void MaybeReportRejected();
 
   void MaybeResolveInternal(JSContext* aCx,
-                            const Optional<JS::Handle<JS::Value> >& aValue,
+                            JS::Handle<JS::Value> aValue,
                             PromiseTaskSync aSync = AsyncTask);
   void MaybeRejectInternal(JSContext* aCx,
-                           const Optional<JS::Handle<JS::Value> >& aValue,
+                           JS::Handle<JS::Value> aValue,
                            PromiseTaskSync aSync = AsyncTask);
 
   void ResolveInternal(JSContext* aCx,
-                       const Optional<JS::Handle<JS::Value> >& aValue,
+                       JS::Handle<JS::Value> aValue,
                        PromiseTaskSync aSync = AsyncTask);
 
   void RejectInternal(JSContext* aCx,
-                      const Optional<JS::Handle<JS::Value> >& aValue,
+                      JS::Handle<JS::Value> aValue,
                       PromiseTaskSync aSync = AsyncTask);
 
   // Static methods for the PromiseInit functions.
   static bool
   JSCallback(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
   static JSObject*
   CreateFunction(JSContext* aCx, JSObject* aParent, Promise* aPromise,
                 int32_t aTask);
--- a/dom/promise/PromiseCallback.cpp
+++ b/dom/promise/PromiseCallback.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* 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 "PromiseCallback.h"
 #include "mozilla/dom/Promise.h"
+#include "mozilla/dom/PromiseNativeHandler.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PromiseCallback)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(PromiseCallback)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PromiseCallback)
@@ -32,21 +33,21 @@ PromiseCallback::PromiseCallback()
 
 PromiseCallback::~PromiseCallback()
 {
   MOZ_COUNT_DTOR(PromiseCallback);
 }
 
 static void
 EnterCompartment(Maybe<JSAutoCompartment>& aAc, JSContext* aCx,
-                 const Optional<JS::Handle<JS::Value> >& aValue)
+                 JS::Handle<JS::Value> aValue)
 {
   // FIXME Bug 878849
-  if (aValue.WasPassed() && aValue.Value().isObject()) {
-    JS::Rooted<JSObject*> rooted(aCx, &aValue.Value().toObject());
+  if (aValue.isObject()) {
+    JS::Rooted<JSObject*> rooted(aCx, &aValue.toObject());
     aAc.construct(aCx, rooted);
   }
 }
 
 // ResolvePromiseCallback
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED_1(ResolvePromiseCallback,
                                      PromiseCallback,
@@ -66,17 +67,17 @@ ResolvePromiseCallback::ResolvePromiseCa
 }
 
 ResolvePromiseCallback::~ResolvePromiseCallback()
 {
   MOZ_COUNT_DTOR(ResolvePromiseCallback);
 }
 
 void
-ResolvePromiseCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
+ResolvePromiseCallback::Call(JS::Handle<JS::Value> aValue)
 {
   // Run resolver's algorithm with value and the synchronous flag set.
   AutoJSContext cx;
   Maybe<JSAutoCompartment> ac;
   EnterCompartment(ac, cx, aValue);
 
   mPromise->ResolveInternal(cx, aValue, Promise::SyncTask);
 }
@@ -101,17 +102,17 @@ RejectPromiseCallback::RejectPromiseCall
 }
 
 RejectPromiseCallback::~RejectPromiseCallback()
 {
   MOZ_COUNT_DTOR(RejectPromiseCallback);
 }
 
 void
-RejectPromiseCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
+RejectPromiseCallback::Call(JS::Handle<JS::Value> aValue)
 {
   // Run resolver's algorithm with value and the synchronous flag set.
   AutoJSContext cx;
   Maybe<JSAutoCompartment> ac;
   EnterCompartment(ac, cx, aValue);
 
   mPromise->RejectInternal(cx, aValue, Promise::SyncTask);
 }
@@ -138,35 +139,35 @@ WrapperPromiseCallback::WrapperPromiseCa
 }
 
 WrapperPromiseCallback::~WrapperPromiseCallback()
 {
   MOZ_COUNT_DTOR(WrapperPromiseCallback);
 }
 
 void
-WrapperPromiseCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
+WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
 {
   AutoJSContext cx;
   Maybe<JSAutoCompartment> ac;
   EnterCompartment(ac, cx, aValue);
 
   ErrorResult rv;
 
   // If invoking callback threw an exception, run resolver's reject with the
   // thrown exception as argument and the synchronous flag set.
-  Optional<JS::Handle<JS::Value> > value(cx,
+  JS::Rooted<JS::Value> value(cx,
     mCallback->Call(mNextPromise->GetParentObject(), aValue, rv,
                     CallbackObject::eRethrowExceptions));
 
   rv.WouldReportJSException();
 
   if (rv.Failed() && rv.IsJSException()) {
-    Optional<JS::Handle<JS::Value> > value(cx);
-    rv.StealJSException(cx, &value.Value());
+    JS::Rooted<JS::Value> value(cx);
+    rv.StealJSException(cx, &value);
 
     Maybe<JSAutoCompartment> ac2;
     EnterCompartment(ac2, cx, value);
     mNextPromise->RejectInternal(cx, value, Promise::SyncTask);
     return;
   }
 
   // Otherwise, run resolver's resolve with value and the synchronous flag
@@ -198,22 +199,63 @@ SimpleWrapperPromiseCallback::SimpleWrap
 }
 
 SimpleWrapperPromiseCallback::~SimpleWrapperPromiseCallback()
 {
   MOZ_COUNT_DTOR(SimpleWrapperPromiseCallback);
 }
 
 void
-SimpleWrapperPromiseCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
+SimpleWrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
 {
   ErrorResult rv;
   mCallback->Call(mPromise, aValue, rv);
 }
 
+// NativePromiseCallback
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED_1(NativePromiseCallback,
+                                     PromiseCallback, mHandler)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(NativePromiseCallback)
+NS_INTERFACE_MAP_END_INHERITING(PromiseCallback)
+
+NS_IMPL_ADDREF_INHERITED(NativePromiseCallback, PromiseCallback)
+NS_IMPL_RELEASE_INHERITED(NativePromiseCallback, PromiseCallback)
+
+NativePromiseCallback::NativePromiseCallback(PromiseNativeHandler* aHandler,
+                                             Promise::PromiseState aState)
+  : mHandler(aHandler)
+  , mState(aState)
+{
+  MOZ_ASSERT(aHandler);
+  MOZ_COUNT_CTOR(NativePromiseCallback);
+}
+
+NativePromiseCallback::~NativePromiseCallback()
+{
+  MOZ_COUNT_DTOR(NativePromiseCallback);
+}
+
+void
+NativePromiseCallback::Call(JS::Handle<JS::Value> aValue)
+{
+  if (mState == Promise::Resolved) {
+    mHandler->ResolvedCallback(aValue);
+    return;
+  }
+
+  if (mState == Promise::Rejected) {
+    mHandler->RejectedCallback(aValue);
+    return;
+  }
+
+  NS_NOTREACHED("huh?");
+}
+
 /* static */ PromiseCallback*
 PromiseCallback::Factory(Promise* aNextPromise, AnyCallback* aCallback,
                          Task aTask)
 {
   MOZ_ASSERT(aNextPromise);
 
   // If we have a callback and a next resolver, we have to exec the callback and
   // then propagate the return value to the next resolver->resolve().
--- a/dom/promise/PromiseCallback.h
+++ b/dom/promise/PromiseCallback.h
@@ -19,17 +19,17 @@ class PromiseCallback : public nsISuppor
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(PromiseCallback)
 
   PromiseCallback();
   virtual ~PromiseCallback();
 
-  virtual void Call(const Optional<JS::Handle<JS::Value> >& aValue) = 0;
+  virtual void Call(JS::Handle<JS::Value> aValue) = 0;
 
   enum Task {
     Resolve,
     Reject
   };
 
   // This factory returns a PromiseCallback object with refcount of 0.
   static PromiseCallback*
@@ -41,17 +41,17 @@ public:
 // aNextPromise->RejectFunction() if the JS Callback throws.
 class WrapperPromiseCallback MOZ_FINAL : public PromiseCallback
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WrapperPromiseCallback,
                                            PromiseCallback)
 
-  void Call(const Optional<JS::Handle<JS::Value> >& aValue) MOZ_OVERRIDE;
+  void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
 
   WrapperPromiseCallback(Promise* aNextPromise, AnyCallback* aCallback);
   ~WrapperPromiseCallback();
 
 private:
   nsRefPtr<Promise> mNextPromise;
   nsRefPtr<AnyCallback> mCallback;
 };
@@ -59,17 +59,17 @@ private:
 // SimpleWrapperPromiseCallback execs a JS Callback with a value.
 class SimpleWrapperPromiseCallback MOZ_FINAL : public PromiseCallback
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SimpleWrapperPromiseCallback,
                                            PromiseCallback)
 
-  void Call(const Optional<JS::Handle<JS::Value> >& aValue) MOZ_OVERRIDE;
+  void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
 
   SimpleWrapperPromiseCallback(Promise* aPromise,
                                AnyCallback* aCallback);
   ~SimpleWrapperPromiseCallback();
 
 private:
   nsRefPtr<Promise> mPromise;
   nsRefPtr<AnyCallback> mCallback;
@@ -79,17 +79,17 @@ private:
 // received by Call().
 class ResolvePromiseCallback MOZ_FINAL : public PromiseCallback
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ResolvePromiseCallback,
                                            PromiseCallback)
 
-  void Call(const Optional<JS::Handle<JS::Value> >& aValue) MOZ_OVERRIDE;
+  void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
 
   ResolvePromiseCallback(Promise* aPromise);
   ~ResolvePromiseCallback();
 
 private:
   nsRefPtr<Promise> mPromise;
 };
 
@@ -97,21 +97,40 @@ private:
 // received by Call().
 class RejectPromiseCallback MOZ_FINAL : public PromiseCallback
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(RejectPromiseCallback,
                                            PromiseCallback)
 
-  void Call(const Optional<JS::Handle<JS::Value> >& aValue) MOZ_OVERRIDE;
+  void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
 
   RejectPromiseCallback(Promise* aPromise);
   ~RejectPromiseCallback();
 
 private:
   nsRefPtr<Promise> mPromise;
 };
 
+// NativePromiseCallback wraps a NativePromiseHandler.
+class NativePromiseCallback MOZ_FINAL : public PromiseCallback
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(NativePromiseCallback,
+                                           PromiseCallback)
+
+  void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
+
+  NativePromiseCallback(PromiseNativeHandler* aHandler,
+                        Promise::PromiseState aState);
+  ~NativePromiseCallback();
+
+private:
+  nsRefPtr<PromiseNativeHandler> mHandler;
+  Promise::PromiseState mState;
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PromiseCallback_h
new file mode 100644
--- /dev/null
+++ b/dom/promise/PromiseNativeHandler.h
@@ -0,0 +1,39 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this file,
+* You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PromiseNativeHandler_h
+#define mozilla_dom_PromiseNativeHandler_h
+
+#include "nsISupports.h"
+
+namespace mozilla {
+namespace dom {
+
+/*
+ * PromiseNativeHandler allows C++ to react to a Promise being rejected/resolved.
+ * A PromiseNativeHandler can be appended to a Promise using
+ * Promise::AppendNativeHandler().
+ */
+class PromiseNativeHandler : public nsISupports
+{
+public:
+  // NS_IMPL_ISUPPORTS0 in Promise.cpp.
+  NS_DECL_ISUPPORTS
+
+  virtual ~PromiseNativeHandler()
+  { }
+
+  virtual void
+  ResolvedCallback(JS::Handle<JS::Value> aValue) = 0;
+
+  virtual void
+  RejectedCallback(JS::Handle<JS::Value> aValue) = 0;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PromiseNativeHandler_h
--- a/dom/promise/moz.build
+++ b/dom/promise/moz.build
@@ -5,16 +5,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 TEST_DIRS += ['tests']
 
 XPIDL_MODULE = 'dom_promise'
 
 EXPORTS.mozilla.dom += [
     'Promise.h',
+    'PromiseNativeHandler.h'
 ]
 
 SOURCES += [
     'Promise.cpp',
     'PromiseCallback.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
--- a/dom/push/src/PushService.jsm
+++ b/dom/push/src/PushService.jsm
@@ -18,16 +18,17 @@ const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
+Cu.importGlobalProperties(["indexedDB"]);
 
 XPCOMUtils.defineLazyModuleGetter(this, "AlarmService",
                                   "resource://gre/modules/AlarmService.jsm");
 
 this.EXPORTED_SYMBOLS = ["PushService"];
 
 const prefs = new Preferences("services.push.");
 // Set debug first so that all debugging actually works.
--- a/dom/src/notification/Notification.cpp
+++ b/dom/src/notification/Notification.cpp
@@ -82,18 +82,17 @@ public:
       return NS_ERROR_FAILURE;
     }
     return NS_OK;
   }
 
   NS_IMETHOD Done(JSContext* aCx)
   {
     JSAutoCompartment ac(aCx, mGlobal);
-    Optional<JS::Handle<JS::Value>> result(aCx,
-                                           JS::ObjectValue(*mNotifications));
+    JS::Rooted<JS::Value> result(aCx, JS::ObjectValue(*mNotifications));
     mPromise->MaybeResolve(aCx, result);
     return NS_OK;
   }
 
 private:
   ~NotificationStorageCallback()
   {
     DropData();
--- a/dom/webidl/Promise.webidl
+++ b/dom/webidl/Promise.webidl
@@ -6,17 +6,17 @@
  * The origin of this IDL file is
  * http://dom.spec.whatwg.org/#promises
  */
 
 // TODO We use object instead Function.  There is an open issue on WebIDL to
 // have different types for "platform-provided function" and "user-provided
 // function"; for now, we just use "object".
 callback PromiseInit = void (object resolve, object reject);
-callback AnyCallback = any (optional any value);
+callback AnyCallback = any (any value);
 
 [Func="mozilla::dom::Promise::EnabledForScope", Constructor(PromiseInit init)]
 interface Promise {
   // TODO bug 875289 - static Promise fulfill(any value);
 
   // Disable the static methods when the interface object is supposed to be
   // disabled, just in case some code decides to walk over to .constructor from
   // the proto of a promise object or someone screws up and manages to create a
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -30,17 +30,17 @@
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Util.h"
-#include <Navigator.h>
+#include "mozilla/dom/Navigator.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
 #include "nsLayoutStatics.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsTraceRefcnt.h"
@@ -800,16 +800,18 @@ CreateJSContextForWorker(WorkerPrivate* 
   for (uint32_t index = 0; index < ArrayLength(gcSettings); index++) {
     const JSSettings::JSGCSetting& setting = gcSettings[index];
     if (setting.IsSet()) {
       NS_ASSERTION(setting.value, "Can't handle 0 values!");
       JS_SetGCParameter(aRuntime, setting.key, setting.value);
     }
   }
 
+  JS_SetIsWorkerRuntime(aRuntime);
+
   JS_SetNativeStackQuota(aRuntime, WORKER_CONTEXT_NATIVE_STACK_LIMIT);
 
   // Security policy:
   static JSSecurityCallbacks securityCallbacks = {
     nullptr,
     ContentSecurityPolicyAllows
   };
   JS_SetSecurityCallbacks(aRuntime, &securityCallbacks);
--- a/gfx/angle/README.mozilla
+++ b/gfx/angle/README.mozilla
@@ -44,16 +44,20 @@ In this order:
     Fixes TCompiler::Init to treat `resources.ArrayIndexClampingStrategy`
     as a request for the default strategy.
 
   angle-tex-pool-default.patch:
     Don't use D3DPOOL_MANAGED on D3D9. Just use D3DPOOL_DEFAULT.
 
   angle-build-unified.patch:
     Fixes required to make angle compile in unified mode
+    Note that a different version of this patch was upstreamed, so the next time that
+    Angle is updated this patch can be discarded.  See:
+    https://chromium.googlesource.com/angle/angle/+/0dd3b3ff66cdc50882125d21e60112d5161279b4
+    https://chromium.googlesource.com/angle/angle/+/0685fbde65a3e90d8d4d4a6c72f2cc1771617fd0
 
 In addition to these patches, the Makefile.in and moz.build build files are ours,
 they're not present in upsteam ANGLE. Therefore, changes made to the build files
 should not be stored in the local .patch files.
 
 
 == How to do a clean-slate upgrade ==
 1.  Backup our moz-specific files:
--- a/gfx/cairo/cairo/src/moz.build
+++ b/gfx/cairo/cairo/src/moz.build
@@ -109,24 +109,28 @@ if CONFIG['MOZ_ENABLE_CAIRO_FT']:
         'cairo-ft.h',
     ]
     SOURCES += [
         'cairo-ft-font.c',
         'cairo-type1-subset.c',
     ]
 
 SOURCES += [
+    'cairo-bentley-ottmann-rectangular.c', # redefinition of '_cairo_bo_trap'
+    'cairo-bentley-ottmann-rectilinear.c', # redefinition of '_cairo_bo_trap'
+    'cairo-bentley-ottmann.c', # redefinition of '_cairo_bo_trap'
+    'cairo-surface-wrapper.c', #  redefinition of '_copy_transformed_pattern'
+]
+
+UNIFIED_SOURCES += [
     'cairo-analysis-surface.c',
     'cairo-arc.c',
     'cairo-array.c',
     'cairo-atomic.c',
     'cairo-base64-stream.c',
-    'cairo-bentley-ottmann-rectangular.c',
-    'cairo-bentley-ottmann-rectilinear.c',
-    'cairo-bentley-ottmann.c',
     'cairo-botor-scan-converter.c',
     'cairo-boxes.c',
     'cairo-cache.c',
     'cairo-clip.c',
     'cairo-color.c',
     'cairo-composite-rectangles.c',
     'cairo-debug.c',
     'cairo-device.c',
@@ -168,17 +172,16 @@ SOURCES += [
     'cairo-spans.c',
     'cairo-spline.c',
     'cairo-stroke-style.c',
     'cairo-surface-clipper.c',
     'cairo-surface-fallback.c',
     'cairo-surface-offset.c',
     'cairo-surface-snapshot.c',
     'cairo-surface-subsurface.c',
-    'cairo-surface-wrapper.c',
     'cairo-surface.c',
     'cairo-tee-surface.c',
     'cairo-tor-scan-converter.c',
     'cairo-toy-font-face.c',
     'cairo-traps.c',
     'cairo-unicode.c',
     'cairo-user-font.c',
     'cairo-version.c',
--- a/gfx/harfbuzz/src/moz.build
+++ b/gfx/harfbuzz/src/moz.build
@@ -18,34 +18,37 @@ EXPORTS.harfbuzz += [
     'hb-shape-plan.h',
     'hb-shape.h',
     'hb-unicode.h',
     'hb-version.h',
     'hb.h',
 ]
 
 SOURCES += [
+    'hb-common.cc', # error: use of undeclared identifier 'strdup'
+    'hb-ot-shape-complex-indic.cc', # error: redefinition of enumerator 'INIT'
+    'hb-ot-shape-complex-sea.cc', # error: redefinition of 'basic_features'
+    'hb-ot-shape.cc', # error: functions that differ only in their return type cannot be overloaded
+]
+
+UNIFIED_SOURCES += [
     'hb-blob.cc',
     'hb-buffer.cc',
-    'hb-common.cc',
     'hb-face.cc',
     'hb-fallback-shape.cc',
     'hb-font.cc',
     'hb-ot-layout.cc',
     'hb-ot-map.cc',
     'hb-ot-shape-complex-arabic.cc',
     'hb-ot-shape-complex-default.cc',
     'hb-ot-shape-complex-indic-table.cc',
-    'hb-ot-shape-complex-indic.cc',
     'hb-ot-shape-complex-myanmar.cc',
-    'hb-ot-shape-complex-sea.cc',
     'hb-ot-shape-complex-thai.cc',
     'hb-ot-shape-fallback.cc',
     'hb-ot-shape-normalize.cc',
-    'hb-ot-shape.cc',
     'hb-ot-tag.cc',
     'hb-set.cc',
     'hb-shape-plan.cc',
     'hb-shape.cc',
     'hb-shaper.cc',
     'hb-unicode.cc',
     'hb-warning.cc',
 ]
--- a/gfx/layers/ThebesLayerBuffer.h
+++ b/gfx/layers/ThebesLayerBuffer.h
@@ -57,26 +57,30 @@ public:
 
   RotatedBuffer(gfxASurface* aBuffer, gfxASurface* aBufferOnWhite,
                 const nsIntRect& aBufferRect,
                 const nsIntPoint& aBufferRotation)
     : mBuffer(aBuffer)
     , mBufferOnWhite(aBufferOnWhite)
     , mBufferRect(aBufferRect)
     , mBufferRotation(aBufferRotation)
+    , mDidSelfCopy(false)
   { }
   RotatedBuffer(gfx::DrawTarget* aDTBuffer, gfx::DrawTarget* aDTBufferOnWhite,
                 const nsIntRect& aBufferRect,
                 const nsIntPoint& aBufferRotation)
     : mDTBuffer(aDTBuffer)
     , mDTBufferOnWhite(aDTBufferOnWhite)
     , mBufferRect(aBufferRect)
     , mBufferRotation(aBufferRotation)
+    , mDidSelfCopy(false)
   { }
-  RotatedBuffer() { }
+  RotatedBuffer()
+    : mDidSelfCopy(false)
+  { }
 
   /*
    * Which buffer should be drawn to/read from.
    */
   enum ContextSource {
     BUFFER_BLACK, // The normal buffer, or buffer with black background when using component alpha.
     BUFFER_WHITE, // The buffer with white background, only valid with component alpha.
     BUFFER_BOTH // The combined black/white buffers, only valid for writing operations, not reading.
--- a/hal/linux/udev.h
+++ b/hal/linux/udev.h
@@ -25,23 +25,37 @@ struct udev_monitor;
 class udev_lib {
  public:
   udev_lib() : lib(nullptr),
                udev(nullptr) {
     // Be careful about ABI compat! 0 -> 1 didn't change any
     // symbols this code relies on, per:
     // https://lists.fedoraproject.org/pipermail/devel/2012-June/168227.html
     const char* lib_names[] = {"libudev.so.0", "libudev.so.1"};
+    // Check whether a library is already loaded so we don't load two
+    // conflicting libs.
     for (unsigned i = 0; i < ArrayLength(lib_names); i++) {
-      lib = dlopen(lib_names[i], RTLD_LAZY | RTLD_GLOBAL);
-      if (lib)
+      lib = dlopen(lib_names[i], RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL);
+      if (lib) {
         break;
+      }
     }
-    if (lib && LoadSymbols())
+    // If nothing loads the first time through, it means no version of libudev
+    // was already loaded.
+    if (!lib) {
+      for (unsigned i = 0; i < ArrayLength(lib_names); i++) {
+        lib = dlopen(lib_names[i], RTLD_LAZY | RTLD_GLOBAL);
+        if (lib) {
+          break;
+        }
+      }
+    }
+    if (lib && LoadSymbols()) {
       udev = udev_new();
+    }
   }
 
   ~udev_lib() {
     if (udev) {
       udev_unref(udev);
     }
 
     if (lib) {
--- a/ipc/chromium/src/third_party/libevent/README.mozilla
+++ b/ipc/chromium/src/third_party/libevent/README.mozilla
@@ -7,8 +7,9 @@ mac/event2/event-config.h
 android/event2/event-config.h
 
 These files are taken from libevent-2.0.21-stable built on the development environment indicated by the first path component. You have to run "./configure" and "make" to get all of the pre-processing done. The file can then be found in "include/event2/".
 
 2. This is ugly, prepare yourself. OS X has a weird problem with how the "TAILQ_END(head)" is used, causing a linking error. Just replace all use of the "TAILQ_END(head)" macro with "NULL".
 
 3. Apply "add mac-arc4random-buf.patch", which removes some bad OS X compatibility code. This will allow libevent to compile on all supported versions of OS X.
 
+4. Apply "openbsd-no-arc4random_addrandom.patch", which fixes the build on OpenBSD (which doesnt provide arc4random_addrandom anymore, see #931354)
--- a/ipc/chromium/src/third_party/libevent/evutil_rand.c
+++ b/ipc/chromium/src/third_party/libevent/evutil_rand.c
@@ -134,15 +134,16 @@ ev_arc4random_buf(void *buf, size_t n)
 #endif /* } !_EVENT_HAVE_ARC4RANDOM */
 
 void
 evutil_secure_rng_get_bytes(void *buf, size_t n)
 {
 	ev_arc4random_buf(buf, n);
 }
 
+#ifndef __OpenBSD__
 void
 evutil_secure_rng_add_bytes(const char *buf, size_t n)
 {
 	arc4random_addrandom((unsigned char*)buf,
 	    n>(size_t)INT_MAX ? INT_MAX : (int)n);
 }
-
+#endif
--- a/ipc/chromium/src/third_party/libevent/include/event2/util.h
+++ b/ipc/chromium/src/third_party/libevent/include/event2/util.h
@@ -667,29 +667,31 @@ void evutil_secure_rng_get_bytes(void *b
  * numbers.  You only need to call it if (a) you want to double-check
  * that one of the seeding methods did succeed, or (b) you plan to drop
  * the capability to seed (by chrooting, or dropping capabilities, or
  * whatever), and you want to make sure that seeding happens before your
  * program loses the ability to do it.
  */
 int evutil_secure_rng_init(void);
 
+#ifndef __OpenBSD__
 /** Seed the random number generator with extra random bytes.
 
     You should almost never need to call this function; it should be
     sufficient to invoke evutil_secure_rng_init(), or let Libevent take
     care of calling evutil_secure_rng_init() on its own.
 
     If you call this function as a _replacement_ for the regular
     entropy sources, then you need to be sure that your input
     contains a fairly large amount of strong entropy.  Doing so is
     notoriously hard: most people who try get it wrong.  Watch out!
 
     @param dat a buffer full of a strong source of random numbers
     @param datlen the number of bytes to read from datlen
  */
 void evutil_secure_rng_add_bytes(const char *dat, size_t datlen);
+#endif
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif /* _EVUTIL_H_ */
new file mode 100644
--- /dev/null
+++ b/ipc/chromium/src/third_party/libevent/openbsd-no-arc4random_addrandom.patch
@@ -0,0 +1,64 @@
+# HG changeset patch
+# User Landry Breuil <landry@openbsd.org>
+# Date 1384377262 -3600
+#      Wed Nov 13 22:14:22 2013 +0100
+# Node ID 026009b2c94dc564413d48df824fabec98e2c631
+# Parent  f2b602a5ee27b2e05abe84ea7cbd358dadd2ffb5
+Bug 931354: OpenBSD doesn't provide arc4random_addrandom anymore, fix libevent accordingly by #ifndef'ing out its caller evutil_secure_rng_add_bytes() (which isnt called anywhere) r=joshaas
+
+diff --git a/ipc/chromium/src/third_party/libevent/evutil_rand.c b/ipc/chromium/src/third_party/libevent/evutil_rand.c
+--- a/ipc/chromium/src/third_party/libevent/evutil_rand.c
++++ b/ipc/chromium/src/third_party/libevent/evutil_rand.c
+@@ -134,15 +134,16 @@ ev_arc4random_buf(void *buf, size_t n)
+ #endif /* } !_EVENT_HAVE_ARC4RANDOM */
+ 
+ void
+ evutil_secure_rng_get_bytes(void *buf, size_t n)
+ {
+ 	ev_arc4random_buf(buf, n);
+ }
+ 
++#ifndef __OpenBSD__
+ void
+ evutil_secure_rng_add_bytes(const char *buf, size_t n)
+ {
+ 	arc4random_addrandom((unsigned char*)buf,
+ 	    n>(size_t)INT_MAX ? INT_MAX : (int)n);
+ }
+-
++#endif
+diff --git a/ipc/chromium/src/third_party/libevent/include/event2/util.h b/ipc/chromium/src/third_party/libevent/include/event2/util.h
+--- a/ipc/chromium/src/third_party/libevent/include/event2/util.h
++++ b/ipc/chromium/src/third_party/libevent/include/event2/util.h
+@@ -667,29 +667,31 @@ void evutil_secure_rng_get_bytes(void *b
+  * numbers.  You only need to call it if (a) you want to double-check
+  * that one of the seeding methods did succeed, or (b) you plan to drop
+  * the capability to seed (by chrooting, or dropping capabilities, or
+  * whatever), and you want to make sure that seeding happens before your
+  * program loses the ability to do it.
+  */
+ int evutil_secure_rng_init(void);
+ 
++#ifndef __OpenBSD__
+ /** Seed the random number generator with extra random bytes.
+ 
+     You should almost never need to call this function; it should be
+     sufficient to invoke evutil_secure_rng_init(), or let Libevent take
+     care of calling evutil_secure_rng_init() on its own.
+ 
+     If you call this function as a _replacement_ for the regular
+     entropy sources, then you need to be sure that your input
+     contains a fairly large amount of strong entropy.  Doing so is
+     notoriously hard: most people who try get it wrong.  Watch out!
+ 
+     @param dat a buffer full of a strong source of random numbers
+     @param datlen the number of bytes to read from datlen
+  */
+ void evutil_secure_rng_add_bytes(const char *dat, size_t datlen);
++#endif
+ 
+ #ifdef __cplusplus
+ }
+ #endif
+ 
+ #endif /* _EVUTIL_H_ */
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -214,17 +214,16 @@ def p_TranslationUnit(p):
 
     # The "canonical" namespace of the tu, what it's considered to be
     # in for the purposes of C++: |#include "foo/bar/TU.h"|
     if tu.protocol:
         assert tu.filetype == 'protocol'
         tu.namespaces = tu.protocol.namespaces
         tu.name = tu.protocol.name
     else:
-        print tu.filetype
         assert tu.filetype == 'header'
         # There's not really a canonical "thing" in headers.  So
         # somewhat arbitrarily use the namespace of the last
         # interesting thing that was declared.
         for thing in reversed(tu.structsAndUnions):
             tu.namespaces = thing.namespaces
             break
 
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -132,30 +132,31 @@ class HashMap
     //    assert(p->key == 3);
     //    char val = p->value;
     typedef typename Impl::AddPtr AddPtr;
     AddPtr lookupForAdd(const Lookup &l) const {
         return impl.lookupForAdd(l);
     }
 
     template<typename KeyInput, typename ValueInput>
-    bool add(AddPtr &p, const KeyInput &k, const ValueInput &v) {
-        Entry e(k, v);
-        return impl.add(p, mozilla::OldMove(e));
+    bool add(AddPtr &p, KeyInput &&k, ValueInput &&v) {
+        Entry e(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
+        return impl.add(p, mozilla::Move(e));
     }
 
-    bool add(AddPtr &p, const Key &k) {
-        Entry e(k, Value());
-        return impl.add(p, mozilla::OldMove(e));
+    template<typename KeyInput>
+    bool add(AddPtr &p, KeyInput &&k) {
+        Entry e(mozilla::Forward<KeyInput>(k), Value());
+        return impl.add(p, mozilla::Move(e));
     }
 
     template<typename KeyInput, typename ValueInput>
-    bool relookupOrAdd(AddPtr &p, const KeyInput &k, const ValueInput &v) {
-        Entry e(k, v);
-        return impl.relookupOrAdd(p, k, mozilla::OldMove(e));
+    bool relookupOrAdd(AddPtr &p, KeyInput &&k, ValueInput &&v) {
+        Entry e(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
+        return impl.relookupOrAdd(p, e.key, mozilla::Move(e));
     }
 
     // |all()| returns a Range containing |count()| elements. E.g.:
     //
     //   typedef HashMap<int,char> HM;
     //   HM h;
     //   for (HM::Range r = h.all(); !r.empty(); r.popFront())
     //     char c = r.front().value;
@@ -214,30 +215,30 @@ class HashMap
     /************************************************** Shorthand operations */
 
     bool has(const Lookup &l) const {
         return impl.lookup(l) != nullptr;
     }
 
     // Overwrite existing value with v. Return false on oom.
     template<typename KeyInput, typename ValueInput>
-    bool put(const KeyInput &k, const ValueInput &v) {
+    bool put(KeyInput &&k, ValueInput &&v) {
         AddPtr p = lookupForAdd(k);
         if (p) {
-            p->value = v;
+            p->value = mozilla::Forward<ValueInput>(v);
             return true;
         }
-        return add(p, k, v);
+        return add(p, mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
     }
 
     // Like put, but assert that the given key is not already present.
     template<typename KeyInput, typename ValueInput>
-    bool putNew(const KeyInput &k, const ValueInput &v) {
-        Entry e(k, v);
-        return impl.putNew(k, mozilla::OldMove(e));
+    bool putNew(KeyInput &&k, ValueInput &&v) {
+        Entry e(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
+        return impl.putNew(e.key, mozilla::Move(e));
     }
 
     // Add (k,defaultValue) if |k| is not found. Return a false-y Ptr on oom.
     Ptr lookupWithDefault(const Key &k, const Value &defaultValue) {
         AddPtr p = lookupForAdd(k);
         if (p)
             return p;
         (void)add(p, k, defaultValue);  // p is left false-y on oom.
@@ -259,18 +260,21 @@ class HashMap
 
     // Infallibly rekey one entry, if present.
     void rekeyAs(const Lookup &old_lookup, const Lookup &new_lookup, const Key &new_key) {
         if (Ptr p = lookup(old_lookup))
             impl.rekeyAndMaybeRehash(p, new_lookup, new_key);
     }
 
     // HashMap is movable
-    HashMap(mozilla::MoveRef<HashMap> rhs) : impl(mozilla::OldMove(rhs->impl)) {}
-    void operator=(mozilla::MoveRef<HashMap> rhs) { impl = mozilla::OldMove(rhs->impl); }
+    HashMap(HashMap &&rhs) : impl(mozilla::Move(rhs.impl)) {}
+    void operator=(HashMap &&rhs) {
+        MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
+        impl = mozilla::Move(rhs.impl);
+    }
 
   private:
     // HashMap is not copyable or assignable
     HashMap(const HashMap &hm) MOZ_DELETE;
     HashMap &operator=(const HashMap &hm) MOZ_DELETE;
 
     friend class Impl::Enum;
 };
@@ -366,20 +370,24 @@ class HashSet
     //    }
     //    assert(*p == 3);
     //
     // Note that relookupOrAdd(p,l,t) performs Lookup using |l| and adds the
     // entry |t|, where the caller ensures match(l,t).
     typedef typename Impl::AddPtr AddPtr;
     AddPtr lookupForAdd(const Lookup &l) const        { return impl.lookupForAdd(l); }
 
-    bool add(AddPtr &p, const T &t)                   { return impl.add(p, t); }
+    template <typename U>
+    bool add(AddPtr &p, U &&u) {
+        return impl.add(p, mozilla::Forward<U>(u));
+    }
 
-    bool relookupOrAdd(AddPtr &p, const Lookup &l, const T &t) {
-        return impl.relookupOrAdd(p, l, t);
+    template <typename U>
+    bool relookupOrAdd(AddPtr &p, const Lookup &l, U &&u) {
+        return impl.relookupOrAdd(p, l, mozilla::Forward<U>(u));
     }
 
     // |all()| returns a Range containing |count()| elements:
     //
     //   typedef HashSet<int> HS;
     //   HS h;
     //   for (HS::Range r = h.all(); !r.empty(); r.popFront())
     //     int i = r.front();
@@ -433,29 +441,32 @@ class HashSet
     unsigned generation() const                       { return impl.generation(); }
 
     /************************************************** Shorthand operations */
 
     bool has(const Lookup &l) const {
         return impl.lookup(l) != nullptr;
     }
 
-    // Overwrite existing value with v. Return false on oom.
-    bool put(const T &t) {
-        AddPtr p = lookupForAdd(t);
-        return p ? true : add(p, t);
+    // Add |u| if it is not present already. Return false on oom.
+    template <typename U>
+    bool put(U &&u) {
+        AddPtr p = lookupForAdd(u);
+        return p ? true : add(p, mozilla::Forward<U>(u));
     }
 
     // Like put, but assert that the given key is not already present.
-    bool putNew(const T &t) {
-        return impl.putNew(t, t);
+    template <typename U>
+    bool putNew(U &&u) {
+        return impl.putNew(u, mozilla::Forward<U>(u));
     }
 
-    bool putNew(const Lookup &l, const T &t) {
-        return impl.putNew(l, t);
+    template <typename U>
+    bool putNew(const Lookup &l, U &&u) {
+        return impl.putNew(l, mozilla::Forward<U>(u));
     }
 
     void remove(const Lookup &l) {
         if (Ptr p = lookup(l))
             remove(p);
     }
 
     // Infallibly rekey one entry, if present.
@@ -467,18 +478,21 @@ class HashSet
 
     // Infallibly rekey one entry, if present.
     void rekeyAs(const Lookup &old_lookup, const Lookup &new_lookup, const T &new_value) {
         if (Ptr p = lookup(old_lookup))
             impl.rekeyAndMaybeRehash(p, new_lookup, new_value);
     }
 
     // HashSet is movable
-    HashSet(mozilla::MoveRef<HashSet> rhs) : impl(mozilla::OldMove(rhs->impl)) {}
-    void operator=(mozilla::MoveRef<HashSet> rhs) { impl = mozilla::OldMove(rhs->impl); }
+    HashSet(HashSet &&rhs) : impl(mozilla::Move(rhs.impl)) {}
+    void operator=(HashSet &&rhs) {
+        MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
+        impl = mozilla::Move(rhs.impl);
+    }
 
   private:
     // HashSet is not copyable or assignable
     HashSet(const HashSet &hs) MOZ_DELETE;
     HashSet &operator=(const HashSet &hs) MOZ_DELETE;
 
     friend class Impl::Enum;
 };
@@ -605,20 +619,21 @@ class HashMapEntry
     template <class, class, class> friend class detail::HashTable;
     template <class> friend class detail::HashTableEntry;
 
     HashMapEntry(const HashMapEntry &) MOZ_DELETE;
     void operator=(const HashMapEntry &) MOZ_DELETE;
 
   public:
     template<typename KeyInput, typename ValueInput>
-    HashMapEntry(const KeyInput &k, const ValueInput &v) : key(k), value(v) {}
+    HashMapEntry(KeyInput &&k, ValueInput &&v)
+      : key(mozilla::Forward<KeyInput>(k)), value(mozilla::Forward<ValueInput>(v)) { }
 
-    HashMapEntry(mozilla::MoveRef<HashMapEntry> rhs)
-      : key(mozilla::OldMove(rhs->key)), value(mozilla::OldMove(rhs->value)) { }
+    HashMapEntry(HashMapEntry &&rhs)
+      : key(mozilla::Move(const_cast<Key &>(rhs.key))), value(mozilla::Move(rhs.value)) { }
 
     typedef Key KeyType;
     typedef Value ValueType;
 
     const Key key;
     Value value;
 };
 
@@ -694,21 +709,21 @@ class HashTableEntry
     void setCollision()               { JS_ASSERT(isLive()); keyHash |= sCollisionBit; }
     void setCollision(HashNumber bit) { JS_ASSERT(isLive()); keyHash |= bit; }
     void unsetCollision()             { keyHash &= ~sCollisionBit; }
     bool hasCollision() const         { return keyHash & sCollisionBit; }
     bool matchHash(HashNumber hn)     { return (keyHash & ~sCollisionBit) == hn; }
     HashNumber getKeyHash() const     { return keyHash & ~sCollisionBit; }
 
     template <class U>
-    void setLive(HashNumber hn, const U &u)
+    void setLive(HashNumber hn, U &&u)
     {
         JS_ASSERT(!isLive());
         keyHash = hn;
-        new(mem.addr()) T(u);
+        new(mem.addr()) T(mozilla::Forward<U>(u));
         JS_ASSERT(isLive());
     }
 };
 
 template <class T, class HashPolicy, class AllocPolicy>
 class HashTable : private AllocPolicy
 {
     typedef typename mozilla::RemoveConst<T>::Type NonConstT;
@@ -856,27 +871,28 @@ class HashTable : private AllocPolicy
             }
 
             if (removed)
                 table.compactIfUnderloaded();
         }
     };
 
     // HashTable is movable
-    HashTable(mozilla::MoveRef<HashTable> rhs)
-      : AllocPolicy(*rhs)
+    HashTable(HashTable &&rhs)
+      : AllocPolicy(rhs)
     {
-        mozilla::PodAssign(this, &*rhs);
-        rhs->table = nullptr;
+        mozilla::PodAssign(this, &rhs);
+        rhs.table = nullptr;
     }
-    void operator=(mozilla::MoveRef<HashTable> rhs) {
+    void operator=(HashTable &&rhs) {
+        MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
         if (table)
             destroyTable(*this, table, capacity());
-        mozilla::PodAssign(this, &*rhs);
-        rhs->table = nullptr;
+        mozilla::PodAssign(this, &rhs);
+        rhs.table = nullptr;
     }
 
   private:
     // HashTable is not copyable or assignable
     HashTable(const HashTable &) MOZ_DELETE;
     void operator=(const HashTable &) MOZ_DELETE;
 
   private:
@@ -1205,17 +1221,17 @@ class HashTable : private AllocPolicy
         removedCount = 0;
         gen++;
         table = newTable;
 
         // Copy only live entries, leaving removed ones behind.
         for (Entry *src = oldTable, *end = src + oldCap; src < end; ++src) {
             if (src->isLive()) {
                 HashNumber hn = src->getKeyHash();
-                findFreeEntry(hn).setLive(hn, mozilla::OldMove(src->get()));
+                findFreeEntry(hn).setLive(hn, mozilla::Move(src->get()));
                 src->destroy();
             }
         }
 
         // All entries have been destroyed, no need to destroyTable.
         this->free_(oldTable);
         return Rehashed;
     }
@@ -1420,17 +1436,17 @@ class HashTable : private AllocPolicy
         HashNumber keyHash = prepareHash(l);
         Entry &entry = lookup(l, keyHash, sCollisionBit);
         AddPtr p(entry, keyHash);
         p.mutationCount = mutationCount;
         return p;
     }
 
     template <class U>
-    bool add(AddPtr &p, const U &rhs)
+    bool add(AddPtr &p, U &&u)
     {
         mozilla::ReentrancyGuard g(*this);
         JS_ASSERT(mutationCount == p.mutationCount);
         JS_ASSERT(table);
         JS_ASSERT(!p.found());
         JS_ASSERT(!(p.keyHash & sCollisionBit));
 
         // Changing an entry from removed to live does not affect whether we
@@ -1443,80 +1459,86 @@ class HashTable : private AllocPolicy
             // Preserve the validity of |p.entry_|.
             RebuildStatus status = checkOverloaded();
             if (status == RehashFailed)
                 return false;
             if (status == Rehashed)
                 p.entry_ = &findFreeEntry(p.keyHash);
         }
 
-        p.entry_->setLive(p.keyHash, rhs);
+        p.entry_->setLive(p.keyHash, mozilla::Forward<U>(u));
         entryCount++;
         mutationCount++;
         return true;
     }
 
+    // Note: |l| may be a reference to a piece of |u|, so this function
+    // must take care not to use |l| after moving |u|.
     template <class U>
-    void putNewInfallible(const Lookup &l, const U &u)
+    void putNewInfallible(const Lookup &l, U &&u)
     {
         JS_ASSERT(table);
 
         HashNumber keyHash = prepareHash(l);
         Entry *entry = &findFreeEntry(keyHash);
 
         if (entry->isRemoved()) {
             METER(stats.addOverRemoved++);
             removedCount--;
             keyHash |= sCollisionBit;
         }
 
-        entry->setLive(keyHash, u);
+        entry->setLive(keyHash, mozilla::Forward<U>(u));
         entryCount++;
         mutationCount++;
     }
 
+    // Note: |l| may be a reference to a piece of |u|, so this function
+    // must take care not to use |l| after moving |u|.
     template <class U>
-    bool putNew(const Lookup &l, const U &u)
+    bool putNew(const Lookup &l, U &&u)
     {
         if (checkOverloaded() == RehashFailed)
             return false;
 
-        putNewInfallible(l, u);
+        putNewInfallible(l, mozilla::Forward<U>(u));
         return true;
     }
 
+    // Note: |l| may be a reference to a piece of |u|, so this function
+    // must take care not to use |l| after moving |u|.
     template <class U>
-    bool relookupOrAdd(AddPtr& p, const Lookup &l, const U &u)
+    bool relookupOrAdd(AddPtr& p, const Lookup &l, U &&u)
     {
         p.mutationCount = mutationCount;
         {
             mozilla::ReentrancyGuard g(*this);
             p.entry_ = &lookup(l, p.keyHash, sCollisionBit);
         }
-        return p.found() || add(p, u);
+        return p.found() || add(p, mozilla::Forward<U>(u));
     }
 
     void remove(Ptr p)
     {
         JS_ASSERT(table);
         mozilla::ReentrancyGuard g(*this);
         JS_ASSERT(p.found());
         remove(*p.entry_);
         checkUnderloaded();
     }
 
     void rekeyWithoutRehash(Ptr p, const Lookup &l, const Key &k)
     {
         JS_ASSERT(table);
         mozilla::ReentrancyGuard g(*this);
         JS_ASSERT(p.found());
-        typename HashTableEntry<T>::NonConstT t(mozilla::OldMove(*p));
+        typename HashTableEntry<T>::NonConstT t(mozilla::Move(*p));
         HashPolicy::setKey(t, const_cast<Key &>(k));
         remove(*p.entry_);
-        putNewInfallible(l, mozilla::OldMove(t));
+        putNewInfallible(l, mozilla::Move(t));
     }
 
     void rekeyAndMaybeRehash(Ptr p, const Lookup &l, const Key &k)
     {
         rekeyWithoutRehash(p, l, k);
         checkOverRemoved();
     }
 
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -268,18 +268,18 @@ struct StringInfo
 //
 // Essentially the only difference between this class and StringInfo is that
 // NotableStringInfo holds a copy of the string's chars.
 struct NotableStringInfo : public StringInfo
 {
     NotableStringInfo();
     NotableStringInfo(JSString *str, const StringInfo &info);
     NotableStringInfo(const NotableStringInfo& info);
-    NotableStringInfo(mozilla::MoveRef<NotableStringInfo> info);
-    NotableStringInfo &operator=(mozilla::MoveRef<NotableStringInfo> info);
+    NotableStringInfo(NotableStringInfo &&info);
+    NotableStringInfo &operator=(NotableStringInfo &&info);
 
     ~NotableStringInfo() {
         js_free(buffer);
     }
 
     // A string needs to take up this many bytes of storage before we consider
     // it to be "notable".
     static size_t notableSize() {
@@ -321,20 +321,20 @@ struct RuntimeSizes
 };
 
 struct ZoneStats : js::ZoneStatsPod
 {
     ZoneStats() {
         strings.init();
     }
 
-    ZoneStats(mozilla::MoveRef<ZoneStats> other)
-        : ZoneStatsPod(other),
-          strings(mozilla::OldMove(other->strings)),
-          notableStrings(mozilla::OldMove(other->notableStrings))
+    ZoneStats(ZoneStats &&other)
+      : ZoneStatsPod(mozilla::Move(other)),
+        strings(mozilla::Move(other.strings)),
+        notableStrings(mozilla::Move(other.notableStrings))
     {}
 
     // Add other's numbers to this object's numbers.  Both objects'
     // notableStrings vectors must be empty at this point, because we can't
     // merge them.  (A NotableStringInfo contains only a prefix of the string,
     // so we can't tell whether two NotableStringInfo objects correspond to the
     // same string.)
     void add(const ZoneStats &other) {
--- a/js/public/Vector.h
+++ b/js/public/Vector.h
@@ -50,17 +50,17 @@ class Vector
                                MinInlineCapacity,
                                AllocPolicy,
                                Vector<T, MinInlineCapacity, AllocPolicy> >
 {
     typedef typename mozilla::VectorBase<T, MinInlineCapacity, AllocPolicy, Vector> Base;
 
   public:
     Vector(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
-    Vector(mozilla::MoveRef<Vector> vec) : Base(vec) {}
-    Vector &operator=(mozilla::MoveRef<Vector> vec) {
-        return Base::operator=(vec);
+    Vector(Vector &&vec) : Base(mozilla::Move(vec)) {}
+    Vector &operator=(Vector &&vec) {
+        return Base::operator=(mozilla::Move(vec));
     }
 };
 
 } // namespace js
 
 #endif /* js_Vector_h */
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -143,16 +143,27 @@ USE_HOST_CXX = 1
 
 ifdef HAVE_DTRACE
 ifneq ($(OS_ARCH),Darwin)
 DTRACE_PROBE_OBJ = $(LIBRARY_NAME)-dtrace.$(OBJ_SUFFIX)
 endif
 MOZILLA_DTRACE_SRC = $(srcdir)/devtools/javascript-trace.d
 endif
 
+backend.RecursiveMakeBackend:
+	@echo "Build configuration changed. Regenerating backend."
+	$(PYTHON) config.status
+
+Makefile: backend.RecursiveMakeBackend
+	@$(TOUCH) $@
+
+include backend.RecursiveMakeBackend.pp
+
+default:: backend.RecursiveMakeBackend
+
 default::
 	$(call py_action,process_install_manifest,--no-remove $(DIST)/include _build_manifests/install/dist_include)
 
 ifneq (,$(CROSS_COMPILE)$(filter-out WINNT OS2,$(OS_ARCH)))
 # nsinstall doesn't get built until we enter config/ in the exports phase,
 # so we'll have to manually ensure it gets built here if we want to use
 # $(EXPORTS)
 export:: config/nsinstall$(HOST_BIN_SUFFIX)
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -17,19 +17,19 @@
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 
 using mozilla::DoubleIsInt32;
+using mozilla::Forward;
 using mozilla::IsNaN;
-using mozilla::OldMove;
-using mozilla::MoveRef;
+using mozilla::Move;
 using mozilla::ArrayLength;
 using JS::DoubleNaNValue;
 
 
 /*** OrderedHashTable ****************************************************************************/
 
 /*
  * Define two collection templates, js::OrderedHashMap and js::OrderedHashSet.
@@ -76,17 +76,17 @@ class OrderedHashTable
     typedef typename Ops::Lookup Lookup;
 
     struct Data
     {
         T element;
         Data *chain;
 
         Data(const T &e, Data *c) : element(e), chain(c) {}
-        Data(MoveRef<T> e, Data *c) : element(e), chain(c) {}
+        Data(T &&e, Data *c) : element(Move(e)), chain(c) {}
     };
 
     class Range;
     friend class Range;
 
   private:
     Data **hashTable;           // hash table (has hashBuckets() elements)
     Data *data;                 // data vector, an array of Data objects
@@ -162,35 +162,36 @@ class OrderedHashTable
     /*
      * If the table already contains an entry that matches |element|,
      * replace that entry with |element|. Otherwise add a new entry.
      *
      * On success, return true, whether there was already a matching element or
      * not. On allocation failure, return false. If this returns false, it
      * means the element was not added to the table.
      */
-    bool put(const T &element) {
+    template <typename ElementInput>
+    bool put(ElementInput &&element) {
         HashNumber h = prepareHash(Ops::getKey(element));
         if (Data *e = lookup(Ops::getKey(element), h)) {
-            e->element = element;
+            e->element = Forward<ElementInput>(element);
             return true;
         }
 
         if (dataLength == dataCapacity) {
             // If the hashTable is more than 1/4 deleted data, simply rehash in
             // place to free up some space. Otherwise, grow the table.
             uint32_t newHashShift = liveCount >= dataCapacity * 0.75 ? hashShift - 1 : hashShift;
             if (!rehash(newHashShift))
                 return false;
         }
 
         h >>= hashShift;
         liveCount++;
         Data *e = &data[dataLength++];
-        new (e) Data(element, hashTable[h]);
+        new (e) Data(Forward<ElementInput>(element), hashTable[h]);
         hashTable[h] = e;
         return true;
     }
 
     /*
      * If the table contains an element matching l, remove it and set *foundp
      * to true. Otherwise set *foundp to false.
      *
@@ -587,17 +588,17 @@ class OrderedHashTable
     void rehashInPlace() {
         for (uint32_t i = 0, N = hashBuckets(); i < N; i++)
             hashTable[i] = nullptr;
         Data *wp = data, *end = data + dataLength;
         for (Data *rp = data; rp != end; rp++) {
             if (!Ops::isEmpty(Ops::getKey(rp->element))) {
                 HashNumber h = prepareHash(Ops::getKey(rp->element)) >> hashShift;
                 if (rp != wp)
-                    wp->element = OldMove(rp->element);
+                    wp->element = Move(rp->element);
                 wp->chain = hashTable[h];
                 hashTable[h] = wp;
                 wp++;
             }
         }
         MOZ_ASSERT(wp == data + liveCount);
 
         while (wp != end)
@@ -634,17 +635,17 @@ class OrderedHashTable
             alloc.free_(newHashTable);
             return false;
         }
 
         Data *wp = newData;
         for (Data *p = data, *end = data + dataLength; p != end; p++) {
             if (!Ops::isEmpty(Ops::getKey(p->element))) {
                 HashNumber h = prepareHash(Ops::getKey(p->element)) >> newHashShift;
-                new (wp) Data(OldMove(p->element), newHashTable[h]);
+                new (wp) Data(Move(p->element), newHashTable[h]);
                 newHashTable[h] = wp;
                 wp++;
             }
         }
         MOZ_ASSERT(wp == newData + liveCount);
 
         alloc.free_(hashTable);
         freeData(data, dataLength);
@@ -674,25 +675,26 @@ class OrderedHashMap
     class Entry
     {
         template <class, class, class> friend class detail::OrderedHashTable;
         void operator=(const Entry &rhs) {
             const_cast<Key &>(key) = rhs.key;
             value = rhs.value;
         }
 
-        void operator=(MoveRef<Entry> rhs) {
-            const_cast<Key &>(key) = OldMove(rhs->key);
-            value = OldMove(rhs->value);
+        void operator=(Entry &&rhs) {
+            MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
+            const_cast<Key &>(key) = Move(rhs.key);
+            value = Move(rhs.value);
         }
 
       public:
         Entry() : key(), value() {}
         Entry(const Key &k, const Value &v) : key(k), value(v) {}
-        Entry(MoveRef<Entry> rhs) : key(OldMove(rhs->key)), value(OldMove(rhs->value)) {}
+        Entry(Entry &&rhs) : key(Move(rhs.key)), value(Move(rhs.value)) {}
 
         const Key key;
         Value value;
     };
 
   private:
     struct MapOps : OrderedHashPolicy
     {
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -682,77 +682,95 @@ static const struct TraceKindPair {
     { "string",     JSTRACE_STRING      },
 };
 
 static bool
 CountHeap(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    jsval v;
-    int32_t traceKind;
-    JSString *str;
-    JSCountHeapTracer countTracer;
-    JSCountHeapNode *node;
-    size_t counter;
-
     RootedValue startValue(cx, UndefinedValue());
     if (args.length() > 0) {
-        v = args[0];
+        jsval v = args[0];
         if (JSVAL_IS_TRACEABLE(v)) {
             startValue = v;
         } else if (!JSVAL_IS_NULL(v)) {
             JS_ReportError(cx,
                            "the first argument is not null or a heap-allocated "
                            "thing");
             return false;
         }
     }
 
-    traceKind = -1;
+    RootedValue traceValue(cx);
+    int32_t traceKind = -1;
+    void *traceThing = NULL;
     if (args.length() > 1) {
-        str = ToString(cx, args[0]);
+        JSString *str = ToString(cx, args[1]);
         if (!str)
             return false;
         JSFlatString *flatStr = JS_FlattenString(cx, str);
         if (!flatStr)
             return false;
-        for (size_t i = 0; ;) {
-            if (JS_FlatStringEqualsAscii(flatStr, traceKindNames[i].name)) {
-                traceKind = traceKindNames[i].kind;
-                break;
+        if (JS_FlatStringEqualsAscii(flatStr, "specific")) {
+            if (args.length() < 3) {
+                JS_ReportError(cx, "tracing of specific value requested "
+                               "but no value provided");
+                return false;
+            }
+            traceValue = args[2];
+            if (!JSVAL_IS_TRACEABLE(traceValue)){
+                JS_ReportError(cx, "cannot trace this kind of value");
+                return false;
             }
-            if (++i == ArrayLength(traceKindNames)) {
-                JSAutoByteString bytes(cx, str);
-                if (!!bytes)
-                    JS_ReportError(cx, "trace kind name '%s' is unknown", bytes.ptr());
-                return false;
+            traceThing = JSVAL_TO_TRACEABLE(traceValue);
+        } else {
+            for (size_t i = 0; ;) {
+                if (JS_FlatStringEqualsAscii(flatStr, traceKindNames[i].name)) {
+                    traceKind = traceKindNames[i].kind;
+                    break;
+                }
+                if (++i == ArrayLength(traceKindNames)) {
+                    JSAutoByteString bytes(cx, str);
+                    if (!!bytes)
+                        JS_ReportError(cx, "trace kind name '%s' is unknown", bytes.ptr());
+                    return false;
+                }
             }
         }
     }
 
+    JSCountHeapTracer countTracer;
     JS_TracerInit(&countTracer.base, JS_GetRuntime(cx), CountHeapNotify);
     if (!countTracer.visited.init()) {
         JS_ReportOutOfMemory(cx);
         return false;
     }
     countTracer.ok = true;
     countTracer.traceList = nullptr;
     countTracer.recycleList = nullptr;
 
     if (startValue.isUndefined()) {
         JS_TraceRuntime(&countTracer.base);
     } else {
         JS_CallValueTracer(&countTracer.base, startValue.address(), "root");
     }
 
-    counter = 0;
+    JSCountHeapNode *node;
+    size_t counter = 0;
     while ((node = countTracer.traceList) != nullptr) {
-        if (traceKind == -1 || node->kind == traceKind)
-            counter++;
+        if (traceThing == nullptr) {
+            // We are looking for all nodes with a specific kind
+            if (traceKind == -1 || node->kind == traceKind)
+                counter++;
+        } else {
+            // We are looking for some specific thing
+            if (node->thing == traceThing)
+                counter++;
+        }
         countTracer.traceList = node->next;
         node->next = countTracer.recycleList;
         countTracer.recycleList = node;
         JS_TraceChildren(&countTracer.base, node->thing, node->kind);
     }
     while ((node = countTracer.recycleList) != nullptr) {
         countTracer.recycleList = node->next;
         js_free(node);
@@ -1354,21 +1372,23 @@ static const JSFunctionSpecWithHelp Test
 "  maxMallocBytes, gcBytes, gcNumber, or sliceTimeBudget."),
 
     JS_FN_HELP("getBuildConfiguration", GetBuildConfiguration, 0, 0,
 "getBuildConfiguration()",
 "  Return an object describing some of the configuration options SpiderMonkey\n"
 "  was built with."),
 
     JS_FN_HELP("countHeap", CountHeap, 0, 0,
-"countHeap([start[, kind]])",
+"countHeap([start[, kind[, thing]]])",
 "  Count the number of live GC things in the heap or things reachable from\n"
 "  start when it is given and is not null. kind is either 'all' (default) to\n"
 "  count all things or one of 'object', 'double', 'string', 'function'\n"
-"  to count only things of that kind."),
+"  to count only things of that kind. If kind is the string 'specific',\n"
+"  then you can provide an extra argument with some specific traceable\n"
+"  thing to count.\n"),
 
 #ifdef DEBUG
     JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 1, 0,
 "oomAfterAllocations(count)",
 "  After 'count' js_malloc memory allocations, fail every following allocation\n"
 "  (return NULL)."),
 #endif
 
--- a/js/src/builtin/TypeRepresentation.cpp
+++ b/js/src/builtin/TypeRepresentation.cpp
@@ -54,16 +54,19 @@ TypeRepresentationHasher::match(TypeRepr
 {
     if (key1->kind() != key2->kind())
         return false;
 
     switch (key1->kind()) {
       case TypeRepresentation::Scalar:
         return matchScalars(key1->asScalar(), key2->asScalar());
 
+      case TypeRepresentation::Reference:
+        return matchReferences(key1->asReference(), key2->asReference());
+
       case TypeRepresentation::Struct:
         return matchStructs(key1->asStruct(), key2->asStruct());
 
       case TypeRepresentation::Array:
         return matchArrays(key1->asArray(), key2->asArray());
     }
 
     MOZ_ASSUME_UNREACHABLE("Invalid kind");
@@ -72,16 +75,23 @@ TypeRepresentationHasher::match(TypeRepr
 bool
 TypeRepresentationHasher::matchScalars(ScalarTypeRepresentation *key1,
                                        ScalarTypeRepresentation *key2)
 {
     return key1->type() == key2->type();
 }
 
 bool
+TypeRepresentationHasher::matchReferences(ReferenceTypeRepresentation *key1,
+                                          ReferenceTypeRepresentation *key2)
+{
+    return key1->type() == key2->type();
+}
+
+bool
 TypeRepresentationHasher::matchStructs(StructTypeRepresentation *key1,
                                        StructTypeRepresentation *key2)
 {
     if (key1->fieldCount() != key2->fieldCount())
         return false;
 
     for (size_t i = 0; i < key1->fieldCount(); i++) {
         if (key1->field(i).id != key2->field(i).id)
@@ -104,16 +114,19 @@ TypeRepresentationHasher::matchArrays(Ar
 }
 
 HashNumber
 TypeRepresentationHasher::hash(TypeRepresentation *key) {
     switch (key->kind()) {
       case TypeRepresentation::Scalar:
         return hashScalar(key->asScalar());
 
+      case TypeRepresentation::Reference:
+        return hashReference(key->asReference());
+
       case TypeRepresentation::Struct:
         return hashStruct(key->asStruct());
 
       case TypeRepresentation::Array:
         return hashArray(key->asArray());
     }
 
     MOZ_ASSUME_UNREACHABLE("Invalid kind");
@@ -121,16 +134,22 @@ TypeRepresentationHasher::hash(TypeRepre
 
 HashNumber
 TypeRepresentationHasher::hashScalar(ScalarTypeRepresentation *key)
 {
     return HashGeneric(key->kind(), key->type());
 }
 
 HashNumber
+TypeRepresentationHasher::hashReference(ReferenceTypeRepresentation *key)
+{
+    return HashGeneric(key->kind(), key->type());
+}
+
+HashNumber
 TypeRepresentationHasher::hashStruct(StructTypeRepresentation *key)
 {
     HashNumber hash = HashGeneric(key->kind());
     for (HashNumber i = 0; i < key->fieldCount(); i++) {
         hash = AddToHash(hash, JSID_BITS(key->field(i).id.get()));
         hash = AddToHash(hash, key->field(i).typeRepr);
     }
     return hash;
@@ -140,24 +159,26 @@ HashNumber
 TypeRepresentationHasher::hashArray(ArrayTypeRepresentation *key)
 {
     return HashGeneric(key->kind(), key->element(), key->length());
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Constructors
 
-TypeRepresentation::TypeRepresentation(Kind kind, size_t size, size_t align)
+TypeRepresentation::TypeRepresentation(Kind kind, size_t size,
+                                       size_t align, bool opaque)
   : size_(size),
     alignment_(align),
-    kind_(kind)
+    kind_(kind),
+    opaque_(opaque)
 {}
 
 ScalarTypeRepresentation::ScalarTypeRepresentation(Type type)
-  : TypeRepresentation(Scalar, 0, 1),
+  : TypeRepresentation(Scalar, 0, 1, false),
     type_(type)
 {
     switch (type) {
       case TYPE_INT8:
       case TYPE_UINT8:
       case TYPE_UINT8_CLAMPED:
         size_ = alignment_ = 1;
         break;
@@ -174,19 +195,38 @@ ScalarTypeRepresentation::ScalarTypeRepr
         break;
 
       case TYPE_FLOAT64:
         size_ = alignment_ = 8;
         break;
     }
 }
 
+ReferenceTypeRepresentation::ReferenceTypeRepresentation(Type type)
+  : TypeRepresentation(Reference, 0, 1, true),
+    type_(type)
+{
+    switch (type) {
+      case TYPE_ANY:
+        size_ = sizeof(js::HeapValue);
+        alignment_ = MOZ_ALIGNOF(js::HeapValue);
+        break;
+
+      case TYPE_OBJECT:
+      case TYPE_STRING:
+        size_ = sizeof(js::HeapPtrObject);
+        alignment_ = MOZ_ALIGNOF(js::HeapPtrObject);
+        break;
+    }
+}
+
 ArrayTypeRepresentation::ArrayTypeRepresentation(TypeRepresentation *element,
                                                  size_t length)
-  : TypeRepresentation(Array, element->size() * length, element->alignment()),
+  : TypeRepresentation(Array, element->size() * length,
+                       element->alignment(), element->opaque()),
     element_(element),
     length_(length)
 {
 }
 
 static inline size_t alignTo(size_t address, size_t align) {
     JS_ASSERT(IsPowerOfTwo(align));
     return (address + align - 1) & -align;
@@ -198,38 +238,46 @@ StructField::StructField(size_t index,
                          size_t offset)
   : index(index),
     id(id),
     typeRepr(typeRepr),
     offset(offset)
 {}
 
 StructTypeRepresentation::StructTypeRepresentation()
-  : TypeRepresentation(Struct, 0, 1),
+  : TypeRepresentation(Struct, 0, 1, false),
     fieldCount_(0) // see ::init() below!
 {
+    // note: size_, alignment_, and opaque_ are computed in ::init() below
 }
 
 bool
 StructTypeRepresentation::init(JSContext *cx,
                                AutoIdVector &ids,
                                AutoObjectVector &typeReprOwners)
 {
     JS_ASSERT(ids.length() == typeReprOwners.length());
     fieldCount_ = ids.length();
 
     // We compute alignment into the field `align_` directly in the
     // loop below, but not `size_` because we have to very careful
     // about overflow. For now, we always use a uint32_t for
     // consistency across build environments.
     uint32_t totalSize = 0;
 
+    // These will be adjusted in the loop below:
+    alignment_ = 1;
+    opaque_ = false;
+
     for (size_t i = 0; i < ids.length(); i++) {
         TypeRepresentation *fieldTypeRepr = fromOwnerObject(*typeReprOwners[i]);
 
+        if (fieldTypeRepr->opaque())
+            opaque_ = true;
+
         uint32_t alignedSize = alignTo(totalSize, fieldTypeRepr->alignment());
         if (alignedSize < totalSize) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                                  JSMSG_TYPEDOBJECT_TOO_BIG);
             return false;
         }
 
         new(fields() + i) StructField(i, ids[i], fieldTypeRepr, alignedSize);
@@ -300,16 +348,21 @@ TypeRepresentation::addToTableOrFree(JSC
                                       Int32Value(asArray()->length()));
         break;
 
       case Scalar:
         ownerObject->initReservedSlot(JS_TYPEREPR_SLOT_TYPE,
                                       Int32Value(asScalar()->type()));
         break;
 
+      case Reference:
+        ownerObject->initReservedSlot(JS_TYPEREPR_SLOT_TYPE,
+                                      Int32Value(asReference()->type()));
+        break;
+
       case Struct:
         break;
     }
 
     ownerObject_.init(ownerObject);
     return &*ownerObject;
 }
 
@@ -333,16 +386,39 @@ ScalarTypeRepresentation::Create(JSConte
         return nullptr;
     new(ptr) ScalarTypeRepresentation(type);
 
     return ptr->addToTableOrFree(cx, p);
 }
 
 /*static*/
 JSObject *
+ReferenceTypeRepresentation::Create(JSContext *cx,
+                                    ReferenceTypeRepresentation::Type type)
+{
+    JSCompartment *comp = cx->compartment();
+
+    ReferenceTypeRepresentation sample(type);
+    TypeRepresentationHash::AddPtr p = comp->typeReprs.lookupForAdd(&sample);
+    if (p)
+        return (*p)->ownerObject();
+
+    // Note: cannot use cx->new_ because constructor is private.
+    ReferenceTypeRepresentation *ptr =
+        (ReferenceTypeRepresentation *) cx->malloc_(
+            sizeof(ReferenceTypeRepresentation));
+    if (!ptr)
+        return nullptr;
+    new(ptr) ReferenceTypeRepresentation(type);
+
+    return ptr->addToTableOrFree(cx, p);
+}
+
+/*static*/
+JSObject *
 ArrayTypeRepresentation::Create(JSContext *cx,
                                 TypeRepresentation *element,
                                 size_t length)
 {
     JSCompartment *comp = cx->compartment();
 
     // Overly conservative, since we are using `size_t` to represent
     // size, but `SafeMul` operators on `int32_t` types. Still, it
@@ -417,16 +493,17 @@ TypeRepresentation::obj_trace(JSTracer *
 
 void
 TypeRepresentation::traceFields(JSTracer *trace)
 {
     mark(trace); // don't forget to mark the self-reference here!
 
     switch (kind()) {
       case Scalar:
+      case Reference:
         break;
 
       case Struct:
         asStruct()->traceStructFields(trace);
         break;
 
       case Array:
         asArray()->traceArrayFields(trace);
@@ -467,16 +544,19 @@ TypeRepresentation::obj_finalize(js::Fre
 
 bool
 TypeRepresentation::appendString(JSContext *cx, StringBuffer &contents)
 {
     switch (kind()) {
       case Scalar:
         return asScalar()->appendStringScalar(cx, contents);
 
+      case Reference:
+        return asReference()->appendStringReference(cx, contents);
+
       case Array:
         return asArray()->appendStringArray(cx, contents);
 
       case Struct:
         return asStruct()->appendStringStruct(cx, contents);
     }
 
     MOZ_ASSUME_UNREACHABLE("Invalid kind");
@@ -500,16 +580,38 @@ ScalarTypeRepresentation::appendStringSc
     switch (type()) {
 #define NUMERIC_TYPE_APPEND_STRING(constant_, type_, name_)                   \
         case constant_: return contents.append(#name_);
         JS_FOR_EACH_SCALAR_TYPE_REPR(NUMERIC_TYPE_APPEND_STRING)
     }
     MOZ_ASSUME_UNREACHABLE("Invalid type");
 }
 
+/*static*/ const char *
+ReferenceTypeRepresentation::typeName(Type type)
+{
+    switch (type) {
+#define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
+        case constant_: return #name_;
+        JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
+    }
+    MOZ_ASSUME_UNREACHABLE("Invalid type");
+}
+
+bool
+ReferenceTypeRepresentation::appendStringReference(JSContext *cx, StringBuffer &contents)
+{
+    switch (type()) {
+#define NUMERIC_TYPE_APPEND_STRING(constant_, type_, name_)                   \
+        case constant_: return contents.append(#name_);
+        JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_APPEND_STRING)
+    }
+    MOZ_ASSUME_UNREACHABLE("Invalid type");
+}
+
 bool
 ArrayTypeRepresentation::appendStringArray(JSContext *cx, StringBuffer &contents)
 {
     if (!contents.append("ArrayType("))
         return false;
 
     if (!element()->appendString(cx, contents))
         return false;
@@ -554,16 +656,172 @@ StructTypeRepresentation::appendStringSt
 
     if (!contents.append("})"))
         return false;
 
     return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////
+// Walking memory
+
+template<typename V>
+static void
+visitReferences(TypeRepresentation *repr, uint8_t *mem, V& visitor)
+{
+    if (repr->transparent())
+        return;
+
+    switch (repr->kind()) {
+      case TypeRepresentation::Scalar:
+        return;
+
+      case TypeRepresentation::Reference:
+        visitor.visitReference(repr->asReference(), mem);
+        return;
+
+      case TypeRepresentation::Array:
+      {
+        ArrayTypeRepresentation *arrayRepr = repr->asArray();
+        TypeRepresentation *elementRepr = arrayRepr->element();
+        for (size_t i = 0; i < arrayRepr->length(); i++) {
+            visitReferences(elementRepr, mem, visitor);
+            mem += elementRepr->size();
+        }
+        return;
+      }
+
+      case TypeRepresentation::Struct:
+      {
+        StructTypeRepresentation *structRepr = repr->asStruct();
+        for (size_t i = 0; i < structRepr->fieldCount(); i++) {
+            const StructField &f = structRepr->field(i);
+            visitReferences(f.typeRepr, mem + f.offset, visitor);
+        }
+        return;
+      }
+    }
+
+    MOZ_ASSUME_UNREACHABLE("Invalid type repr kind");
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Initializing instances
+
+namespace js {
+class MemoryInitVisitor {
+    const JSRuntime *rt_;
+
+  public:
+    MemoryInitVisitor(const JSRuntime *rt)
+      : rt_(rt)
+    {}
+
+    void visitReference(ReferenceTypeRepresentation *repr, uint8_t *mem);
+};
+} // namespace js
+
+void
+js::MemoryInitVisitor::visitReference(ReferenceTypeRepresentation *repr, uint8_t *mem)
+{
+    switch (repr->type()) {
+      case ReferenceTypeRepresentation::TYPE_ANY:
+      {
+        js::HeapValue *heapValue = reinterpret_cast<js::HeapValue *>(mem);
+        heapValue->init(UndefinedValue());
+        return;
+      }
+
+      case ReferenceTypeRepresentation::TYPE_OBJECT:
+      {
+        js::HeapPtrObject *objectPtr =
+            reinterpret_cast<js::HeapPtrObject *>(mem);
+        objectPtr->init(nullptr);
+        return;
+      }
+
+      case ReferenceTypeRepresentation::TYPE_STRING:
+      {
+        js::HeapPtrString *stringPtr =
+            reinterpret_cast<js::HeapPtrString *>(mem);
+        stringPtr->init(rt_->emptyString);
+        return;
+      }
+    }
+
+    MOZ_ASSUME_UNREACHABLE("Invalid kind");
+}
+
+void
+TypeRepresentation::initInstance(const JSRuntime *rt, uint8_t *mem)
+{
+    MemoryInitVisitor visitor(rt);
+    memset(mem, 0, size());
+    if (opaque())
+        visitReferences(this, mem, visitor);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Tracing instances
+
+namespace js {
+class MemoryTracingVisitor {
+    JSTracer *trace_;
+
+  public:
+
+    MemoryTracingVisitor(JSTracer *trace)
+      : trace_(trace)
+    {}
+
+    void visitReference(ReferenceTypeRepresentation *repr, uint8_t *mem);
+};
+} // namespace js
+
+void
+js::MemoryTracingVisitor::visitReference(ReferenceTypeRepresentation *repr, uint8_t *mem)
+{
+    switch (repr->type()) {
+      case ReferenceTypeRepresentation::TYPE_ANY:
+      {
+        js::HeapValue *heapValue = reinterpret_cast<js::HeapValue *>(mem);
+        gc::MarkValue(trace_, heapValue, "reference-val");
+        return;
+      }
+
+      case ReferenceTypeRepresentation::TYPE_OBJECT:
+      {
+        js::HeapPtrObject *objectPtr =
+            reinterpret_cast<js::HeapPtrObject *>(mem);
+        if (*objectPtr)
+            gc::MarkObject(trace_, objectPtr, "reference-obj");
+        return;
+      }
+
+      case ReferenceTypeRepresentation::TYPE_STRING:
+      {
+        js::HeapPtrString *stringPtr =
+            reinterpret_cast<js::HeapPtrString *>(mem);
+        if (*stringPtr)
+            gc::MarkString(trace_, stringPtr, "reference-str");
+        return;
+      }
+    }
+
+    MOZ_ASSUME_UNREACHABLE("Invalid kind");
+}
+
+void
+TypeRepresentation::traceInstance(JSTracer *trace, uint8_t *mem)
+{
+    MemoryTracingVisitor visitor(trace);
+    visitReferences(this, mem, visitor);
+}
+
+///////////////////////////////////////////////////////////////////////////
 // Misc
 
 const StructField *
 StructTypeRepresentation::fieldNamed(jsid id) const
 {
     for (size_t i = 0; i < fieldCount(); i++) {
         if (field(i).id.get() == id)
             return &field(i);
--- a/js/src/builtin/TypeRepresentation.h
+++ b/js/src/builtin/TypeRepresentation.h
@@ -34,16 +34,24 @@
   the owner object for the type is stored in `SLOT_TYPE_REPR`.
 
   The canonicalization table maintains *weak references* to the
   TypeRepresentation* pointers. That is, the table is not traced.
   Instead, whenever an object is created, it is paired with its owner
   object, and the finalizer of the owner object removes the pointer
   from the table and then frees the pointer.
 
+  # Opacity
+
+  A type representation is considered "opaque" if it contains
+  references (strings, objects, any). In those cases we have to be
+  more limited with respect to aliasing etc to preserve portability
+  across engines (for example, we don't want to expose sizeof(Any))
+  and memory safety.
+
   # Future plans:
 
   The owner object will eventually be exposed to self-hosted script
   and will offer methods for querying and manipulating the binary data
   it describes.
 
  */
 
@@ -54,92 +62,116 @@
 #include "builtin/TypedObjectConstants.h"
 #include "gc/Barrier.h"
 #include "js/HashTable.h"
 
 namespace js {
 
 class TypeRepresentation;
 class ScalarTypeRepresentation;
+class ReferenceTypeRepresentation;
 class ArrayTypeRepresentation;
 class StructTypeRepresentation;
 
 struct Class;
 class StringBuffer;
 
 struct TypeRepresentationHasher
 {
     typedef TypeRepresentation *Lookup;
     static HashNumber hash(TypeRepresentation *key);
     static bool match(TypeRepresentation *key1, TypeRepresentation *key2);
 
   private:
     static HashNumber hashScalar(ScalarTypeRepresentation *key);
+    static HashNumber hashReference(ReferenceTypeRepresentation *key);
     static HashNumber hashStruct(StructTypeRepresentation *key);
     static HashNumber hashArray(ArrayTypeRepresentation *key);
 
     static bool matchScalars(ScalarTypeRepresentation *key1,
                              ScalarTypeRepresentation *key2);
+    static bool matchReferences(ReferenceTypeRepresentation *key1,
+                                ReferenceTypeRepresentation *key2);
     static bool matchStructs(StructTypeRepresentation *key1,
                              StructTypeRepresentation *key2);
     static bool matchArrays(ArrayTypeRepresentation *key1,
                             ArrayTypeRepresentation *key2);
 };
 
 typedef js::HashSet<TypeRepresentation *,
                     TypeRepresentationHasher,
                     RuntimeAllocPolicy> TypeRepresentationHash;
 
 class TypeRepresentation {
   public:
     enum Kind {
         Scalar = JS_TYPEREPR_SCALAR_KIND,
+        Reference = JS_TYPEREPR_REFERENCE_KIND,
         Struct = JS_TYPEREPR_STRUCT_KIND,
         Array = JS_TYPEREPR_ARRAY_KIND
     };
 
   protected:
-    TypeRepresentation(Kind kind, size_t size, size_t align);
+    TypeRepresentation(Kind kind, size_t size, size_t align, bool opaque);
 
     size_t size_;
     size_t alignment_;
     Kind kind_;
+    bool opaque_;
 
     JSObject *addToTableOrFree(JSContext *cx, TypeRepresentationHash::AddPtr &p);
 
   private:
     static const Class class_;
     static void obj_trace(JSTracer *trace, JSObject *object);
     static void obj_finalize(js::FreeOp *fop, JSObject *object);
 
     HeapPtrObject ownerObject_;
     void traceFields(JSTracer *tracer);
 
   public:
     size_t size() const { return size_; }
     size_t alignment() const { return alignment_; }
     Kind kind() const { return kind_; }
+    bool opaque() const { return opaque_; }
+    bool transparent() const { return !opaque_; }
     JSObject *ownerObject() const { return ownerObject_.get(); }
 
     // Appends a stringified form of this type representation onto
     // buffer, for use in error messages and the like.
     bool appendString(JSContext *cx, StringBuffer &buffer);
 
+    // Initializes memory that contains an instance of this type
+    // with appropriate default values (typically 0).
+    void initInstance(const JSRuntime *rt, uint8_t *mem);
+
+    // Traces memory that contains an instance of this type.
+    void traceInstance(JSTracer *trace, uint8_t *mem);
+
     static bool isOwnerObject(JSObject &obj);
     static TypeRepresentation *fromOwnerObject(JSObject &obj);
 
     bool isScalar() const {
         return kind() == Scalar;
     }
 
     ScalarTypeRepresentation *asScalar() {
         JS_ASSERT(isScalar());
         return (ScalarTypeRepresentation*) this;
     }
 
+    bool isReference() const {
+        return kind() == Reference;
+    }
+
+    ReferenceTypeRepresentation *asReference() {
+        JS_ASSERT(isReference());
+        return (ReferenceTypeRepresentation*) this;
+    }
+
     bool isArray() const {
         return kind() == Array;
     }
 
     ArrayTypeRepresentation *asArray() {
         JS_ASSERT(isArray());
         return (ArrayTypeRepresentation*) this;
     }
@@ -188,17 +220,19 @@ class ScalarTypeRepresentation : public 
     // See TypeRepresentation::appendString()
     bool appendStringScalar(JSContext *cx, StringBuffer &buffer);
 
   public:
     Type type() const {
         return type_;
     }
 
-    bool convertValue(JSContext *cx, HandleValue value, MutableHandleValue vp);
+    const char *typeName() const {
+        return typeName(type());
+    }
 
     static const char *typeName(Type type);
     static JSObject *Create(JSContext *cx, Type type);
 };
 
 // Enumerates the cases of ScalarTypeRepresentation::Type which have
 // unique C representation. In particular, omits Uint8Clamped since it
 // is just a Uint8.
@@ -212,16 +246,55 @@ class ScalarTypeRepresentation : public 
     macro_(ScalarTypeRepresentation::TYPE_FLOAT32, float,    float32)         \
     macro_(ScalarTypeRepresentation::TYPE_FLOAT64, double,   float64)
 
 // Must be in same order as the enum ScalarTypeRepresentation::Type:
 #define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_)                                    \
     JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                           \
     macro_(ScalarTypeRepresentation::TYPE_UINT8_CLAMPED, uint8_t, uint8Clamped)
 
+class ReferenceTypeRepresentation : public TypeRepresentation {
+  public:
+    // Must match order of JS_FOR_EACH_REFERENCE_TYPE_REPR below
+    enum Type {
+        TYPE_ANY = JS_REFERENCETYPEREPR_ANY,
+        TYPE_OBJECT = JS_REFERENCETYPEREPR_OBJECT,
+        TYPE_STRING = JS_REFERENCETYPEREPR_STRING,
+    };
+    static const int32_t TYPE_MAX = TYPE_STRING + 1;
+
+  private:
+    // so TypeRepresentation can call appendStringScalar() etc
+    friend class TypeRepresentation;
+
+    Type type_;
+
+    explicit ReferenceTypeRepresentation(Type type);
+
+    // See TypeRepresentation::appendString()
+    bool appendStringReference(JSContext *cx, StringBuffer &buffer);
+
+  public:
+    Type type() const {
+        return type_;
+    }
+
+    const char *typeName() const {
+        return typeName(type());
+    }
+
+    static const char *typeName(Type type);
+    static JSObject *Create(JSContext *cx, Type type);
+};
+
+#define JS_FOR_EACH_REFERENCE_TYPE_REPR(macro_)                             \
+    macro_(ReferenceTypeRepresentation::TYPE_ANY,    HeapValue, Any)        \
+    macro_(ReferenceTypeRepresentation::TYPE_OBJECT, HeapPtrObject, Object) \
+    macro_(ReferenceTypeRepresentation::TYPE_STRING, HeapPtrString, string)
+
 class ArrayTypeRepresentation : public TypeRepresentation {
   private:
     // so TypeRepresentation can call appendStringArray() etc
     friend class TypeRepresentation;
 
     TypeRepresentation *element_;
     size_t length_;
 
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -95,44 +95,50 @@ ToObjectIfObject(HandleValue value)
 {
     if (!value.isObject())
         return nullptr;
 
     return &value.toObject();
 }
 
 static inline bool
-IsNumericTypeObject(JSObject &type)
+IsScalarTypeObject(JSObject &type)
+{
+    return type.hasClass(&ScalarType::class_);
+}
+
+static inline bool
+IsReferenceTypeObject(JSObject &type)
 {
-    return &NumericTypeClasses[0] <= type.getClass() &&
-           type.getClass() < &NumericTypeClasses[ScalarTypeRepresentation::TYPE_MAX];
+    return type.hasClass(&ReferenceType::class_);
+}
+
+static inline bool
+IsSimpleTypeObject(JSObject &type)
+{
+    return IsScalarTypeObject(type) || IsReferenceTypeObject(type);
 }
 
 static inline bool
 IsArrayTypeObject(JSObject &type)
 {
     return type.hasClass(&ArrayType::class_);
 }
 
 static inline bool
 IsStructTypeObject(JSObject &type)
 {
     return type.hasClass(&StructType::class_);
 }
 
 static inline bool
-IsComplexTypeObject(JSObject &type)
-{
-    return IsArrayTypeObject(type) || IsStructTypeObject(type);
-}
-
-static inline bool
 IsTypeObject(JSObject &type)
 {
-    return IsNumericTypeObject(type) || IsComplexTypeObject(type);
+    return IsScalarTypeObject(type) || IsArrayTypeObject(type) ||
+           IsStructTypeObject(type) || IsReferenceTypeObject(type);
 }
 
 static inline bool
 IsTypedDatum(JSObject &obj)
 {
     return obj.is<TypedObject>() || obj.is<TypedHandle>();
 }
 
@@ -168,16 +174,41 @@ typeRepresentation(JSObject &typeObj)
 
 static inline JSObject *
 GetType(JSObject &datum)
 {
     JS_ASSERT(IsTypedDatum(datum));
     return &datum.getReservedSlot(JS_DATUM_SLOT_TYPE_OBJ).toObject();
 }
 
+static bool
+TypeObjectToSource(JSContext *cx, unsigned int argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    RootedObject thisObj(cx, ToObjectIfObject(args.thisv()));
+    if (!thisObj || !IsTypeObject(*thisObj)) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage,
+                             nullptr, JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS,
+                             "this", "type object");
+        return false;
+    }
+
+    StringBuffer contents(cx);
+    if (!typeRepresentation(*thisObj)->appendString(cx, contents))
+        return false;
+
+    RootedString result(cx, contents.finishString());
+    if (!result)
+        return false;
+
+    args.rval(