Merge the last PGO-green inbound changest to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 30 Oct 2012 10:48:44 -0400
changeset 111884 71290adea0c1e6b0ab35b260a561648b72072b23
parent 111819 626b7ea149bcb42997bb1011ea6f3884e04357d7 (current diff)
parent 111883 00c8ee61e262578493e0b21a9019014d63002f61 (diff)
child 111885 a2a201dd7a85b0a123ad929d146f76a0a3491b9e
child 111904 5d062234521ade91a3414d5040fdcec10b5cff0d
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
milestone19.0a1
Merge the last PGO-green inbound changest to m-c.
browser/components/safebrowsing/SafeBrowsing.jsm
browser/components/safebrowsing/content/blockedSite.xhtml
browser/components/safebrowsing/content/report-phishing-overlay.xul
browser/components/safebrowsing/jar.mn
xpcom/base/MemoryInfoDumper.cpp
xpcom/base/MemoryInfoDumper.h
--- a/accessible/src/atk/AtkSocketAccessible.cpp
+++ b/accessible/src/atk/AtkSocketAccessible.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <atk/atk.h>
 #include "AtkSocketAccessible.h"
 
 #include "InterfaceInitFuncs.h"
 #include "nsMai.h"
+#include "mozilla/Likely.h"
 
 AtkSocketEmbedType AtkSocketAccessible::g_atk_socket_embed = NULL;
 GType AtkSocketAccessible::g_atk_socket_type = G_TYPE_INVALID;
 const char* AtkSocketAccessible::sATKSocketEmbedSymbol = "atk_socket_embed";
 const char* AtkSocketAccessible::sATKSocketGetTypeSymbol = "atk_socket_get_type";
 
 bool AtkSocketAccessible::gCanEmbed = FALSE;
 
@@ -100,17 +101,17 @@ GetExtents(AtkComponent* aComponent, gin
                    aX, aY, aWidth, aHeight, aCoordType);
 }
 }
 
 void
 mai_atk_component_iface_init(AtkComponentIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid Interface");
-  if (NS_UNLIKELY(!aIface))
+  if (MOZ_UNLIKELY(!aIface))
     return;
 
   aIface->ref_accessible_at_point = RefAccessibleAtPoint;
   aIface->get_extents = GetExtents;
 }
 
 AtkSocketAccessible::AtkSocketAccessible(nsIContent* aContent,
                                          DocAccessible* aDoc,
--- a/accessible/src/atk/nsMaiInterfaceAction.cpp
+++ b/accessible/src/atk/nsMaiInterfaceAction.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
 #include "Accessible-inl.h"
 #include "nsMai.h"
 #include "Role.h"
+#include "mozilla/Likely.h"
 
 #include "nsString.h"
 
 using namespace mozilla::a11y;
 
 extern "C" {
 
 static gboolean
@@ -111,17 +112,17 @@ getKeyBindingCB(AtkAction *aAction, gint
   return AccessibleWrap::ReturnString(keyBindingsStr);
 }
 }
 
 void
 actionInterfaceInitCB(AtkActionIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid aIface");
-  if (NS_UNLIKELY(!aIface))
+  if (MOZ_UNLIKELY(!aIface))
     return;
 
   aIface->do_action = doActionCB;
   aIface->get_n_actions = getActionCountCB;
   aIface->get_description = getActionDescriptionCB;
   aIface->get_keybinding = getKeyBindingCB;
   aIface->get_name = getActionNameCB;
 }
--- a/accessible/src/atk/nsMaiInterfaceComponent.cpp
+++ b/accessible/src/atk/nsMaiInterfaceComponent.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
 #include "AccessibleWrap.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsMai.h"
+#include "mozilla/Likely.h"
 
 extern "C" {
 
 static AtkObject*
 refAccessibleAtPointCB(AtkComponent* aComponent, gint aAccX, gint aAccY,
                        AtkCoordType aCoordType)
 {
   return refAccessibleAtPointHelper(GetAccessibleWrap(ATK_OBJECT(aComponent)),
@@ -95,17 +96,17 @@ getExtentsHelper(AccessibleWrap* aAccWra
   *aWidth = width;
   *aHeight = height;
 }
 
 void
 componentInterfaceInitCB(AtkComponentIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid Interface");
-  if(NS_UNLIKELY(!aIface))
+  if(MOZ_UNLIKELY(!aIface))
     return;
 
   /*
    * Use default implementation in atk for contains, get_position,
    * and get_size
    */
   aIface->ref_accessible_at_point = refAccessibleAtPointCB;
   aIface->get_extents = getExtentsCB;
--- a/accessible/src/atk/nsMaiInterfaceDocument.cpp
+++ b/accessible/src/atk/nsMaiInterfaceDocument.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
 #include "AccessibleWrap.h"
 #include "DocAccessible.h"
 #include "nsMai.h"
+#include "mozilla/Likely.h"
 
 static const char* const kDocTypeName = "W3C-doctype";
 static const char* const kDocUrlName = "DocURL";
 static const char* const kMimeTypeName = "MimeType";
 
 // below functions are vfuncs on an ATK  interface so they need to be C call
 extern "C" {
 
@@ -21,17 +22,17 @@ static const gchar* getDocumentLocaleCB(
 static AtkAttributeSet* getDocumentAttributesCB(AtkDocument* aDocument);
 static const gchar* getDocumentAttributeValueCB(AtkDocument* aDocument,
                                                 const gchar* aAttrName);
 
 void
 documentInterfaceInitCB(AtkDocumentIface *aIface)
 {
     NS_ASSERTION(aIface, "Invalid Interface");
-    if(NS_UNLIKELY(!aIface))
+    if(MOZ_UNLIKELY(!aIface))
         return;
 
     /*
      * We don't support get_document or set_attribute right now.
      * get_document_type is deprecated, we return DocType in
      * get_document_attribute_value and get_document_attributes instead.
      */
     aIface->get_document_attributes = getDocumentAttributesCB;
--- a/accessible/src/atk/nsMaiInterfaceEditableText.cpp
+++ b/accessible/src/atk/nsMaiInterfaceEditableText.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
 #include "HyperTextAccessible.h"
 #include "nsMai.h"
 
 #include "nsString.h"
+#include "mozilla/Likely.h"
 
 extern "C" {
 static void
 setTextContentsCB(AtkEditableText *aText, const gchar *aString)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (!accWrap)
     return;
@@ -111,17 +112,17 @@ pasteTextCB(AtkEditableText *aText, gint
   text->PasteText(aPosition);
 }
 }
 
 void
 editableTextInterfaceInitCB(AtkEditableTextIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid aIface");
-  if (NS_UNLIKELY(!aIface))
+  if (MOZ_UNLIKELY(!aIface))
     return;
 
   aIface->set_text_contents = setTextContentsCB;
   aIface->insert_text = insertTextCB;
   aIface->copy_text = copyTextCB;
   aIface->cut_text = cutTextCB;
   aIface->delete_text = deleteTextCB;
   aIface->paste_text = pasteTextCB;
--- a/accessible/src/atk/nsMaiInterfaceHyperlinkImpl.cpp
+++ b/accessible/src/atk/nsMaiInterfaceHyperlinkImpl.cpp
@@ -2,16 +2,17 @@
 /* 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 "nsMaiHyperlink.h"
+#include "mozilla/Likely.h"
 
 extern "C" {
 static AtkHyperlink*
 getHyperlinkCB(AtkHyperlinkImpl* aImpl)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImpl));
   if (!accWrap)
     return nullptr;
@@ -23,13 +24,13 @@ getHyperlinkCB(AtkHyperlinkImpl* aImpl)
   return maiHyperlink->GetAtkHyperlink();
 }
 }
 
 void
 hyperlinkImplInterfaceInitCB(AtkHyperlinkImplIface *aIface)
 {
   NS_ASSERTION(aIface, "no interface!");
-  if (NS_UNLIKELY(!aIface))
+  if (MOZ_UNLIKELY(!aIface))
     return;
 
   aIface->get_hyperlink = getHyperlinkCB;
 }
--- a/accessible/src/atk/nsMaiInterfaceHypertext.cpp
+++ b/accessible/src/atk/nsMaiInterfaceHypertext.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
 #include "HyperTextAccessible.h"
 #include "nsMai.h"
 #include "nsMaiHyperlink.h"
+#include "mozilla/Likely.h"
 
 extern "C" {
 
 static AtkHyperlink*
 getLinkCB(AtkHypertext *aText, gint aLinkIndex)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (!accWrap)
@@ -65,15 +66,15 @@ getLinkIndexCB(AtkHypertext *aText, gint
   return index;
 }
 }
 
 void
 hypertextInterfaceInitCB(AtkHypertextIface* aIface)
 {
   NS_ASSERTION(aIface, "no interface!");
-  if (NS_UNLIKELY(!aIface))
+  if (MOZ_UNLIKELY(!aIface))
     return;
 
   aIface->get_link = getLinkCB;
   aIface->get_n_links = getLinkCountCB;
   aIface->get_link_index = getLinkIndexCB;
 }
--- a/accessible/src/atk/nsMaiInterfaceImage.cpp
+++ b/accessible/src/atk/nsMaiInterfaceImage.cpp
@@ -3,16 +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/. */
 
 #include "InterfaceInitFuncs.h"
 
 #include "AccessibleWrap.h"
 #include "ImageAccessible.h"
+#include "mozilla/Likely.h"
 #include "nsMai.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 extern "C" {
 const gchar* getDescriptionCB(AtkObject* aAtkObj);
 
@@ -48,15 +49,15 @@ getImageSizeCB(AtkImage* aImage, gint* a
   accWrap->AsImage()->GetImageSize(aAccWidth, aAccHeight);
 }
 }
 
 void
 imageInterfaceInitCB(AtkImageIface* aIface)
 {
   NS_ASSERTION(aIface, "no interface!");
-  if (NS_UNLIKELY(!aIface))
+  if (MOZ_UNLIKELY(!aIface))
     return;
 
   aIface->get_image_position = getImagePositionCB;
   aIface->get_image_description = getImageDescriptionCB;
   aIface->get_image_size = getImageSizeCB;
 }
--- a/accessible/src/atk/nsMaiInterfaceSelection.cpp
+++ b/accessible/src/atk/nsMaiInterfaceSelection.cpp
@@ -3,16 +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/. */
 
 #include "InterfaceInitFuncs.h"
 
 #include "AccessibleWrap.h"
 #include "nsMai.h"
+#include "mozilla/Likely.h"
 
 #include <atk/atk.h>
 
 extern "C" {
 
 static gboolean
 addSelectionCB(AtkSelection *aSelection, gint i)
 {
@@ -91,17 +92,17 @@ selectAllSelectionCB(AtkSelection *aSele
   return accWrap->SelectAll();
 }
 }
 
 void
 selectionInterfaceInitCB(AtkSelectionIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid aIface");
-  if (NS_UNLIKELY(!aIface))
+  if (MOZ_UNLIKELY(!aIface))
     return;
 
   aIface->add_selection = addSelectionCB;
   aIface->clear_selection = clearSelectionCB;
   aIface->ref_selection = refSelectionCB;
   aIface->get_selection_count = getSelectionCountCB;
   aIface->is_child_selected = isChildSelectedCB;
   aIface->remove_selection = removeSelectionCB;
--- a/accessible/src/atk/nsMaiInterfaceTable.cpp
+++ b/accessible/src/atk/nsMaiInterfaceTable.cpp
@@ -10,16 +10,18 @@
 #include "AccessibleWrap.h"
 #include "nsAccUtils.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "nsMai.h"
 
 #include "nsArrayUtils.h"
 
+#include "mozilla/Likely.h"
+
 using namespace mozilla::a11y;
 
 extern "C" {
 static AtkObject*
 refAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (!accWrap || aRowIdx < 0 || aColIdx < 0)
@@ -288,17 +290,17 @@ isCellSelectedCB(AtkTable *aTable, gint 
       IsCellSelected(aRowIdx, aColIdx));
 }
 }
 
 void
 tableInterfaceInitCB(AtkTableIface* aIface)
 {
   NS_ASSERTION(aIface, "no interface!");
-  if (NS_UNLIKELY(!aIface))
+  if (MOZ_UNLIKELY(!aIface))
     return;
 
   aIface->ref_at = refAtCB;
   aIface->get_index_at = getIndexAtCB;
   aIface->get_column_at_index = getColumnAtIndexCB;
   aIface->get_row_at_index = getRowAtIndexCB;
   aIface->get_n_columns = getColumnCountCB;
   aIface->get_n_rows = getRowCountCB;
--- a/accessible/src/atk/nsMaiInterfaceText.cpp
+++ b/accessible/src/atk/nsMaiInterfaceText.cpp
@@ -6,16 +6,18 @@
 
 #include "InterfaceInitFuncs.h"
 
 #include "HyperTextAccessible.h"
 #include "nsMai.h"
 
 #include "nsIPersistentProperties2.h"
 
+#include "mozilla/Likely.h"
+
 using namespace mozilla::a11y;
 
 AtkAttributeSet* ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes);
 
 static void
 ConvertTexttoAsterisks(AccessibleWrap* accWrap, nsAString& aString)
 {
   // convert each char to "*" when it's "password text" 
@@ -441,17 +443,17 @@ setCaretOffsetCB(AtkText *aText, gint aO
     return NS_SUCCEEDED(rv) ? TRUE : FALSE;
 }
 }
 
 void
 textInterfaceInitCB(AtkTextIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid aIface");
-  if (NS_UNLIKELY(!aIface))
+  if (MOZ_UNLIKELY(!aIface))
     return;
 
   aIface->get_text = getTextCB;
   aIface->get_text_after_offset = getTextAfterOffsetCB;
   aIface->get_text_at_offset = getTextAtOffsetCB;
   aIface->get_character_at_offset = getCharacterAtOffsetCB;
   aIface->get_text_before_offset = getTextBeforeOffsetCB;
   aIface->get_caret_offset = getCaretOffsetCB;
--- a/accessible/src/atk/nsMaiInterfaceValue.cpp
+++ b/accessible/src/atk/nsMaiInterfaceValue.cpp
@@ -1,15 +1,16 @@
 /* -*- 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"
 
 extern "C" {
 
 static void
 getCurrentValueCB(AtkValue *obj, GValue *value)
@@ -111,17 +112,17 @@ setCurrentValueCB(AtkValue *obj, const G
     return !NS_FAILED(accValue->SetCurrentValue(accDouble));
 }
 }
 
 void
 valueInterfaceInitCB(AtkValueIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid aIface");
-  if (NS_UNLIKELY(!aIface))
+  if (MOZ_UNLIKELY(!aIface))
     return;
 
   aIface->get_current_value = getCurrentValueCB;
   aIface->get_maximum_value = getMaximumValueCB;
   aIface->get_minimum_value = getMinimumValueCB;
   aIface->get_minimum_increment = getMinimumIncrementCB;
   aIface->set_current_value = setCurrentValueCB;
 }
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -245,16 +245,17 @@ nsAccessibilityService::ContentRangeInse
   if (logging::IsEnabled(logging::eTree)) {
     logging::MsgBegin("TREE", "content inserted");
     logging::Node("container", aContainer);
     for (nsIContent* child = aStartChild; child != aEndChild;
          child = child->GetNextSibling()) {
       logging::Node("content", child);
     }
     logging::MsgEnd();
+    logging::Stack();
   }
 #endif
 
   DocAccessible* docAccessible = GetDocAccessible(aPresShell);
   if (docAccessible)
     docAccessible->ContentInserted(aContainer, aStartChild, aEndChild);
 }
 
@@ -264,16 +265,17 @@ nsAccessibilityService::ContentRemoved(n
                                        nsIContent* aChild)
 {
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eTree)) {
     logging::MsgBegin("TREE", "content removed");
     logging::Node("container", aContainer);
     logging::Node("content", aChild);
     logging::MsgEnd();
+    logging::Stack();
   }
 #endif
 
   DocAccessible* docAccessible = GetDocAccessible(aPresShell);
   if (docAccessible)
     docAccessible->ContentRemoved(aContainer, aChild);
 }
 
--- a/accessible/tests/mochitest/name/markup.js
+++ b/accessible/tests/mochitest/name/markup.js
@@ -9,17 +9,17 @@ var gRuleDoc = null;
 var gDumpToConsole = true;
 
 /**
  * Start name tests. Run through markup elements and test names for test
  * element (see namerules.xml for details).
  */
 function testNames()
 {
-  enableLogging("tree");
+  enableLogging("tree,stack");
 
   var request = new XMLHttpRequest();
   request.open("get", gNameRulesFileURL, false);
   request.send();
 
   gRuleDoc = request.responseXML;
 
   var markupElms = evaluateXPath(gRuleDoc, "//rules/rulesample/markup");
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -186,16 +186,17 @@ pref("breakpad.reportURL", "http://crash
 pref("app.releaseNotesURL", "http://www.mozilla.com/%LOCALE%/b2g/%VERSION%/releasenotes/");
 pref("app.support.baseURL", "http://support.mozilla.com/b2g");
 pref("app.feedbackURL", "http://input.mozilla.com/feedback/");
 pref("app.privacyURL", "http://www.mozilla.com/%LOCALE%/m/privacy.html");
 pref("app.creditsURL", "http://www.mozilla.org/credits/");
 pref("app.featuresURL", "http://www.mozilla.com/%LOCALE%/b2g/features/");
 pref("app.faqURL", "http://www.mozilla.com/%LOCALE%/b2g/faq/");
 // Whether we want to report crashes (headless)
+//XXX Remove this pref when bug 801932 is fixed
 pref("app.reportCrashes", true);
 
 // Name of alternate about: page for certificate errors (when undefined, defaults to about:neterror)
 pref("security.alternate_certificate_error_page", "certerror");
 
 pref("security.warn_viewing_mixed", false); // Warning is disabled.  See Bug 616712.
 
 // Override some named colors to avoid inverse OS themes
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -176,8 +176,20 @@ SettingsListener.observe('debug.log-anim
 SettingsListener.observe('debug.dev-mode', false, function(value) {
   Services.prefs.setBoolPref('dom.mozApps.dev_mode', value);
 });
 
 // =================== Privacy ====================
 SettingsListener.observe('privacy.donottrackheader.enabled', false, function(value) {
   Services.prefs.setBoolPref('privacy.donottrackheader.enabled', value);
 });
+
+// =================== Crash Reporting ====================
+SettingsListener.observe('app.reportCrashes', 'ask', function(value) {
+  if (value == 'always') {
+    Services.prefs.setBoolPref('app.reportCrashes', true);
+  } else if (value == 'never') {
+    Services.prefs.setBoolPref('app.reportCrashes', false);
+  } else {
+    Services.prefs.clearUserPref('app.reportCrashes');
+  }
+});
+
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -67,36 +67,54 @@ function getContentWindow() {
 var shell = {
 
   get CrashSubmit() {
     delete this.CrashSubmit;
     Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
     return this.CrashSubmit;
   },
 
-  reportCrash: function shell_reportCrash(aCrashID) {
+  reportCrash: function shell_reportCrash(isChrome, aCrashID) {
     let crashID = aCrashID;
     try {
-      if (crashID == undefined || crashID == "")
+      // For chrome crashes, we want to report the lastRunCrashID.
+      if (isChrome) {
         crashID = Cc["@mozilla.org/xre/app-info;1"]
                     .getService(Ci.nsIXULRuntime).lastRunCrashID;
+      }
     } catch(e) { }
-    if (Services.prefs.getBoolPref('app.reportCrashes') &&
-        crashID) {
+
+    // Bail if there isn't a valid crashID.
+    if (!crashID) {
+      return;
+    }
+
+    try {
+      // Check if we should automatically submit this crash.
+      if (Services.prefs.getBoolPref("app.reportCrashes")) {
+        this.submitCrash(crashID);
+      }
+    } catch (e) { }
 
-      Services.obs.addObserver(function observer(subject, topic, state) {
-          if (topic != "network:offline-status-changed")
-            return;
-          if (state == 'online') {
-            shell.CrashSubmit.submit(crashID);
-            Services.obs.removeObserver(observer, topic);
-          }
-        }
-        , "network:offline-status-changed", false);
-    }
+    // Let Gaia notify the user of the crash.
+    this.sendChromeEvent({
+      type: "handle-crash",
+      crashID: crashID,
+      chrome: isChrome
+    });
+  },
+
+  // This function submits a crash when we're online.
+  submitCrash: function shell_submitCrash(aCrashID) {
+    Services.obs.addObserver(function observer(subject, topic, state) {
+      if (state == 'online') {
+        shell.CrashSubmit.submit(aCrashID);
+        Services.obs.removeObserver(observer, topic);
+      }
+    }, "network:offline-status-changed", false);
   },
 
   get contentBrowser() {
     delete this.contentBrowser;
     return this.contentBrowser = document.getElementById('homescreen');
   },
 
   get homeURL() {
@@ -153,25 +171,25 @@ var shell = {
     if (!homeURL) {
       let msg = 'Fatal error during startup: No homescreen found: try setting B2G_HOMESCREEN';
       alert(msg);
       return;
     }
 
     let manifestURL = this.manifestURL;
     // <html:iframe id="homescreen"
-    //              mozbrowser="true" mozallowfullscreen="true"
+    //              mozbrowser="true" allowfullscreen="true"
     //              style="overflow: hidden; -moz-box-flex: 1; border: none;"
     //              src="data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;'>"/>
     let browserFrame =
       document.createElementNS('http://www.w3.org/1999/xhtml', 'html:iframe');
     browserFrame.setAttribute('id', 'homescreen');
     browserFrame.setAttribute('mozbrowser', 'true');
     browserFrame.setAttribute('mozapp', manifestURL);
-    browserFrame.setAttribute('mozallowfullscreen', 'true');
+    browserFrame.setAttribute('allowfullscreen', 'true');
     browserFrame.setAttribute('style', "overflow: hidden; -moz-box-flex: 1; border: none;");
     browserFrame.setAttribute('src', "data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;");
     document.getElementById('shell').appendChild(browserFrame);
 
     browserFrame.contentWindow
                 .QueryInterface(Ci.nsIInterfaceRequestor)
                 .getInterface(Ci.nsIWebNavigation)
                 .sessionHistory = Cc["@mozilla.org/browser/shistory;1"]
@@ -331,17 +349,17 @@ var shell = {
         }
         break;
       case 'mozbrowserloadstart':
         if (content.document.location == 'about:blank')
           return;
 
         this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
 
-        this.reportCrash();
+        this.reportCrash(true);
 
         let chromeWindow = window.QueryInterface(Ci.nsIDOMChromeWindow);
         chromeWindow.browserDOMWindow = new nsBrowserAccess();
 
         Cu.import('resource://gre/modules/Webapps.jsm');
         DOMApplicationRegistry.allAppsLaunchable = true;
 
         this.sendEvent(window, 'ContentStart');
@@ -766,26 +784,34 @@ window.addEventListener('ContentStart', 
         error: String(e)
       });
     }
   });
 });
 
 (function contentCrashTracker() {
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
-      let cs = Cc["@mozilla.org/consoleservice;1"]
-                 .getService(Ci.nsIConsoleService);
       let props = aSubject.QueryInterface(Ci.nsIPropertyBag2);
       if (props.hasKey("abnormal") && props.hasKey("dumpID")) {
-        shell.reportCrash(props.getProperty("dumpID"));
+        shell.reportCrash(false, props.getProperty("dumpID"));
       }
     },
     "ipc:content-shutdown", false);
 })();
 
+// Listen for crashes submitted through the crash reporter UI.
+window.addEventListener('ContentStart', function cr_onContentStart() {
+  let content = shell.contentBrowser.contentWindow;
+  content.addEventListener("mozContentEvent", function cr_onMozContentEvent(e) {
+    if (e.detail.type == "submit-crash" && e.detail.crashID) {
+      shell.submitCrash(e.detail.crashID);
+    }
+  });
+});
+
 window.addEventListener('ContentStart', function update_onContentStart() {
   let updatePrompt = Cc["@mozilla.org/updates/update-prompt;1"]
                        .createInstance(Ci.nsIUpdatePrompt);
 
   let content = shell.contentBrowser.contentWindow;
   content.addEventListener("mozContentEvent", updatePrompt.wrappedJSObject);
 });
 
rename from browser/components/safebrowsing/content/blockedSite.xhtml
rename to browser/base/content/blockedSite.xhtml
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -5,28 +5,37 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 #endif
  */
 
 // One of the possible values for the mousewheel.* preferences.
 // From nsEventStateManager.cpp.
 const MOUSE_SCROLL_ZOOM = 3;
 
+Cu.import('resource://gre/modules/ContentPrefInstance.jsm');
+
+function getContentPrefs(aWindow) {
+  let context = aWindow ? aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                 .getInterface(Ci.nsIWebNavigation)
+                                 .QueryInterface(Ci.nsILoadContext) : null;
+  return new ContentPrefInstance(context);
+}
+
 /**
  * Controls the "full zoom" setting and its site-specific preferences.
  */
 var FullZoom = {
   // Identifies the setting in the content prefs database.
   name: "browser.content.full-zoom",
 
   // The global value (if any) for the setting.  Lazily loaded from the service
   // when first requested, then updated by the pref change listener as it changes.
   // If there is no global value, then this should be undefined.
   get globalValue() {
-    var globalValue = Services.contentPrefs.getPref(null, this.name);
+    var globalValue = getContentPrefs(gBrowser.contentDocument.defaultView).getPref(null, this.name);
     if (typeof globalValue != "undefined")
       globalValue = this._ensureValid(globalValue);
     delete this.globalValue;
     return this.globalValue = globalValue;
   },
 
   // browser.zoom.siteSpecific preference cache
   _siteSpecificPref: undefined,
@@ -50,30 +59,30 @@ var FullZoom = {
   //**************************************************************************//
   // Initialization & Destruction
 
   init: function FullZoom_init() {
     // Listen for scrollwheel events so we can save scrollwheel-based changes.
     window.addEventListener("DOMMouseScroll", this, false);
 
     // Register ourselves with the service so we know when our pref changes.
-    Services.contentPrefs.addObserver(this.name, this);
+    getContentPrefs().addObserver(this.name, this);
 
     this._siteSpecificPref =
       gPrefService.getBoolPref("browser.zoom.siteSpecific");
     this.updateBackgroundTabs =
       gPrefService.getBoolPref("browser.zoom.updateBackgroundTabs");
     // Listen for changes to the browser.zoom branch so we can enable/disable
     // updating background tabs and per-site saving and restoring of zoom levels.
     gPrefService.addObserver("browser.zoom.", this, true);
   },
 
   destroy: function FullZoom_destroy() {
     gPrefService.removeObserver("browser.zoom.", this);
-    Services.contentPrefs.removeObserver(this.name, this);
+    getContentPrefs().removeObserver(this.name, this);
     window.removeEventListener("DOMMouseScroll", this, false);
   },
 
 
   //**************************************************************************//
   // Event Handlers
 
   // nsIDOMEventListener
@@ -144,39 +153,41 @@ var FullZoom = {
         }
         break;
     }
   },
 
   // nsIContentPrefObserver
 
   onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue) {
-    if (aGroup == Services.contentPrefs.grouper.group(gBrowser.currentURI))
+    let contentPrefs = getContentPrefs(gBrowser.contentDocument.defaultView);
+    if (aGroup == contentPrefs.grouper.group(gBrowser.currentURI))
       this._applyPrefToSetting(aValue);
     else if (aGroup == null) {
       this.globalValue = this._ensureValid(aValue);
 
       // If the current page doesn't have a site-specific preference,
       // then its zoom should be set to the new global preference now that
       // the global preference has changed.
-      if (!Services.contentPrefs.hasPref(gBrowser.currentURI, this.name))
+      if (!contentPrefs.hasPref(gBrowser.currentURI, this.name))
         this._applyPrefToSetting();
     }
   },
 
   onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName) {
-    if (aGroup == Services.contentPrefs.grouper.group(gBrowser.currentURI))
+    let contentPrefs = getContentPrefs(gBrowser.contentDocument.defaultView);
+    if (aGroup == contentPrefs.grouper.group(gBrowser.currentURI))
       this._applyPrefToSetting();
     else if (aGroup == null) {
       this.globalValue = undefined;
 
       // If the current page doesn't have a site-specific preference,
       // then its zoom should be set to the default preference now that
       // the global preference has changed.
-      if (!Services.contentPrefs.hasPref(gBrowser.currentURI, this.name))
+      if (!contentPrefs.hasPref(gBrowser.currentURI, this.name))
         this._applyPrefToSetting();
     }
   },
 
   // location change observer
 
   /**
    * Called when the location of a tab changes.
@@ -202,22 +213,23 @@ var FullZoom = {
     let browser = aBrowser || gBrowser.selectedBrowser;
 
     // Media documents should always start at 1, and are not affected by prefs.
     if (!aIsTabSwitch && browser.contentDocument.mozSyntheticDocument) {
       ZoomManager.setZoomForBrowser(browser, 1);
       return;
     }
 
-    if (Services.contentPrefs.hasCachedPref(aURI, this.name)) {
-      let zoomValue = Services.contentPrefs.getPref(aURI, this.name);
+    let contentPrefs = getContentPrefs(gBrowser.contentDocument.defaultView);
+    if (contentPrefs.hasCachedPref(aURI, this.name)) {
+      let zoomValue = contentPrefs.getPref(aURI, this.name);
       this._applyPrefToSetting(zoomValue, browser);
     } else {
       var self = this;
-      Services.contentPrefs.getPref(aURI, this.name, function (aResult) {
+      contentPrefs.getPref(aURI, this.name, function (aResult) {
         // Check that we're still where we expect to be in case this took a while.
         // Null check currentURI, since the window may have been destroyed before
         // we were called.
         if (browser.currentURI && aURI.equals(browser.currentURI)) {
           self._applyPrefToSetting(aResult, browser);
         }
       });
     }
@@ -292,22 +304,22 @@ var FullZoom = {
   },
 
   _applySettingToPref: function FullZoom__applySettingToPref() {
     if (!this.siteSpecific || gInPrintPreviewMode ||
         content.document.mozSyntheticDocument)
       return;
 
     var zoomLevel = ZoomManager.zoom;
-    Services.contentPrefs.setPref(gBrowser.currentURI, this.name, zoomLevel);
+    getContentPrefs(gBrowser.contentDocument.defaultView).setPref(gBrowser.currentURI, this.name, zoomLevel);
   },
 
   _removePref: function FullZoom__removePref() {
     if (!(content.document.mozSyntheticDocument))
-      Services.contentPrefs.removePref(gBrowser.currentURI, this.name);
+      getContentPrefs(gBrowser.contentDocument.defaultView).removePref(gBrowser.currentURI, this.name);
   },
 
 
   //**************************************************************************//
   // Utilities
 
   _ensureValid: function FullZoom__ensureValid(aValue) {
     if (isNaN(aValue))
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -205,16 +205,20 @@
                               key="viewBookmarksSidebarKb"
                               observes="viewBookmarksSidebar"
                               accesskey="&bookmarksButton.accesskey;"/>
                     <menuitem id="menu_historySidebar"
                               key="key_gotoHistory"
                               observes="viewHistorySidebar"
                               label="&historyButton.label;"
                               accesskey="&historySidebarCmd.accesskey;"/>
+                    <menuitem id="menu_socialSidebar"
+                              type="checkbox"
+                              autocheck="false"
+                              command="Social:ToggleSidebar"/>
                   </menupopup>
                 </menu>
                 <menuseparator/>
                 <menuitem id="menu_stop"
                           class="show-only-for-keyboard"
                           label="&stopCmd.label;"
                           accesskey="&stopCmd.accesskey;"
                           command="Browser:Stop"
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -98,16 +98,19 @@ let SocialUI = {
     toggleCommand.setAttribute("label", label);
     toggleCommand.setAttribute("accesskey", accesskey);
 
     let kbMenuitem = document.getElementById("menu_socialAmbientMenu");
     kbMenuitem.hidden = !Social.enabled;
     kbMenuitem.setAttribute("label", label);
     kbMenuitem.setAttribute("accesskey", accesskey);
 
+    // The View->Sidebar menu.
+    document.getElementById("menu_socialSidebar").setAttribute("label", Social.provider.name);
+
     SocialToolbar.init();
     SocialShareButton.init();
     SocialSidebar.init();
     SocialMenu.populate();
   },
 
   updateToggleCommand: function SocialUI_updateToggleCommand() {
     let toggleCommand = this.toggleCommand;
@@ -187,16 +190,35 @@ let SocialUI = {
                                   .getInterface(Ci.nsIWebNavigation)
                                   .QueryInterface(Ci.nsIDocShell)
                                   .chromeEventHandler;
     let containerParent = container.parentNode;
     if (containerParent.classList.contains("social-panel") &&
         containerParent instanceof Ci.nsIDOMXULPopupElement) {
       containerParent.hidePopup();
     }
+  },
+
+  disableWithConfirmation: function SocialUI_disableWithConfirmation() {
+    let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
+    let dialogTitle = gNavigatorBundle.getFormattedString("social.remove.confirmationOK",
+                                                          [Social.provider.name]);
+    let text = gNavigatorBundle.getFormattedString("social.remove.confirmationLabel",
+                                                   [Social.provider.name, brandShortName]);
+    let okButtonText = dialogTitle;
+
+    let ps = Services.prompt;
+    let flags = ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0 +
+                ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1 +
+                ps.BUTTON_POS_0_DEFAULT;
+
+    let confirmationIndex = ps.confirmEx(null, dialogTitle, text, flags,
+                                         okButtonText, null, null, null, {});
+    if (confirmationIndex == 0)
+      Social.active = false;
   }
 }
 
 let SocialChatBar = {
   get chatbar() {
     return document.getElementById("pinnedchats");
   },
   // Whether the chats can be shown for this window.
@@ -645,16 +667,25 @@ var SocialMenu = {
     }
   }
 };
 
 var SocialToolbar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialToolbar_init() {
     this.button.setAttribute("image", Social.provider.iconURL);
+
+    let removeItem = document.getElementById("social-remove-menuitem");
+    let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
+    let label = gNavigatorBundle.getFormattedString("social.remove.label",
+                                                    [brandShortName]);
+    let accesskey = gNavigatorBundle.getString("social.remove.accesskey");
+    removeItem.setAttribute("label", label);
+    removeItem.setAttribute("accesskey", accesskey);
+
     this.updateButton();
     this.updateProfile();
     this._dynamicResizer = new DynamicResizeWatcher();
   },
 
   get button() {
     return document.getElementById("social-provider-button");
   },
@@ -808,18 +839,17 @@ var SocialToolbar = {
         iconContainers.appendChild(box);
       }
 
       let labelValue = icon.counter || "";
       // Only update the value attribute if it has changed to reduce layout changes.
       if (!label.hasAttribute("value") || label.getAttribute("value") != labelValue)
         label.setAttribute("value", labelValue);
 
-      if (image.getAttribute("src") != icon.iconURL)
-        image.setAttribute("src", icon.iconURL);
+      image.style.listStyleImage = "url(" + icon.iconURL + ")";
     }
     panel.appendChild(notificationFrames);
     iconBox.appendChild(iconContainers);
 
     for (let frame of createdFrames) {
       if (frame.docShell) {
         frame.docShell.isActive = false;
         frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -897,19 +927,31 @@ var SocialToolbar = {
                                              encodeURIComponent(src), null, null, null, null);
     sizeSocialPanelToContent(aNotificationFrame);
   }
 }
 
 var SocialSidebar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialSidebar_init() {
+    let sbrowser = document.getElementById("social-sidebar-browser");
+    this.errorListener = new SocialErrorListener("sidebar");
+    this.configureSidebarDocShell(sbrowser.docShell);
     this.updateSidebar();
   },
 
+  configureSidebarDocShell: function SocialSidebar_configureDocShell(aDocShell) {
+    // setting isAppTab causes clicks on untargeted links to open new tabs
+    aDocShell.isAppTab = true;
+    aDocShell.QueryInterface(Ci.nsIWebProgress)
+             .addProgressListener(SocialSidebar.errorListener,
+                                  Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
+                                  Ci.nsIWebProgress.NOTIFY_LOCATION);
+  },
+
   // Whether the sidebar can be shown for this window.
   get canShow() {
     return Social.uiVisible && Social.provider.sidebarURL && !this.chromeless;
   },
 
   // Whether this is a "chromeless window" (e.g. popup window). We don't show
   // the sidebar in these windows.
   get chromeless() {
@@ -918,20 +960,21 @@ var SocialSidebar = {
            docElem.getAttribute('chromehidden').contains("toolbar");
   },
 
   // Whether the user has toggled the sidebar on (for windows where it can appear)
   get opened() {
     return Services.prefs.getBoolPref("social.sidebar.open") && !document.mozFullScreen;
   },
 
-  dispatchEvent: function(aType, aDetail) {
+  setSidebarVisibilityState: function(aEnabled) {
     let sbrowser = document.getElementById("social-sidebar-browser");
+    sbrowser.docShell.isActive = aEnabled;
     let evt = sbrowser.contentDocument.createEvent("CustomEvent");
-    evt.initCustomEvent(aType, true, true, aDetail ? aDetail : {});
+    evt.initCustomEvent(aEnabled ? "socialFrameShow" : "socialFrameHide", true, true, {});
     sbrowser.contentDocument.documentElement.dispatchEvent(evt);
   },
 
   updateSidebar: function SocialSidebar_updateSidebar() {
     clearTimeout(this._unloadTimeoutId);
     // Hide the toggle menu item if the sidebar cannot appear
     let command = document.getElementById("Social:ToggleSidebar");
     command.setAttribute("hidden", this.canShow ? "false" : "true");
@@ -939,65 +982,71 @@ var SocialSidebar = {
     // Hide the sidebar if it cannot appear, or has been toggled off.
     // Also set the command "checked" state accordingly.
     let hideSidebar = !this.canShow || !this.opened;
     let broadcaster = document.getElementById("socialSidebarBroadcaster");
     broadcaster.hidden = hideSidebar;
     command.setAttribute("checked", !hideSidebar);
 
     let sbrowser = document.getElementById("social-sidebar-browser");
-    sbrowser.docShell.isActive = !hideSidebar;
     if (hideSidebar) {
-      this.dispatchEvent("socialFrameHide");
+      this.setSidebarVisibilityState(false);
       // If we've been disabled, unload the sidebar content immediately;
       // if the sidebar was just toggled to invisible, wait a timeout
       // before unloading.
       if (!this.canShow) {
         this.unloadSidebar();
       } else {
         this._unloadTimeoutId = setTimeout(
           this.unloadSidebar,
           Services.prefs.getIntPref("social.sidebar.unload_timeout_ms")
         );
       }
     } else {
       // Make sure the right sidebar URL is loaded
       if (sbrowser.getAttribute("origin") != Social.provider.origin) {
         sbrowser.setAttribute("origin", Social.provider.origin);
-        // setting isAppTab causes clicks on untargeted links to open new tabs
-        sbrowser.docShell.isAppTab = true;
-        sbrowser.webProgress.addProgressListener(new SocialErrorListener("sidebar"),
-                                                 Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
-                                                 Ci.nsIWebProgress.NOTIFY_LOCATION);
         sbrowser.setAttribute("src", Social.provider.sidebarURL);
         sbrowser.addEventListener("load", function sidebarOnShow() {
-          sbrowser.removeEventListener("load", sidebarOnShow);
+          sbrowser.removeEventListener("load", sidebarOnShow, true);
           // let load finish, then fire our event
           setTimeout(function () {
-            SocialSidebar.dispatchEvent("socialFrameShow");
+            SocialSidebar.setSidebarVisibilityState(true);
           }, 0);
-        });
+        }, true);
       } else {
-        this.dispatchEvent("socialFrameShow");
+        this.setSidebarVisibilityState(true);
       }
     }
   },
 
   unloadSidebar: function SocialSidebar_unloadSidebar() {
     let sbrowser = document.getElementById("social-sidebar-browser");
     if (!sbrowser.hasAttribute("origin"))
       return;
 
     // Bug 803255 - If we don't remove the sidebar browser from the DOM,
     // the previous document leaks because it's only released when the
     // sidebar is made visible again.
     let container = sbrowser.parentNode;
     container.removeChild(sbrowser);
     sbrowser.removeAttribute("origin");
     sbrowser.removeAttribute("src");
+
+    function resetDocShell(docshellSupports) {
+      let docshell = docshellSupports.QueryInterface(Ci.nsIDocShell);
+      if (docshell.chromeEventHandler != sbrowser)
+        return;
+
+      SocialSidebar.configureSidebarDocShell(docshell);
+
+      Services.obs.removeObserver(resetDocShell, "webnavigation-create");
+    }
+    Services.obs.addObserver(resetDocShell, "webnavigation-create", false);
+
     container.appendChild(sbrowser);
 
     SocialFlyout.unload();
   },
 
   _unloadTimeoutId: 0,
 
   setSidebarErrorMessage: function() {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -686,16 +686,19 @@
                       label="&social.toggleSidebar.label;"
                       accesskey="&social.toggleSidebar.accesskey;"/>
             <menuitem id="social-toggle-notifications-menuitem"
                       type="checkbox"
                       autocheck="false"
                       command="Social:ToggleNotifications"
                       label="&social.toggleNotifications.label;"
                       accesskey="&social.toggleNotifications.accesskey;"/>
+            <menuseparator/>
+            <menuitem id="social-remove-menuitem"
+                      oncommand="SocialUI.disableWithConfirmation();"/>
           </menupopup>
         </toolbarbutton>
       </toolbaritem>
 
       <toolbaritem id="bookmarks-menu-button-container"
                    class="chromeclass-toolbar-additional"
                    removable="true"
                    title="&bookmarksMenuButton.label;">
rename from browser/components/safebrowsing/content/report-phishing-overlay.xul
rename to browser/base/content/report-phishing-overlay.xul
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -351,17 +351,17 @@ Sanitizer.prototype = {
         // Clear site-specific permissions like "Allow this site to open popups"
         var pm = Components.classes["@mozilla.org/permissionmanager;1"]
                            .getService(Components.interfaces.nsIPermissionManager);
         pm.removeAll();
         
         // Clear site-specific settings like page-zoom level
         var cps = Components.classes["@mozilla.org/content-pref/service;1"]
                             .getService(Components.interfaces.nsIContentPrefService);
-        cps.removeGroupedPrefs();
+        cps.removeGroupedPrefs(null);
         
         // Clear "Never remember passwords for this site", which is not handled by
         // the permission manager
         var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
                               .getService(Components.interfaces.nsILoginManager);
         var hosts = pwmgr.getAllDisabledHosts();
         for each (var host in hosts) {
           pwmgr.setLoginSavingEnabled(host, true);
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -5,17 +5,17 @@
     xmlns:xbl="http://www.mozilla.org/xbl"
     xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <binding id="chatbox">
     <content orient="vertical" mousethrough="never">
       <xul:hbox class="chat-titlebar" xbl:inherits="minimized,selected,activity"
                 onclick="document.getBindingParent(this).toggle();" align="baseline">
         <xul:image class="chat-status-icon" xbl:inherits="src=image"/>
-        <xul:label class="chat-title" flex="1" xbl:inherits="value=label,crop"/>
+        <xul:label class="chat-title" flex="1" xbl:inherits="value=label" crop="center"/>
         <xul:toolbarbutton class="chat-close-button chat-toolbarbutton"
                            oncommand="document.getBindingParent(this).close();"/>
       </xul:hbox>
       <xul:iframe anonid="iframe" class="chat-frame" flex="1"
                   xbl:inherits="src,origin,collapsed=minimized" type="content"/>
     </content>
 
     <implementation implements="nsIDOMEventListener">
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -875,17 +875,17 @@ function startTest() {
     ok(contextMenu, "Got context menu XUL");
 
     if (chromeWin.document.getElementById("Browser:Stop").getAttribute("disabled") != "true") {
       todo(false, "Wait for subwindow to load... (This should usually happen once.)");
       SimpleTest.executeSoon(startTest);
       return;
     }
 
-    subwindow.mozAllowFullScreen = true;
+    subwindow.allowfullscreen = true;
     lastElement = null;
 
     text   = subwindow.document.getElementById("test-text");
     link   = subwindow.document.getElementById("test-link");
     imagelink = subwindow.document.getElementById("test-image-link");
     mailto = subwindow.document.getElementById("test-mailto");
     input  = subwindow.document.getElementById("test-input");
     img    = subwindow.document.getElementById("test-image");
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -117,8 +117,13 @@ browser.jar:
 #ifdef XP_WIN
         content/browser/win6BrowserOverlay.xul        (content/win6BrowserOverlay.xul)
 #endif
         content/browser/social-icon.png               (content/social-icon.png)
         content/browser/socialchat.xml                (content/socialchat.xml)
 # the following files are browser-specific overrides
 *       content/browser/license.html                  (/toolkit/content/license.html)
 % override chrome://global/content/license.html chrome://browser/content/license.html
+#ifdef MOZ_SAFE_BROWSING
+*       content/browser/report-phishing-overlay.xul     (content/report-phishing-overlay.xul)
+        content/browser/blockedSite.xhtml               (content/blockedSite.xhtml)
+% overlay chrome://browser/content/browser.xul chrome://browser/content/report-phishing-overlay.xul
+#endif
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -29,17 +29,17 @@ struct RedirEntry {
   unless your about: page really needs chrome privileges. Security review is
   required before adding new map entries without
   URI_SAFE_FOR_UNTRUSTED_CONTENT.  Also note, however, that adding
   URI_SAFE_FOR_UNTRUSTED_CONTENT will allow random web sites to link to that
   URI.  Perhaps we should separate the two concepts out...
  */
 static RedirEntry kRedirMap[] = {
 #ifdef MOZ_SAFE_BROWSING
-  { "blocked", "chrome://browser/content/safebrowsing/blockedSite.xhtml",
+  { "blocked", "chrome://browser/content/blockedSite.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
 #endif
   { "certerror", "chrome://browser/content/certerror/aboutCertError.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -436,21 +436,16 @@ PrivateBrowsingService.prototype = {
         this._unload();
         break;
       case "private-browsing":
         // clear all auth tokens
         let sdr = Cc["@mozilla.org/security/sdr;1"].
                   getService(Ci.nsISecretDecoderRing);
         sdr.logoutAndTeardown();
     
-        // clear plain HTTP auth sessions
-        let authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].
-                      getService(Ci.nsIHttpAuthManager);
-        authMgr.clearAll();
-
         try {
           this._prefs.deleteBranch("geo.wifi.access_token.");
         } catch (ex) {}
 
         if (!this._inPrivateBrowsing) {
           // Clear the error console
           let consoleService = Cc["@mozilla.org/consoleservice;1"].
                                getService(Ci.nsIConsoleService);
--- a/browser/components/privatebrowsing/test/browser/global/browser_privatebrowsing_DownloadLastDirWithCPS.js
+++ b/browser/components/privatebrowsing/test/browser/global/browser_privatebrowsing_DownloadLastDirWithCPS.js
@@ -109,17 +109,17 @@ function runTest() {
       is(gDownloadLastDir.getFile(uri2).path, dir2.path, "uri2 should return dir2"); // set in CPS
       is(gDownloadLastDir.getFile(uri3).path, dir3.path, "uri3 should return dir3"); // set in CPS
       is(gDownloadLastDir.getFile(uri4).path, dir2.path, "uri4 should return dir2"); // fallback
     }
 
     { // check clearHistory removes all data
       clearHistory();
       is(gDownloadLastDir.file, null, "clearHistory removes all data");
-      is(Services.contentPrefs.hasPref(uri1, "browser.download.lastDir"), false, "LastDir preference should be absent");
+      is(Services.contentPrefs.hasPref(uri1, "browser.download.lastDir", null), false, "LastDir preference should be absent");
       is(gDownloadLastDir.getFile(uri1), null, "uri1 should point to null");
       is(gDownloadLastDir.getFile(uri2), null, "uri2 should point to null");
       is(gDownloadLastDir.getFile(uri3), null, "uri3 should point to null");
       is(gDownloadLastDir.getFile(uri4), null, "uri4 should point to null");
     }
 
     Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
 
--- a/browser/components/privatebrowsing/test/unit/test_httpauth.js
+++ b/browser/components/privatebrowsing/test/unit/test_httpauth.js
@@ -1,79 +1,102 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // This test makes sure the HTTP authenticated sessions are correctly cleared
 // when entering and leaving the private browsing mode.
 
+Components.utils.import("resource://gre/modules/Services.jsm");
+
 function run_test_on_service() {
-  var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
-           getService(Ci.nsIPrivateBrowsingService);
-
   var am = Cc["@mozilla.org/network/http-auth-manager;1"].
            getService(Ci.nsIHttpAuthManager);
 
   const kHost1 = "pbtest3.example.com";
   const kHost2 = "pbtest4.example.com";
   const kPort = 80;
   const kHTTP = "http";
   const kBasic = "basic";
   const kRealm = "realm";
   const kDomain = "example.com";
   const kUser = "user";
   const kUser2 = "user2";
   const kPassword = "pass";
   const kPassword2 = "pass2";
   const kEmpty = "";
-
+  
+  const PRIVATE = true;
+  const NOT_PRIVATE = false;
+  
   try {
     var domain = {value: kEmpty}, user = {value: kEmpty}, pass = {value: kEmpty};
     // simulate a login via HTTP auth outside of the private mode
     am.setAuthIdentity(kHTTP, kHost1, kPort, kBasic, kRealm, kEmpty, kDomain, kUser, kPassword);
     // make sure the recently added auth entry is available outside the private browsing mode
-    am.getAuthIdentity(kHTTP, kHost1, kPort, kBasic, kRealm, kEmpty, domain, user, pass);
+    am.getAuthIdentity(kHTTP, kHost1, kPort, kBasic, kRealm, kEmpty, domain, user, pass, NOT_PRIVATE);
     do_check_eq(domain.value, kDomain);
     do_check_eq(user.value, kUser);
     do_check_eq(pass.value, kPassword);
-    // enter private browsing mode
-    pb.privateBrowsingEnabled = true;
-    // make sure the added auth entry is no longer accessible
+
+    // make sure the added auth entry is no longer accessible in private
     domain = {value: kEmpty}, user = {value: kEmpty}, pass = {value: kEmpty};
     try {
       // should throw
-      am.getAuthIdentity(kHTTP, kHost1, kPort, kBasic, kRealm, kEmpty, domain, user, pass);
+      am.getAuthIdentity(kHTTP, kHost1, kPort, kBasic, kRealm, kEmpty, domain, user, pass, PRIVATE);
       do_throw("Auth entry should not be retrievable after entering the private browsing mode");
     } catch (e) {
       do_check_eq(domain.value, kEmpty);
       do_check_eq(user.value, kEmpty);
       do_check_eq(pass.value, kEmpty);
     }
 
     // simulate a login via HTTP auth inside of the private mode
-    am.setAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, kDomain, kUser2, kPassword2);
-    // make sure the recently added auth entry is available outside the private browsing mode
+    am.setAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, kDomain, kUser2, kPassword2, PRIVATE);
+    // make sure the recently added auth entry is available inside the private browsing mode
     domain = {value: kEmpty}, user = {value: kEmpty}, pass = {value: kEmpty};
-    am.getAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, domain, user, pass);
+    am.getAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, domain, user, pass, PRIVATE);
     do_check_eq(domain.value, kDomain);
     do_check_eq(user.value, kUser2);
     do_check_eq(pass.value, kPassword2);
-    // exit private browsing mode
-    pb.privateBrowsingEnabled = false;
-    // make sure the added auth entry is no longer accessible
+
+    try {
+      // make sure the recently added auth entry is not available outside the private browsing mode
+      domain = {value: kEmpty}, user = {value: kEmpty}, pass = {value: kEmpty};
+      am.getAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, domain, user, pass, NOT_PRIVATE);
+      do_throw("Auth entry should not be retrievable outside of private browsing mode");
+    } catch (x) {
+      do_check_eq(domain.value, kEmpty);
+      do_check_eq(user.value, kEmpty);
+      do_check_eq(pass.value, kEmpty);
+    }
+
+    // simulate leaving private browsing mode
+    Services.obs.notifyObservers(null, "last-pb-context-exited", null);
+
+    // make sure the added auth entry is no longer accessible in any privacy state
     domain = {value: kEmpty}, user = {value: kEmpty}, pass = {value: kEmpty};
     try {
-      // should throw
-      am.getAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, domain, user, pass);
+      // should throw (not available in public mode)
+      am.getAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, domain, user, pass, NOT_PRIVATE);
       do_throw("Auth entry should not be retrievable after exiting the private browsing mode");
     } catch (e) {
       do_check_eq(domain.value, kEmpty);
       do_check_eq(user.value, kEmpty);
       do_check_eq(pass.value, kEmpty);
     }
+    try {
+      // should throw (no longer available in private mode)
+      am.getAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, domain, user, pass, PRIVATE);
+      do_throw("Auth entry should not be retrievable in private mode after exiting the private browsing mode");
+    } catch (x) {
+      do_check_eq(domain.value, kEmpty);
+      do_check_eq(user.value, kEmpty);
+      do_check_eq(pass.value, kEmpty);
+    }
   } catch (e) {
     do_throw("Unexpected exception while testing HTTP auth manager: " + e);
   }
 }
 
 // Support running tests on both the service itself and its wrapper
 function run_test() {
   run_test_on_all_services();
--- a/browser/components/safebrowsing/Makefile.in
+++ b/browser/components/safebrowsing/Makefile.in
@@ -7,21 +7,9 @@ DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 TEST_DIRS += content/test
 
-# Normally the "client ID" sent in updates is appinfo.name, but for
-# official Firefox releases from Mozilla we use a special identifier.
-ifdef MOZILLA_OFFICIAL
-ifdef MOZ_PHOENIX
-DEFINES += -DUSE_HISTORIC_SAFEBROWSING_ID=1
-endif
-endif
-
-EXTRA_PP_JS_MODULES = \
-  SafeBrowsing.jsm \
-  $(NULL)
-
 include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/browser/components/safebrowsing/jar.mn
+++ /dev/null
@@ -1,8 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-browser.jar:
-  content/browser/safebrowsing/report-phishing-overlay.xul     (content/report-phishing-overlay.xul)
-  content/browser/safebrowsing/blockedSite.xhtml               (content/blockedSite.xhtml)
-% overlay chrome://browser/content/browser.xul         chrome://browser/content/safebrowsing/report-phishing-overlay.xul
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -389,16 +389,24 @@ fullscreen.rememberDecision=Remember dec
 
 # LOCALIZATION NOTE (social.toggle.label): %1$S is the name of the social provider, %2$S is brandShortName (e.g. Firefox)
 social.toggle.label=%1$S for %2$S
 social.toggle.accesskey=f
 
 # LOCALIZATION NOTE (social.activated.description): %1$S is the name of the social provider, %2$S is brandShortName (e.g. Firefox)
 social.activated.description=You've turned on %1$S for %2$S.
 
+# LOCALIZATION NOTE (social.remove.label): %S = brandShortName
+social.remove.label=Remove from %S
+social.remove.accesskey=R
+# LOCALIZATION NOTE (social.remove.confirmationLabel): %1$S is the name of the social provider, %2$S is brandShortName (e.g. Firefox)
+social.remove.confirmationLabel=Are you sure you want to remove %1$S for %2$S?
+# LOCALIZATION NOTE (social.remove.confirmationOK): %S is the name of the social provider
+social.remove.confirmationOK=Remove %S
+
 # LOCALIZATION NOTE (social.error.message): %1$S is brandShortName (e.g. Firefox), %2$S is the name of the social provider
 social.error.message=%1$S is unable to connect with %2$S right now.
 social.error.tryAgain.label=Try Again
 social.error.tryAgain.accesskey=T
 social.error.ok.label=OK
 social.error.ok.accesskey=O
 social.error.closeSidebar.label=Close This Sidebar
 social.error.closeSidebar.accesskey=C
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -2647,18 +2647,17 @@ html|*#gcli-output-frame {
 }
 
 .social-notification-icon-stack {
   padding: 0;
 }
 
 .social-notification-icon-image {
   margin: 5px 3px;
-  width: 16px;
-  height: 16px;
+  -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 .social-notification-icon-hbox {
   padding: 0;
 }
 
 .social-notification-icon-label {
   background-color: rgb(240,61,37);
@@ -2722,17 +2721,17 @@ html|*#gcli-output-frame {
 }
 
 .chat-close-button:hover {
   -moz-image-region: rect(28px, 14px, 42px, 0);
 }
 
 .chat-title {
   font-weight: bold;
-  color: -moz-dialogtext;
+  color: black;
   text-shadow: none;
   cursor: inherit;
 }
 
 .chat-titlebar {
   background-color: #d9d9d9;
   background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
   height: 20px;
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -4095,18 +4095,17 @@ html|*#gcli-output-frame {
 
 @media (-moz-mac-lion-theme) {
   .social-notification-icon-stack > image:-moz-window-inactive {
     opacity: .5;
   }
 }
 
 .social-notification-icon-image {
-  width: 16px;
-  height: 16px;
+  -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 /* === end of social toolbar button === */
 
 /* === social toolbar provider menu  === */
 
 #social-statusarea-user-portrait {
   width: 32px;
@@ -4153,17 +4152,17 @@ html|*#gcli-output-frame {
 }
 
 .chat-close-button:hover {
   -moz-image-region: rect(28px, 14px, 42px, 0);
 }
 
 .chat-title {
   font-weight: bold;
-  color: -moz-dialogtext;
+  color: black;
   text-shadow: none;
   cursor: inherit;
 }
 
 .chat-titlebar {
   background-color: #d9d9d9;
   background-image: linear-gradient(rgba(255,255,255,.43), rgba(255,255,255,0));
   height: 20px;
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -3309,17 +3309,17 @@ html|*#gcli-output-frame {
 }
 
 #social-toolbar-item > .toolbarbutton-1 {
   padding: 5px;
   -moz-appearance: toolbarbutton;
 }
 
 @navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1 {
-  padding: 5px 0;
+  padding: 6px 0;
 }
 
 @navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1:first-child {
   -moz-padding-start: 5px;
 }
 
 @navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1:last-child {
   -moz-padding-end: 5px;
@@ -3343,18 +3343,17 @@ html|*#gcli-output-frame {
   box-shadow: 0 1px 0 rgba(0,39,121,0.77);
 }
 
 .social-notification-icon-label[value=""] {
   display: none;
 }
 
 .social-notification-icon-image {
-  width: 16px;
-  height: 16px;
+  -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 /* social toolbar provider menu */
 #social-statusarea-popup {
   margin-top: 0;
   margin-left: -12px;
   margin-right: -12px;
 }
@@ -3426,17 +3425,17 @@ html|*#gcli-output-frame {
 }
 
 .chat-close-button:hover {
   -moz-image-region: rect(28px, 14px, 42px, 0);
 }
 
 .chat-title {
   font-weight: bold;
-  color: -moz-dialogtext;
+  color: black;
   text-shadow: none;
   cursor: inherit;
 }
 
 .chat-titlebar {
   background-color: #c4cfde;
   background-image: linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,0));
   height: 20px;
--- a/configure.in
+++ b/configure.in
@@ -7148,17 +7148,20 @@ AC_SUBST(DLLFLAGS)
 dnl We need to wrap dlopen and related functions on Android because we use
 dnl our own linker.
 if test "$OS_TARGET" = Android; then
     WRAP_LDFLAGS="${WRAP_LDFLAGS} -L$_objdir/dist/lib -lmozglue"
     if test -n "$MOZ_OLD_LINKER"; then
         WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=dlopen,--wrap=dlclose,--wrap=dlerror,--wrap=dlsym,--wrap=dladdr"
     fi
     WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=getaddrinfo,--wrap=freeaddrinfo,--wrap=gai_strerror"
-    WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=fork,--wrap=pthread_atfork,--wrap=raise,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
+    WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl--wrap=PR_GetEnv,--wrap=PR_SetEnv"
+    if test -z "$gonkdir"; then
+        WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=fork,--wrap=pthread_atfork,--wrap=raise"
+    fi
 fi
 
 dnl ========================================================
 dnl = Use malloc wrapper lib
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(wrap-malloc,
 [  --enable-wrap-malloc    Wrap malloc calls (gnu linker only)],
     _WRAP_MALLOC=1,
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsINode_h___
 #define nsINode_h___
 
 #include "mozilla/ErrorResult.h"
+#include "mozilla/Likely.h"
 #include "nsCOMPtr.h"               // for member, local
 #include "nsGkAtoms.h"              // for nsGkAtoms::baseURIProperty
 #include "nsIDOMEventTarget.h"      // for base class
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeSelector.h"     // base class
 #include "nsINodeInfo.h"            // member (in nsCOMPtr)
 #include "nsIVariant.h"             // for use in GetUserData()
 #include "nsNodeInfoManager.h"      // for use in NodePrincipal()
@@ -733,17 +734,17 @@ public:
     return mNodeInfo->NodeInfoManager()->DocumentPrincipal();
   }
 
   /**
    * Get the parent nsIContent for this node.
    * @return the parent, or null if no parent or the parent is not an nsIContent
    */
   nsIContent* GetParent() const {
-    return NS_LIKELY(GetBoolFlag(ParentIsContent)) ?
+    return MOZ_LIKELY(GetBoolFlag(ParentIsContent)) ?
       reinterpret_cast<nsIContent*>(mParent) : nullptr;
   }
 
   /**
    * Get the parent nsINode for this node. This can be either an nsIContent,
    * an nsIDocument or an nsIAttribute.
    * @return the parent node
    */
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -6,16 +6,17 @@
 
 /*
  * Base class for all element classes; this provides an implementation
  * of DOM Core's nsIDOMElement, implements nsIContent, provides
  * utility methods for subclasses, and so forth.
  */
 
 #include "mozilla/Util.h"
+#include "mozilla/Likely.h"
 
 #include "mozilla/dom/FragmentOrElement.h"
 
 #include "nsDOMAttribute.h"
 #include "nsDOMAttributeMap.h"
 #include "nsIAtom.h"
 #include "nsINodeInfo.h"
 #include "nsIDocument.h"
@@ -1552,17 +1553,17 @@ static const char* kNSURIs[] = {
   " (MathML)",
   " (RDF)",
   " (XUL)",
   " (SVG)",
   " (XML Events)"
 };
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
-  if (NS_UNLIKELY(cb.WantDebugInfo())) {
+  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     char name[512];
     uint32_t nsid = tmp->GetNameSpaceID();
     nsAtomCString localName(tmp->NodeInfo()->NameAtom());
     nsAutoCString uri;
     if (tmp->OwnerDoc()->GetDocumentURI()) {
       tmp->OwnerDoc()->GetDocumentURI()->GetSpec(uri);
     }
 
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -16,16 +16,17 @@
 #include "nsIDocument.h"
 #include "nsGenericElement.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsContentUtils.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsGkAtoms.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 #include "mozilla/dom/NodeListBinding.h"
+#include "mozilla/Likely.h"
 
 // Form related includes
 #include "nsIDOMHTMLFormElement.h"
 
 #include "pldhash.h"
 
 #ifdef DEBUG_CONTENT_LIST
 #include "nsIContentIterator.h"
@@ -43,17 +44,17 @@ nsBaseContentList::~nsBaseContentList()
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsBaseContentList)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBaseContentList)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mElements)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBaseContentList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   if (nsCCUncollectableMarker::sGeneration && tmp->IsBlack() &&
-      NS_LIKELY(!cb.WantAllTraces())) {
+      MOZ_LIKELY(!cb.WantAllTraces())) {
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mElements)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsBaseContentList)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=2 sw=2 et tw=78: */
 /* 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/. */
 
 /* A namespace class for static layout utilities. */
 
 #include "mozilla/Util.h"
+#include "mozilla/Likely.h"
 
 #include "jsapi.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
 
 #include <math.h>
 
 #include "Layers.h"
@@ -5613,17 +5614,17 @@ nsContentUtils::GetSafeJSContext()
 }
 
 /* static */
 nsresult
 nsContentUtils::ASCIIToLower(nsAString& aStr)
 {
   PRUnichar* iter = aStr.BeginWriting();
   PRUnichar* end = aStr.EndWriting();
-  if (NS_UNLIKELY(!iter || !end)) {
+  if (MOZ_UNLIKELY(!iter || !end)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   while (iter != end) {
     PRUnichar c = *iter;
     if (c >= 'A' && c <= 'Z') {
       *iter = c + ('a' - 'A');
     }
     ++iter;
@@ -5634,17 +5635,17 @@ nsContentUtils::ASCIIToLower(nsAString& 
 /* static */
 nsresult
 nsContentUtils::ASCIIToLower(const nsAString& aSource, nsAString& aDest)
 {
   uint32_t len = aSource.Length();
   aDest.SetLength(len);
   if (aDest.Length() == len) {
     PRUnichar* dest = aDest.BeginWriting();
-    if (NS_UNLIKELY(!dest)) {
+    if (MOZ_UNLIKELY(!dest)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
     const PRUnichar* iter = aSource.BeginReading();
     const PRUnichar* end = aSource.EndReading();
     while (iter != end) {
       PRUnichar c = *iter;
       *dest = (c >= 'A' && c <= 'Z') ?
          c + ('a' - 'A') : c;
@@ -5657,17 +5658,17 @@ nsContentUtils::ASCIIToLower(const nsASt
 }
 
 /* static */
 nsresult
 nsContentUtils::ASCIIToUpper(nsAString& aStr)
 {
   PRUnichar* iter = aStr.BeginWriting();
   PRUnichar* end = aStr.EndWriting();
-  if (NS_UNLIKELY(!iter || !end)) {
+  if (MOZ_UNLIKELY(!iter || !end)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   while (iter != end) {
     PRUnichar c = *iter;
     if (c >= 'a' && c <= 'z') {
       *iter = c + ('A' - 'a');
     }
     ++iter;
@@ -5678,17 +5679,17 @@ nsContentUtils::ASCIIToUpper(nsAString& 
 /* static */
 nsresult
 nsContentUtils::ASCIIToUpper(const nsAString& aSource, nsAString& aDest)
 {
   uint32_t len = aSource.Length();
   aDest.SetLength(len);
   if (aDest.Length() == len) {
     PRUnichar* dest = aDest.BeginWriting();
-    if (NS_UNLIKELY(!dest)) {
+    if (MOZ_UNLIKELY(!dest)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
     const PRUnichar* iter = aSource.BeginReading();
     const PRUnichar* end = aSource.EndReading();
     while (iter != end) {
       PRUnichar c = *iter;
       *dest = (c >= 'a' && c <= 'z') ?
          c + ('A' - 'a') : c;
@@ -6608,71 +6609,55 @@ nsContentUtils::FindInternalContentViewe
       else
       *aLoaderType = TYPE_UNKNOWN;
     }
     return docFactory.forget();
   }
 
 #ifdef MOZ_MEDIA
 #ifdef MOZ_OGG
-  if (nsHTMLMediaElement::IsOggEnabled()) {
-    for (unsigned int i = 0; i < ArrayLength(nsHTMLMediaElement::gOggTypes); ++i) {
-      const char* type = nsHTMLMediaElement::gOggTypes[i];
-      if (!strcmp(aType, type)) {
-        docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
-        if (docFactory && aLoaderType) {
-          *aLoaderType = TYPE_CONTENT;
-        }
-        return docFactory.forget();
-      }
+  if (nsHTMLMediaElement::IsOggType(nsDependentCString(aType))) {
+    docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
+    if (docFactory && aLoaderType) {
+      *aLoaderType = TYPE_CONTENT;
     }
+    return docFactory.forget();
   }
 #endif
 
 #ifdef MOZ_WEBM
-  if (nsHTMLMediaElement::IsWebMEnabled()) {
-    for (unsigned int i = 0; i < ArrayLength(nsHTMLMediaElement::gWebMTypes); ++i) {
-      const char* type = nsHTMLMediaElement::gWebMTypes[i];
-      if (!strcmp(aType, type)) {
-        docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
-        if (docFactory && aLoaderType) {
-          *aLoaderType = TYPE_CONTENT;
-        }
-        return docFactory.forget();
-      }
+  if (nsHTMLMediaElement::IsWebMType(nsDependentCString(aType))) {
+    docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
+    if (docFactory && aLoaderType) {
+      *aLoaderType = TYPE_CONTENT;
     }
+    return docFactory.forget();
   }
 #endif
 
 #ifdef MOZ_GSTREAMER
-  if (nsHTMLMediaElement::IsH264Enabled()) {
-    for (unsigned int i = 0; i < ArrayLength(nsHTMLMediaElement::gH264Types); ++i) {
-      const char* type = nsHTMLMediaElement::gH264Types[i];
-      if (!strcmp(aType, type)) {
-        docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
-        if (docFactory && aLoaderType) {
-          *aLoaderType = TYPE_CONTENT;
-        }
-        return docFactory.forget();
-      }
+  if (nsHTMLMediaElement::IsGStreamerSupportedType(nsDependentCString(aType))) {
+    docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
+    if (docFactory && aLoaderType) {
+      *aLoaderType = TYPE_CONTENT;
     }
+    return docFactory.forget();
   }
 #endif
 
 #ifdef MOZ_MEDIA_PLUGINS
   if (nsHTMLMediaElement::IsMediaPluginsEnabled() &&
       nsHTMLMediaElement::IsMediaPluginsType(nsDependentCString(aType))) {
     docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
     if (docFactory && aLoaderType) {
       *aLoaderType = TYPE_CONTENT;
     }
     return docFactory.forget();
   }
 #endif // MOZ_MEDIA_PLUGINS
-
 #endif // MOZ_MEDIA
 
   return NULL;
 }
 
 // static
 bool
 nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -4,16 +4,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/. */
 
 /*
  * Base class for all our document implementations.
  */
 
 #include "mozilla/Util.h"
+#include "mozilla/Likely.h"
 
 #ifdef MOZ_LOGGING
 // so we can get logging even in release builds
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
 #include "plstr.h"
 #include "prprf.h"
@@ -1584,17 +1585,17 @@ static const char* kNSURIs[] = {
   "(XSLT)",
   "(XBL)",
   "(MathML)",
   "(RDF)",
   "(XUL)"
 };
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
-  if (NS_UNLIKELY(cb.WantDebugInfo())) {
+  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     char name[512];
     nsAutoCString loadedAsData;
     if (tmp->IsLoadedAsData()) {
       loadedAsData.AssignLiteral("data");
     } else {
       loadedAsData.AssignLiteral("normal");
     }
     uint32_t nsid = tmp->GetDefaultNamespaceID();
@@ -9053,17 +9054,17 @@ nsDocument::IsFullScreenEnabled(bool aCa
     LogFullScreenDenied(aLogFailure, "FullScreenDeniedHidden", this);
     return false;
   }
   if (HasFullScreenSubDocument(this)) {
     LogFullScreenDenied(aLogFailure, "FullScreenDeniedSubDocFullScreen", this);
     return false;
   }
 
-  // Ensure that all ancestor <iframe> elements have the mozallowfullscreen
+  // Ensure that all ancestor <iframe> elements have the allowfullscreen
   // boolean attribute set.
   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
   bool allowed = false;
   if (docShell) {
     docShell->GetFullscreenAllowed(&allowed);
   }
   if (!allowed) {
     LogFullScreenDenied(aLogFailure, "FullScreenDeniedIframeDisallowed", this);
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -68,16 +68,17 @@ GK_ATOM(after, "after")
 GK_ATOM(after_end, "after_end")
 GK_ATOM(after_start, "after_start")
 GK_ATOM(align, "align")
 GK_ATOM(alink, "alink")
 GK_ATOM(all, "all")
 GK_ATOM(allowevents, "allowevents")
 GK_ATOM(allowforms, "allow-forms")
 GK_ATOM(allownegativeassertions, "allownegativeassertions")
+GK_ATOM(allowfullscreen, "allowfullscreen")
 GK_ATOM(allowsameorigin, "allow-same-origin")
 GK_ATOM(allowscripts, "allow-scripts")
 GK_ATOM(allowtopnavigation, "allow-top-navigation")
 GK_ATOM(allowuntrusted, "allowuntrusted")
 GK_ATOM(alt, "alt")
 GK_ATOM(alternate, "alternate")
 GK_ATOM(always, "always")
 GK_ATOM(ancestor, "ancestor")
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -8,16 +8,17 @@
  * Base class for all DOM nodes.
  */
 
 #include "nsINode.h"
 
 #include "jsapi.h"
 #include "mozAutoDocUpdate.h"
 #include "mozilla/CORSMode.h"
+#include "mozilla/Likely.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Util.h"
 #include "nsAsyncDOMEvent.h"
 #include "nsAttrValueOrString.h"
 #include "nsBindingManager.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsClientRect.h"
 #include "nsContentCreatorFunctions.h"
@@ -1137,17 +1138,17 @@ nsINode::UnoptimizableCCNode() const
          (IsElement() &&
           AsElement()->IsInNamespace(kNameSpaceID_XBL));
 }
 
 /* static */
 bool
 nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
 {
-  if (NS_LIKELY(!cb.WantAllTraces())) {
+  if (MOZ_LIKELY(!cb.WantAllTraces())) {
     nsIDocument *currentDoc = tmp->GetCurrentDoc();
     if (currentDoc &&
         nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) {
       return false;
     }
 
     if (nsCCUncollectableMarker::sGeneration) {
       // If we're black no need to traverse.
--- a/content/base/src/nsNodeInfo.cpp
+++ b/content/base/src/nsNodeInfo.cpp
@@ -5,16 +5,17 @@
 
 /*
  * Class that represents a prefix/namespace/localName triple; a single
  * nodeinfo is shared by all elements in a document that have that
  * prefix, namespace, and localName.
  */
 
 #include "mozilla/Util.h"
+#include "mozilla/Likely.h"
 
 #include "nscore.h"
 #include "nsNodeInfo.h"
 #include "nsNodeInfoManager.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsIAtom.h"
 #include "nsDOMString.h"
@@ -159,17 +160,17 @@ static const char* kNSURIs[] = {
   " (XSLT)",
   " (XBL)",
   " (MathML)",
   " (RDF)",
   " (XUL)"
 };
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsNodeInfo)
-  if (NS_UNLIKELY(cb.WantDebugInfo())) {
+  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     char name[72];
     uint32_t nsid = tmp->NamespaceID();
     nsAtomCString localName(tmp->NameAtom());
     if (nsid < ArrayLength(kNSURIs)) {
       PR_snprintf(name, sizeof(name), "nsNodeInfo%s %s", kNSURIs[nsid],
                   localName.get());
     }
     else {
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -25,16 +25,17 @@
 #include "nsGkAtoms.h"
 #include "nsContentUtils.h"
 #include "nsGenericDOMDataNode.h"
 #include "nsClientRect.h"
 #include "nsLayoutUtils.h"
 #include "nsTextFrame.h"
 #include "nsFontFaceList.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/Likely.h"
 
 using namespace mozilla;
 
 /******************************************************
  * stack based utilty class for managing monitor
  ******************************************************/
 
 // NS_ERROR_DOM_NOT_OBJECT_ERR is not the correct one to throw, but spec doesn't say
@@ -390,17 +391,17 @@ nsRange::CharacterDataChanged(nsIDocumen
       // splitText(), aInfo->mDetails->mNextSibling is the new text node
       NS_ASSERTION(aInfo->mDetails->mType ==
                    CharacterDataChangeInfo::Details::eSplit,
                    "only a split can start before the end");
       NS_ASSERTION(static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd + 1,
                    "mStartOffset is beyond the end of this node");
       newStartOffset = static_cast<uint32_t>(mStartOffset) - aInfo->mChangeStart;
       newStartNode = aInfo->mDetails->mNextSibling;
-      if (NS_UNLIKELY(aContent == mRoot)) {
+      if (MOZ_UNLIKELY(aContent == mRoot)) {
         newRoot = IsValidBoundary(newStartNode);
       }
 
       bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
       if (isCommonAncestor) {
         UnregisterCommonAncestor(mStartParent);
         RegisterCommonAncestor(newStartNode);
       }
@@ -452,24 +453,24 @@ nsRange::CharacterDataChanged(nsIDocumen
   if (aInfo->mDetails &&
       aInfo->mDetails->mType == CharacterDataChangeInfo::Details::eMerge) {
     // normalize(), aInfo->mDetails->mNextSibling is the merged text node
     // that will be removed
     nsIContent* removed = aInfo->mDetails->mNextSibling;
     if (removed == mStartParent) {
       newStartOffset = static_cast<uint32_t>(mStartOffset) + aInfo->mChangeStart;
       newStartNode = aContent;
-      if (NS_UNLIKELY(removed == mRoot)) {
+      if (MOZ_UNLIKELY(removed == mRoot)) {
         newRoot = IsValidBoundary(newStartNode);
       }
     }
     if (removed == mEndParent) {
       newEndOffset = static_cast<uint32_t>(mEndOffset) + aInfo->mChangeStart;
       newEndNode = aContent;
-      if (NS_UNLIKELY(removed == mRoot)) {
+      if (MOZ_UNLIKELY(removed == mRoot)) {
         newRoot = IsValidBoundary(newEndNode);
       }
     }
   }
   if (newStartNode || newEndNode) {
     if (!newStartNode) {
       newStartNode = mStartParent;
       newStartOffset = mStartOffset;
--- a/content/events/src/nsDOMEventTargetHelper.cpp
+++ b/content/events/src/nsDOMEventTargetHelper.cpp
@@ -8,25 +8,26 @@
 #include "nsEventDispatcher.h"
 #include "nsGUIEvent.h"
 #include "nsIDocument.h"
 #include "nsIJSContextStack.h"
 #include "nsDOMJSUtils.h"
 #include "prprf.h"
 #include "nsGlobalWindow.h"
 #include "nsDOMEvent.h"
+#include "mozilla/Likely.h"
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMEventTargetHelper)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDOMEventTargetHelper)
-  if (NS_UNLIKELY(cb.WantDebugInfo())) {
+  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     char name[512];
     nsAutoString uri;
     if (tmp->mOwner && tmp->mOwner->GetExtantDocument()) {
       tmp->mOwner->GetExtantDocument()->GetDocumentURI(uri);
     }
     PR_snprintf(name, sizeof(name), "nsDOMEventTargetHelper %s",
                 NS_ConvertUTF16toUTF8(uri).get());
     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -303,17 +303,18 @@ public:
 #ifdef MOZ_WEBM
   static bool IsWebMEnabled();
   static bool IsWebMType(const nsACString& aType);
   static const char gWebMTypes[2][11];
   static char const *const gWebMCodecs[4];
 #endif
 
 #ifdef MOZ_GSTREAMER
-  static bool IsH264Enabled();
+  static bool IsGStreamerEnabled();
+  static bool IsGStreamerSupportedType(const nsACString& aType);
   static bool IsH264Type(const nsACString& aType);
   static const char gH264Types[3][16];
   static char const *const gH264Codecs[7];
 #endif
 
 #ifdef MOZ_WIDGET_GONK
   static bool IsOmxEnabled();
   static bool IsOmxSupportedType(const nsACString& aType);
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
+#include "mozilla/Likely.h"
 
 #include "nscore.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsCOMPtr.h"
 #include "nsIAtom.h"
 #include "nsIContentViewer.h"
 #include "mozilla/css/StyleRule.h"
@@ -1032,17 +1033,17 @@ StartElement(Element* aContent, StringBu
     // Bug 16988.  Yuck.
     if (localName == nsGkAtoms::br && tagNS == kNameSpaceID_XHTML &&
         attName == nsGkAtoms::type && attNs == kNameSpaceID_None &&
         StringBeginsWith(*attValue, NS_LITERAL_STRING("_moz"))) {
       delete attValue;
       continue;
     }
     
-    if (NS_LIKELY(attNs == kNameSpaceID_None) ||
+    if (MOZ_LIKELY(attNs == kNameSpaceID_None) ||
         (attNs == kNameSpaceID_XMLNS &&
          attName == nsGkAtoms::xmlns)) {
       aBuilder.Append(" ");
     } else if (attNs == kNameSpaceID_XML) {
       aBuilder.Append(" xml:");
     } else if (attNs == kNameSpaceID_XMLNS) {
       aBuilder.Append(" xmlns:");
     } else if (attNs == kNameSpaceID_XLink) {
@@ -2153,17 +2154,17 @@ nsGenericHTMLElement::ParseBackgroundAtt
     nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
         getter_AddRefs(uri), aValue, doc, baseURI);
     if (NS_FAILED(rv)) {
       return false;
     }
 
     nsString value(aValue);
     nsRefPtr<nsStringBuffer> buffer = nsCSSValue::BufferFromString(value);
-    if (NS_UNLIKELY(!buffer)) {
+    if (MOZ_UNLIKELY(!buffer)) {
       return false;
     }
 
     mozilla::css::URLValue *url =
       new mozilla::css::URLValue(buffer, baseURI, uri, NodePrincipal());
     aResult.SetTo(url, &aValue);
     return true;
   }
--- a/content/html/content/src/nsHTMLIFrameElement.cpp
+++ b/content/html/content/src/nsHTMLIFrameElement.cpp
@@ -50,17 +50,17 @@ NS_IMPL_STRING_ATTR(nsHTMLIFrameElement,
 NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Height, height)
 NS_IMPL_URI_ATTR(nsHTMLIFrameElement, LongDesc, longdesc)
 NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, MarginHeight, marginheight)
 NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, MarginWidth, marginwidth)
 NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Name, name)
 NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Scrolling, scrolling)
 NS_IMPL_URI_ATTR(nsHTMLIFrameElement, Src, src)
 NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Width, width)
-NS_IMPL_BOOL_ATTR(nsHTMLIFrameElement, MozAllowFullScreen, mozallowfullscreen)
+NS_IMPL_BOOL_ATTR(nsHTMLIFrameElement, Allowfullscreen, allowfullscreen)
 NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Sandbox, sandbox)
 
 void
 nsHTMLIFrameElement::GetItemValueText(nsAString& aValue)
 {
   GetSrc(aValue);
 }
 
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -270,17 +270,17 @@ nsHTMLInputElement::nsFilePickerShownCal
         continue;
       }
       nsCOMPtr<nsIDOMFile> domFile =
         do_QueryObject(new nsDOMFileFile(localFile));
       newFiles.AppendObject(domFile);
       if (!prefSaved) {
         // Store the last used directory using the content pref service
         nsHTMLInputElement::gUploadLastDir->StoreLastUsedDirectory(
-          mInput->OwnerDoc()->GetDocumentURI(), localFile);
+          mInput->OwnerDoc(), localFile);
         prefSaved = true;
       }
     }
   }
   else {
     nsCOMPtr<nsIFile> localFile;
     nsresult rv = mFilePicker->GetFile(getter_AddRefs(localFile));
     NS_ENSURE_SUCCESS(rv, rv);
@@ -288,17 +288,17 @@ nsHTMLInputElement::nsFilePickerShownCal
       nsString path;
       rv = localFile->GetPath(path);
       if (!path.IsEmpty()) {
         nsCOMPtr<nsIDOMFile> domFile=
           do_QueryObject(new nsDOMFileFile(localFile));
         newFiles.AppendObject(domFile);
         // Store the last used directory using the content pref service
         nsHTMLInputElement::gUploadLastDir->StoreLastUsedDirectory(
-          mInput->OwnerDoc()->GetDocumentURI(), localFile);
+          mInput->OwnerDoc(), localFile);
       }
     }
   }
 
   if (!newFiles.Count()) {
     return NS_OK;
   }
 
@@ -405,17 +405,17 @@ nsHTMLInputElement::AsyncClickHandler::R
       oldFiles[0]->GetName(leafName);
       if (!leafName.IsEmpty()) {
         filePicker->SetDefaultString(leafName);
       }
     }
   } else {
     // Attempt to retrieve the last used directory from the content pref service
     nsCOMPtr<nsIFile> localFile;
-    nsHTMLInputElement::gUploadLastDir->FetchLastUsedDirectory(doc->GetDocumentURI(),
+    nsHTMLInputElement::gUploadLastDir->FetchLastUsedDirectory(doc,
                                                                getter_AddRefs(localFile));
     if (!localFile) {
       // Default to "desktop" directory for each platform
       nsCOMPtr<nsIFile> homeDir;
       NS_GetSpecialDirectory(NS_OS_DESKTOP_DIR, getter_AddRefs(homeDir));
       localFile = do_QueryInterface(homeDir);
     }
     filePicker->SetDisplayDirectory(localFile);
@@ -443,88 +443,102 @@ nsHTMLInputElement::InitUploadLastDir() 
 }
 
 void 
 nsHTMLInputElement::DestroyUploadLastDir() {
   NS_IF_RELEASE(gUploadLastDir);
 }
 
 nsresult
-UploadLastDir::FetchLastUsedDirectory(nsIURI* aURI, nsIFile** aFile)
+UploadLastDir::FetchLastUsedDirectory(nsIDocument* aDoc, nsIFile** aFile)
 {
-  NS_PRECONDITION(aURI, "aURI is null");
+  NS_PRECONDITION(aDoc, "aDoc is null");
   NS_PRECONDITION(aFile, "aFile is null");
+
+  nsIURI* docURI = aDoc->GetDocumentURI();
+  NS_PRECONDITION(docURI, "docURI is null");
+
+  nsCOMPtr<nsISupports> container = aDoc->GetContainer();
+  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(container);
+
   // Attempt to get the CPS, if it's not present we'll just return
   nsCOMPtr<nsIContentPrefService> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   if (!contentPrefService)
     return NS_ERROR_NOT_AVAILABLE;
   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
   if (!uri)
     return NS_ERROR_OUT_OF_MEMORY;
-  uri->SetAsISupports(aURI);
+  uri->SetAsISupports(docURI);
 
   // Get the last used directory, if it is stored
   bool hasPref;
-  if (NS_SUCCEEDED(contentPrefService->HasPref(uri, CPS_PREF_NAME, &hasPref)) && hasPref) {
+  if (NS_SUCCEEDED(contentPrefService->HasPref(uri, CPS_PREF_NAME, loadContext, &hasPref)) && hasPref) {
     nsCOMPtr<nsIVariant> pref;
-    contentPrefService->GetPref(uri, CPS_PREF_NAME, nullptr, getter_AddRefs(pref));
+    contentPrefService->GetPref(uri, CPS_PREF_NAME, loadContext, nullptr, getter_AddRefs(pref));
     nsString prefStr;
     pref->GetAsAString(prefStr);
 
     nsCOMPtr<nsIFile> localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
     if (!localFile)
       return NS_ERROR_OUT_OF_MEMORY;
     localFile->InitWithPath(prefStr);
     localFile.forget(aFile);
   }
   return NS_OK;
 }
 
 nsresult
-UploadLastDir::StoreLastUsedDirectory(nsIURI* aURI, nsIFile* aFile)
+UploadLastDir::StoreLastUsedDirectory(nsIDocument* aDoc, nsIFile* aFile)
 {
-  NS_PRECONDITION(aURI, "aURI is null");
+  NS_PRECONDITION(aDoc, "aDoc is null");
   NS_PRECONDITION(aFile, "aFile is null");
+
+  nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
+  NS_PRECONDITION(docURI, "docURI is null");
+
   nsCOMPtr<nsIFile> parentFile;
   aFile->GetParent(getter_AddRefs(parentFile));
   if (!parentFile) {
     return NS_OK;
   }
 
   // Attempt to get the CPS, if it's not present we'll just return
   nsCOMPtr<nsIContentPrefService> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   if (!contentPrefService)
     return NS_ERROR_NOT_AVAILABLE;
   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
   if (!uri)
     return NS_ERROR_OUT_OF_MEMORY;
-  uri->SetAsISupports(aURI);
+  uri->SetAsISupports(docURI);
  
   // Find the parent of aFile, and store it
   nsString unicodePath;
   parentFile->GetPath(unicodePath);
   if (unicodePath.IsEmpty()) // nothing to do
     return NS_OK;
   nsCOMPtr<nsIWritableVariant> prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID);
   if (!prefValue)
     return NS_ERROR_OUT_OF_MEMORY;
   prefValue->SetAsAString(unicodePath);
-  return contentPrefService->SetPref(uri, CPS_PREF_NAME, prefValue);
+
+  nsCOMPtr<nsISupports> container = aDoc->GetContainer();
+  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(container);
+  return contentPrefService->SetPref(uri, CPS_PREF_NAME, prefValue, loadContext);
 }
 
 NS_IMETHODIMP
 UploadLastDir::Observe(nsISupports *aSubject, char const *aTopic, PRUnichar const *aData)
 {
   if (strcmp(aTopic, "browser:purge-session-history") == 0) {
     nsCOMPtr<nsIContentPrefService> contentPrefService =
       do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
     if (contentPrefService)
-      contentPrefService->RemovePrefsByName(CPS_PREF_NAME);
+      contentPrefService->RemovePrefsByName(CPS_PREF_NAME, nullptr);
   }
   return NS_OK;
 }
 
 #ifdef ACCESSIBILITY
 //Helper method
 static nsresult FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
                                           nsPresContext* aPresContext,
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -30,29 +30,29 @@ class UploadLastDir MOZ_FINAL : public n
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   /**
    * Fetch the last used directory for this location from the content
    * pref service, if it is available.
    *
-   * @param aURI URI of the current page
+   * @param aDoc  current document
    * @param aFile path to the last used directory
    */
-  nsresult FetchLastUsedDirectory(nsIURI* aURI, nsIFile** aFile);
+  nsresult FetchLastUsedDirectory(nsIDocument* aDoc, nsIFile** aFile);
 
   /**
    * Store the last used directory for this location using the
    * content pref service, if it is available
    * @param aURI URI of the current page
    * @param aFile file chosen by the user - the path to the parent of this
    *        file will be stored
    */
-  nsresult StoreLastUsedDirectory(nsIURI* aURI, nsIFile* aFile);
+  nsresult StoreLastUsedDirectory(nsIDocument* aDoc, nsIFile* aFile);
 };
 
 class nsHTMLInputElement : public nsGenericHTMLFormElement,
                            public nsImageLoadingContent,
                            public nsIDOMHTMLInputElement,
                            public nsITextControlElement,
                            public nsIPhonetic,
                            public nsIDOMNSEditableElement,
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -2148,34 +2148,29 @@ char const *const nsHTMLMediaElement::gH
 #ifdef MOZ_GSTREAMER
 const char nsHTMLMediaElement::gH264Types[3][16] = {
   "video/mp4",
   "video/3gpp",
   "video/quicktime",
 };
 
 bool
-nsHTMLMediaElement::IsH264Enabled()
+nsHTMLMediaElement::IsGStreamerEnabled()
 {
-  return Preferences::GetBool("media.h264.enabled");
+  return Preferences::GetBool("media.gstreamer.enabled");
 }
 
 bool
 nsHTMLMediaElement::IsH264Type(const nsACString& aType)
 {
-  if (!IsH264Enabled()) {
-    return false;
-  }
-
   for (uint32_t i = 0; i < ArrayLength(gH264Types); ++i) {
     if (aType.EqualsASCII(gH264Types[i])) {
       return true;
     }
   }
-
   return false;
 }
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 const char nsHTMLMediaElement::gOmxTypes[5][16] = {
   "audio/mpeg",
   "audio/mp4",
@@ -2260,17 +2255,17 @@ nsHTMLMediaElement::IsDASHMPDType(const 
     }
   }
 
   return false;
 }
 #endif
 
 /* static */
-nsHTMLMediaElement::CanPlayStatus 
+nsHTMLMediaElement::CanPlayStatus
 nsHTMLMediaElement::CanHandleMediaType(const char* aMIMEType,
                                        char const *const ** aCodecList)
 {
 #ifdef MOZ_RAW
   if (IsRawType(nsDependentCString(aMIMEType))) {
     *aCodecList = gRawCodecs;
     return CANPLAY_MAYBE;
   }
@@ -2424,34 +2419,64 @@ nsHTMLMediaElement::CanPlayType(const ns
   default:
   case CANPLAY_MAYBE:
     aResult.AssignLiteral("maybe");
     break;
   }
   return NS_OK;
 }
 
+#ifdef MOZ_GSTREAMER
+bool
+nsHTMLMediaElement::IsGStreamerSupportedType(const nsACString& aMimeType)
+{
+  if (!IsGStreamerEnabled())
+    return false;
+  if (IsH264Type(aMimeType))
+    return true;
+  if (!Preferences::GetBool("media.prefer-gstreamer", false))
+    return false;
+#ifdef MOZ_WEBM
+  if (IsWebMType(aMimeType))
+    return true;
+#endif
+#ifdef MOZ_OGG
+  if (IsOggType(aMimeType))
+    return true;
+#endif
+  return false;
+}
+#endif
+
 already_AddRefed<nsMediaDecoder>
 nsHTMLMediaElement::CreateDecoder(const nsACString& aType)
 {
+
+#ifdef MOZ_GSTREAMER
+  // When enabled, use GStreamer for H.264, but not for codecs handled by our
+  // bundled decoders, unless the "media.prefer-gstreamer" pref is set.
+  if (IsGStreamerSupportedType(aType)) {
+    nsRefPtr<nsGStreamerDecoder> decoder = new nsGStreamerDecoder();
+    if (decoder->Init(this)) {
+      return decoder.forget();
+    }
+  }
+#endif
+
 #ifdef MOZ_RAW
   if (IsRawType(aType)) {
     nsRefPtr<nsRawDecoder> decoder = new nsRawDecoder();
     if (decoder->Init(this)) {
       return decoder.forget();
     }
   }
 #endif
 #ifdef MOZ_OGG
   if (IsOggType(aType)) {
-#ifdef MOZ_GSTREAMER 
-    nsRefPtr<nsGStreamerDecoder> decoder = new nsGStreamerDecoder();
-#else
     nsRefPtr<nsOggDecoder> decoder = new nsOggDecoder();
-#endif
     if (decoder->Init(this)) {
       return decoder.forget();
     }
   }
 #endif
 #ifdef MOZ_WAVE
   if (IsWaveType(aType)) {
     nsRefPtr<nsWaveDecoder> decoder = new nsWaveDecoder();
@@ -2473,44 +2498,32 @@ nsHTMLMediaElement::CreateDecoder(const 
     nsRefPtr<nsMediaPluginDecoder> decoder = new nsMediaPluginDecoder(aType);
     if (decoder->Init(this)) {
       return decoder.forget();
     }
   }
 #endif
 #ifdef MOZ_WEBM
   if (IsWebMType(aType)) {
-#ifdef MOZ_GSTREAMER 
-    nsRefPtr<nsGStreamerDecoder> decoder = new nsGStreamerDecoder();
-#else
     nsRefPtr<nsWebMDecoder> decoder = new nsWebMDecoder();
-#endif
     if (decoder->Init(this)) {
       return decoder.forget();
     }
   }
 #endif
 
 #ifdef MOZ_DASH
   if (IsDASHMPDType(aType)) {
     nsRefPtr<nsDASHDecoder> decoder = new nsDASHDecoder();
     if (decoder->Init(this)) {
       return decoder.forget();
     }
   }
 #endif
 
-#ifdef MOZ_GSTREAMER 
-  if (IsH264Type(aType)) {
-    nsRefPtr<nsGStreamerDecoder> decoder = new nsGStreamerDecoder();
-    if (decoder->Init(this)) {
-      return decoder.forget();
-    }
-  }
-#endif
   return nullptr;
 }
 
 nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
 {
   NS_ASSERTION(mLoadingSrc, "mLoadingSrc must already be set");
   NS_ASSERTION(mDecoder == nullptr, "Shouldn't have a decoder");
 
--- a/content/html/content/test/file_fullscreen-api.html
+++ b/content/html/content/test/file_fullscreen-api.html
@@ -73,17 +73,17 @@ function enter1(event) {
   is(document.mozFullScreenElement, null, "8. Full-screen element should still be null after re-adding former FSE.");
 }
 
 function exit1(event) {
   ok(!document.mozFullScreen, "9. Should have left full-screen mode (first time)");
   is(event.target, document, "10. Event target should be full-screen document #2");
   is(document.mozFullScreenElement, null, "11. Full-screen element should be null.");
   iframe = document.createElement("iframe");
-  iframe.mozAllowFullScreen = true;
+  iframe.allowfullscreen = true;
   addFullscreenChangeContinuation("enter", enter2);
   document.body.appendChild(iframe);
   iframe.src = iframeContents;
 }
 
 function enter2(event) {
   ok(document.mozFullScreen, "12. Should be back in full-screen mode (second time)");
   is(event.target, document, "13. Event target should be full-screen document #3");
--- a/content/html/content/test/file_fullscreen-denied-inner.html
+++ b/content/html/content/test/file_fullscreen-denied-inner.html
@@ -1,22 +1,22 @@
 <html>
   <body onload='foo();'>
   <script>
     function foo() {
       document.addEventListener('mozfullscreenerror',
         function() {
-          parent.ok(true, "Request from an iframe without mozallowfullscreen should be denied");
+          parent.ok(true, "Request from an iframe without allowfullscreen should be denied");
           parent.finish();
         },
         false);
       document.addEventListener('mozfullscreenchange',
         function() {
-          parent.ok(false, "Request from an iframe without mozallowfullscreen should be denied, but was granted!");
+          parent.ok(false, "Request from an iframe without allowfullscreen should be denied, but was granted!");
           parent.finish();
         },
         false);
-      parent.is(document.mozFullScreenEnabled, false, "Full-screen should not be enabled, coz mozallowfullscreen isn't present.");
+      parent.is(document.mozFullScreenEnabled, false, "Full-screen should not be enabled, coz allowfullscreen isn't present.");
       document.body.mozRequestFullScreen();    
     }
   </script>
   </body>
 </html>
--- a/content/html/content/test/file_fullscreen-denied.html
+++ b/content/html/content/test/file_fullscreen-denied.html
@@ -66,17 +66,17 @@ function keyHandler(event) {
   addFullscreenErrorContinuation(
     function() {
       ok(!document.mozFullScreen, "Should not grant request in long-running event handler.");
 
       // Disable the requirement for trusted contexts only, so the tests are easier
       // to write.
       SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
 
-      // Create an iframe without a mozallowfullscreen attribute, whose contents requests
+      // Create an iframe without a allowfullscreen attribute, whose contents requests
       // full-screen. The request should be denied, and we should not receive a fullscreenchange
       // event in this document.
       var iframe = document.createElement("iframe");
       iframe.src = "file_fullscreen-denied-inner.html";
       document.body.appendChild(iframe);
     });
   document.body.mozRequestFullScreen();
 }
--- a/content/html/content/test/file_fullscreen-hidden.html
+++ b/content/html/content/test/file_fullscreen-hidden.html
@@ -5,17 +5,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 -->
 <head>
   <title>Test for Bug 697636</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 
-<iframe id="f" src="data:text/html,<body text=green>1" mozallowfullscreen></iframe>
+<iframe id="f" src="data:text/html,<body text=green>1" allowfullscreen></iframe>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=697636">Mozilla Bug 697636</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
--- a/content/html/content/test/file_fullscreen-navigation.html
+++ b/content/html/content/test/file_fullscreen-navigation.html
@@ -5,17 +5,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 -->
 <head>
   <title>Test for Bug 685402</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body style="background-color: gray;">
 
-<iframe id="f" src="data:text/html,<body text=green>1" mozallowfullscreen></iframe>
+<iframe id="f" src="data:text/html,<body text=green>1" allowfullscreen></iframe>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=685402">Mozilla Bug 685402</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
--- a/content/html/content/test/file_fullscreen-rollback.html
+++ b/content/html/content/test/file_fullscreen-rollback.html
@@ -21,17 +21,17 @@ Tests:
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="application/javascript" src="file_fullscreen-utils.js"></script>
 </head>
 <body>
 
 <div id="fse">
   <div id="fse-inner">
-    <iframe id="subdoc" mozallowfullscreen src="data:text/html,<html><body bgcolor='black'></body></html>"></iframe>
+    <iframe id="subdoc" allowfullscreen src="data:text/html,<html><body bgcolor='black'></body></html>"></iframe>
   </div>
 </div>
 
 <div id="non-fse"></div>
 
 <script type="application/javascript">
 
 /** Test for Bug 700764 **/
--- a/content/html/content/test/test_fullscreen-api.html
+++ b/content/html/content/test/test_fullscreen-api.html
@@ -26,17 +26,17 @@
 // Ensure the full-screen api is enabled, and will be disabled on test exit.
 SpecialPowers.setBoolPref("full-screen-api.enabled", true);
 
 // Disable the requirement for trusted contexts only, so the tests are easier
 // to write.
 SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
 
 // Run the tests which go full-screen in new windows, as mochitests normally
-// run in an iframe, which by default will not have the mozallowfullscreen
+// run in an iframe, which by default will not have the allowfullscreen
 // attribute set, so full-screen won't work.
 var gTestWindows = [
   "file_fullscreen-rollback.html",
   "file_fullscreen-esc-exit.html",
   "file_fullscreen-denied.html",
   "file_fullscreen-api.html",
   "file_fullscreen-api-keys.html",
   "file_fullscreen-plugins.html",
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/AudioEventTimeline.h
@@ -0,0 +1,374 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#pragma once
+
+#include "mozilla/Attributes.h"
+#include "mozilla/FloatingPoint.h"
+#include "nsTArray.h"
+#include "math.h"
+
+namespace mozilla {
+
+namespace dom {
+
+/**
+ * This class will be instantiated with different template arguments for testing and
+ * production code.
+ *
+ * FloatArrayWrapper is a type which satisfies the following:
+ *  - Is copy-constructible.
+ *  - Implements a Data() method returning a float*, representing an array.
+ *  - Implements a Length() method returning a uint32_t, representing the array length.
+ *  - Implements an inited() method returning true for valid objects.
+ * ErrorResult is a type which satisfies the following:
+ *  - Implements a Throw() method taking an nsresult argument, representing an error code.
+ */
+template <class FloatArrayWrapper, class ErrorResult>
+class AudioEventTimeline
+{
+private:
+  struct Event {
+    enum Type MOZ_ENUM_TYPE(uint32_t) {
+      SetValue,
+      LinearRamp,
+      ExponentialRamp,
+      SetTarget,
+      SetValueCurve
+    };
+
+    Event(Type aType, float aTime, float aValue, float aTimeConstant = 0.0,
+          float aDuration = 0.0, FloatArrayWrapper aCurve = FloatArrayWrapper())
+      : mType(aType)
+      , mTime(aTime)
+      , mValue(aValue)
+      , mTimeConstant(aTimeConstant)
+      , mDuration(aDuration)
+    {
+      if (aCurve.inited()) {
+        mCurve = aCurve;
+      }
+    }
+
+    bool IsValid() const
+    {
+      return IsValid(mTime) &&
+             IsValid(mValue) &&
+             IsValid(mTimeConstant) &&
+             IsValid(mDuration);
+    }
+
+    Type mType;
+    float mTime;
+    float mValue;
+    float mTimeConstant;
+    float mDuration;
+    FloatArrayWrapper mCurve;
+
+  private:
+    static bool IsValid(float value)
+    {
+      return MOZ_DOUBLE_IS_FINITE(value);
+    }
+  };
+
+public:
+  AudioEventTimeline(float aDefaultValue,
+                     float aMinValue,
+                     float aMaxValue)
+    : mValue(aDefaultValue)
+    , mDefaultValue(aDefaultValue)
+    , mMinValue(aMinValue)
+    , mMaxValue(aMaxValue)
+  {
+    MOZ_ASSERT(aDefaultValue >= aMinValue);
+    MOZ_ASSERT(aDefaultValue <= aMaxValue);
+    MOZ_ASSERT(aMinValue < aMaxValue);
+  }
+
+  float Value() const
+  {
+    // TODO: Return the current value based on the timeline of the AudioContext
+    return mValue;
+  }
+
+  void SetValue(float aValue)
+  {
+    // Silently don't change anything if there are any events
+    if (mEvents.IsEmpty()) {
+      mValue = aValue;
+    }
+  }
+
+  float ComputedValue() const
+  {
+    // TODO: implement
+    return 0;
+  }
+
+  float MinValue() const
+  {
+    return mMinValue;
+  }
+
+  float MaxValue() const
+  {
+    return mMaxValue;
+  }
+
+  float DefaultValue() const
+  {
+    return mDefaultValue;
+  }
+
+  void SetValueAtTime(float aValue, float aStartTime, ErrorResult& aRv)
+  {
+    InsertEvent(Event(Event::Type::SetValue, aStartTime, aValue), aRv);
+  }
+
+  void LinearRampToValueAtTime(float aValue, float aEndTime, ErrorResult& aRv)
+  {
+    InsertEvent(Event(Event::Type::LinearRamp, aEndTime, aValue), aRv);
+  }
+
+  void ExponentialRampToValueAtTime(float aValue, float aEndTime, ErrorResult& aRv)
+  {
+    InsertEvent(Event(Event::Type::ExponentialRamp, aEndTime, aValue), aRv);
+  }
+
+  void SetTargetAtTime(float aTarget, float aStartTime, float aTimeConstant, ErrorResult& aRv)
+  {
+    InsertEvent(Event(Event::Type::SetTarget, aStartTime, aTarget, aTimeConstant), aRv);
+  }
+
+  void SetValueCurveAtTime(const FloatArrayWrapper& aValues, float aStartTime, float aDuration, ErrorResult& aRv)
+  {
+    // TODO: implement
+    // InsertEvent(Event(Event::Type::SetValueCurve, aStartTime, 0.0f, 0.0f, aDuration, aValues), aRv);
+  }
+
+  void CancelScheduledValues(float aStartTime)
+  {
+    // TODO: implement
+  }
+
+  // This method computes the AudioParam value at a given time based on the event timeline
+  float GetValueAtTime(float aTime) const
+  {
+    const Event* previous = nullptr;
+    const Event* next = nullptr;
+
+    bool bailOut = false;
+    for (unsigned i = 0; !bailOut && i < mEvents.Length(); ++i) {
+      switch (mEvents[i].mType) {
+      case Event::Type::SetValue:
+      case Event::Type::SetTarget:
+      case Event::Type::LinearRamp:
+      case Event::Type::ExponentialRamp:
+        if (aTime == mEvents[i].mTime) {
+          // Find the last event with the same time
+          do {
+            ++i;
+          } while (i < mEvents.Length() &&
+                   aTime == mEvents[i].mTime);
+          return mEvents[i - 1].mValue;
+        }
+        previous = next;
+        next = &mEvents[i];
+        if (aTime < mEvents[i].mTime) {
+          bailOut = true;
+        }
+        break;
+      case Event::Type::SetValueCurve:
+        // TODO: implement
+        break;
+      default:
+        MOZ_ASSERT(false, "unreached");
+      }
+    }
+    // Handle the case where the time is past all of the events
+    if (!bailOut) {
+      previous = next;
+      next = nullptr;
+    }
+
+    // Just return the default value if we did not find anything
+    if (!previous && !next) {
+      return mValue;
+    }
+
+    // If the requested time is before all of the existing events
+    if (!previous) {
+      switch (next->mType) {
+      case Event::Type::SetValue:
+      case Event::Type::SetTarget:
+        // The requested time is before the first event
+        return mValue;
+      case Event::Type::LinearRamp:
+        // Use t=0 as T0 and v=defaultValue as V0
+        return LinearInterpolate(0.0f, mValue, next->mTime, next->mValue, aTime);
+      case Event::Type::ExponentialRamp:
+        // Use t=0 as T0 and v=defaultValue as V0
+        return ExponentialInterpolate(0.0f, mValue, next->mTime, next->mValue, aTime);
+      case Event::Type::SetValueCurve:
+        // TODO: implement
+        return 0.0f;
+      }
+      MOZ_ASSERT(false, "unreached");
+    }
+
+    // SetTarget nodes can be handled no matter what their next node is (if they have one)
+    if (previous->mType == Event::Type::SetTarget) {
+      // Follow the curve, without regard to the next node
+      return ExponentialApproach(previous->mTime, mValue, previous->mValue,
+                                 previous->mTimeConstant, aTime);
+    }
+
+    // If the requested time is after all of the existing events
+    if (!next) {
+      switch (previous->mType) {
+      case Event::Type::SetValue:
+      case Event::Type::LinearRamp:
+      case Event::Type::ExponentialRamp:
+        // The value will be constant after the last event
+        return previous->mValue;
+      case Event::Type::SetValueCurve:
+        // TODO: implement
+        return 0.0f;
+      case Event::Type::SetTarget:
+        MOZ_ASSERT(false, "unreached");
+      }
+      MOZ_ASSERT(false, "unreached");
+    }
+
+    // Finally, handle the case where we have both a previous and a next event
+
+    // First, handle the case where our range ends up in a ramp event
+    switch (next->mType) {
+    case Event::Type::LinearRamp:
+      return LinearInterpolate(previous->mTime, previous->mValue, next->mTime, next->mValue, aTime);
+    case Event::Type::ExponentialRamp:
+      return ExponentialInterpolate(previous->mTime, previous->mValue, next->mTime, next->mValue, aTime);
+    case Event::Type::SetValue:
+    case Event::Type::SetTarget:
+    case Event::Type::SetValueCurve:
+      break;
+    }
+
+    // Now handle all other cases
+    switch (previous->mType) {
+    case Event::Type::SetValue:
+    case Event::Type::LinearRamp:
+    case Event::Type::ExponentialRamp:
+      // If the next event type is neither linear or exponential ramp, the
+      // value is constant.
+      return previous->mValue;
+    case Event::Type::SetValueCurve:
+      // TODO: implement
+      return 0.0f;
+    case Event::Type::SetTarget:
+      MOZ_ASSERT(false, "unreached");
+    }
+
+    MOZ_ASSERT(false, "unreached");
+    return 0.0f;
+  }
+
+  // Return the number of events scheduled
+  uint32_t GetEventCount() const
+  {
+    return mEvents.Length();
+  }
+
+  static float LinearInterpolate(float t0, float v0, float t1, float v1, float t)
+  {
+    return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));
+  }
+
+  static float ExponentialInterpolate(float t0, float v0, float t1, float v1, float t)
+  {
+    return v0 * powf(v1 / v0, (t - t0) / (t1 - t0));
+  }
+
+  static float ExponentialApproach(float t0, float v0, float v1, float timeConstant, float t)
+  {
+    return v1 + (v0 - v1) * expf(-(t - t0) / timeConstant);
+  }
+
+private:
+  void InsertEvent(const Event& aEvent, ErrorResult& aRv)
+  {
+    if (!aEvent.IsValid()) {
+      aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+      return;
+    }
+
+    // Make sure that non-curve events don't fall within the duration of a
+    // curve event.
+    for (unsigned i = 0; i < mEvents.Length(); ++i) {
+      if (mEvents[i].mType == Event::Type::SetValueCurve &&
+          mEvents[i].mTime <= aEvent.mTime &&
+          (mEvents[i].mTime + mEvents[i].mDuration) >= aEvent.mTime) {
+        aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+        return;
+      }
+    }
+
+    // Make sure that curve events don't fall in a range which includes other
+    // events.
+    if (aEvent.mType == Event::Type::SetValueCurve) {
+      for (unsigned i = 0; i < mEvents.Length(); ++i) {
+        if (mEvents[i].mTime >= aEvent.mTime &&
+            mEvents[i].mTime <= (aEvent.mTime + aEvent.mDuration)) {
+          aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+          return;
+        }
+      }
+    }
+
+    for (unsigned i = 0; i < mEvents.Length(); ++i) {
+      if (aEvent.mTime == mEvents[i].mTime) {
+        if (aEvent.mType == mEvents[i].mType) {
+          // If times and types are equal, replace the event
+          mEvents.ReplaceElementAt(i, aEvent);
+        } else {
+          // Otherwise, place the element after the last event of another type
+          do {
+            ++i;
+          } while (i < mEvents.Length() &&
+                   aEvent.mType != mEvents[i].mType &&
+                   aEvent.mTime == mEvents[i].mTime);
+          mEvents.InsertElementAt(i, aEvent);
+        }
+        return;
+      }
+      // Otherwise, place the event right after the latest existing event
+      if (aEvent.mTime < mEvents[i].mTime) {
+        mEvents.InsertElementAt(i, aEvent);
+        return;
+      }
+    }
+
+    // If we couldn't find a place for the event, just append it to the list
+    mEvents.AppendElement(aEvent);
+  }
+
+private:
+  // This is a sorted array of the events in the timeline.  Queries of this
+  // data structure should probably be more frequent than modifications to it,
+  // and that is the reason why we're using a simple array as the data structure.
+  // We can optimize this in the future if the performance of the array ends up
+  // being a bottleneck.
+  nsTArray<Event> mEvents;
+  float mValue;
+  const float mDefaultValue;
+  const float mMinValue;
+  const float mMaxValue;
+};
+
+}
+}
+
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/AudioParam.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "AudioParam.h"
+#include "nsContentUtils.h"
+#include "nsIDOMWindow.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/AudioParamBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(AudioParam)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(AudioParam)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER_NATIVE
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(AudioParam)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mContext, AudioContext)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(AudioParam)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioParam, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioParam, Release)
+
+AudioParam::AudioParam(AudioContext* aContext,
+                       float aDefaultValue,
+                       float aMinValue,
+                       float aMaxValue)
+  : AudioParamTimeline(aDefaultValue, aMinValue, aMaxValue)
+  , mContext(aContext)
+{
+  SetIsDOMBinding();
+}
+
+AudioParam::~AudioParam()
+{
+}
+
+JSObject*
+AudioParam::WrapObject(JSContext* aCx, JSObject* aScope,
+                         bool* aTriedToWrap)
+{
+  return AudioParamBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
+}
+}
+
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/AudioParam.h
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#pragma once
+
+#include "AudioEventTimeline.h"
+#include "nsWrapperCache.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsCOMPtr.h"
+#include "EnableWebAudioCheck.h"
+#include "nsAutoPtr.h"
+#include "AudioContext.h"
+#include "mozilla/dom/TypedArray.h"
+#include "mozilla/Util.h"
+
+class JSContext;
+class nsIDOMWindow;
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+namespace detail {
+
+// This class wraps a JS typed array so that AudioEventTimeline does not need
+// to know about JSObjects directly.
+class FloatArrayWrapper
+{
+public:
+  FloatArrayWrapper() // creates an uninitialized object
+  {
+  }
+  FloatArrayWrapper(const Float32Array& array)
+  {
+    mArray.construct(array);
+  }
+  FloatArrayWrapper(const FloatArrayWrapper& rhs)
+  {
+    MOZ_ASSERT(!rhs.mArray.empty());
+    mArray.construct(rhs.mArray.ref());
+  }
+
+  FloatArrayWrapper& operator=(const FloatArrayWrapper& rhs)
+  {
+    MOZ_ASSERT(!rhs.mArray.empty());
+    mArray.destroyIfConstructed();
+    mArray.construct(rhs.mArray.ref());
+    return *this;
+  }
+
+  // Expose the API used by AudioEventTimeline
+  float* Data() const
+  {
+    MOZ_ASSERT(inited());
+    return mArray.ref().Data();
+  }
+  uint32_t Length() const
+  {
+    MOZ_ASSERT(inited());
+    return mArray.ref().Length();
+  }
+  bool inited() const
+  {
+    return !mArray.empty();
+  }
+
+private:
+  Maybe<Float32Array> mArray;
+};
+
+}
+
+typedef AudioEventTimeline<detail::FloatArrayWrapper, ErrorResult> AudioParamTimeline;
+
+class AudioParam MOZ_FINAL : public nsWrapperCache,
+                             public EnableWebAudioCheck,
+                             public AudioParamTimeline
+{
+public:
+  AudioParam(AudioContext* aContext,
+             float aDefaultValue,
+             float aMinValue,
+             float aMaxValue);
+  virtual ~AudioParam();
+
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioParam)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioParam)
+
+  AudioContext* GetParentObject() const
+  {
+    return mContext;
+  }
+
+  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
+                               bool* aTriedToWrap);
+
+  // We override SetValueCurveAtTime to convert the Float32Array to the wrapper
+  // object.
+  void SetValueCurveAtTime(JSContext* cx, const Float32Array& aValues, float aStartTime, float aDuration, ErrorResult& aRv)
+  {
+    AudioParamTimeline::SetValueCurveAtTime(detail::FloatArrayWrapper(aValues),
+                                            aStartTime, aDuration, aRv);
+  }
+
+private:
+  nsRefPtr<AudioContext> mContext;
+};
+
+}
+}
+
--- a/content/media/webaudio/Makefile.in
+++ b/content/media/webaudio/Makefile.in
@@ -15,26 +15,32 @@ LIBRARY_NAME   := gkconwebaudio_s
 LIBXUL_LIBRARY := 1
 
 CPPSRCS := \
   AudioBuffer.cpp \
   AudioBufferSourceNode.cpp \
   AudioContext.cpp \
   AudioDestinationNode.cpp \
   AudioNode.cpp \
+  AudioParam.cpp \
   AudioSourceNode.cpp \
   EnableWebAudioCheck.cpp \
   $(NULL)
 
 EXPORTS_NAMESPACES := mozilla/dom
 EXPORTS_mozilla/dom := \
   AudioBuffer.h \
   AudioBufferSourceNode.h \
   AudioDestinationNode.h \
   AudioNode.h \
+  AudioParam.h \
   AudioSourceNode.h \
   $(NULL)
 
 PARALLEL_DIRS := test
 
+ifdef ENABLE_TESTS
+TOOL_DIRS += compiledtest
+endif
+
 FORCE_STATIC_LIB := 1
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/compiledtest/Makefile.in
@@ -0,0 +1,19 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH          := @DEPTH@
+topsrcdir      := @top_srcdir@
+srcdir         := @srcdir@
+VPATH          := @srcdir@
+relativesrcdir := @relativesrcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+LOCAL_INCLUDES := -I$(srcdir)/..
+
+CPP_UNIT_TESTS := \
+  TestAudioEventTimeline.cpp \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/compiledtest/TestAudioEventTimeline.cpp
@@ -0,0 +1,343 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "AudioEventTimeline.h"
+#include "TestHarness.h"
+#include <sstream>
+#include <limits>
+
+using namespace mozilla::dom;
+using std::numeric_limits;
+
+// Some simple testing primitives
+void ok(bool val, const char* msg)
+{
+  if (val) {
+    passed(msg);
+  } else {
+    fail(msg);
+  }
+}
+
+namespace std {
+
+template <class T>
+basic_ostream<T, char_traits<T> >&
+operator<<(basic_ostream<T, char_traits<T> >& os, nsresult rv)
+{
+  os << static_cast<uint32_t>(rv);
+  return os;
+}
+
+}
+
+template <class T, class U>
+void is(const T& a, const U& b, const char* msg)
+{
+  std::stringstream ss;
+  ss << msg << ", Got: " << a << ", expected: " << b;
+  ok(a == b, ss.str().c_str());
+}
+
+template <>
+void is(const float& a, const float& b, const char* msg)
+{
+  // stupidly high, since we mostly care about the correctness of the algorithm
+  const float kEpsilon = 0.00001f;
+
+  std::stringstream ss;
+  ss << msg << ", Got: " << a << ", expected: " << b;
+  ok(fabsf(a - b) < kEpsilon, ss.str().c_str());
+}
+
+class FloatArrayMock
+{
+public:
+  // This implementation is not used for now, so let's just return dummy values.
+  float* Data() const
+  {
+    return nullptr;
+  }
+  uint32_t Length() const
+  {
+    return 0;
+  }
+  bool inited() const
+  {
+    return true;
+  }
+};
+
+class ErrorResultMock
+{
+public:
+  ErrorResultMock()
+    : mRv(NS_OK)
+  {
+  }
+  void Throw(nsresult aRv)
+  {
+    mRv = aRv;
+  }
+
+  operator nsresult() const
+  {
+    return mRv;
+  }
+
+private:
+  nsresult mRv;
+};
+
+typedef AudioEventTimeline<FloatArrayMock, ErrorResultMock> Timeline;
+
+void TestSpecExample()
+{
+  // First, run the basic tests
+  Timeline timeline(10.0f, .1f, 20.0f);
+  is(timeline.DefaultValue(), 10.0f, "Correct default value returned");
+  is(timeline.MinValue(), .1f, "Correct min value returned");
+  is(timeline.MaxValue(), 20.0f, "Correct max value returned");
+
+  ErrorResultMock rv;
+
+  // This test is copied from the example in the Web Audio spec
+  const float t0 = 0.0f,
+              t1 = 0.1f,
+              t2 = 0.2f,
+              t3 = 0.3f,
+              t4 = 0.4f,
+              t5 = 0.6f,
+              t6 = 0.7f/*,
+              t7 = 1.0f*/;
+  timeline.SetValueAtTime(0.2f, t0, rv);
+  is(rv, NS_OK, "SetValueAtTime succeeded");
+  timeline.SetValueAtTime(0.3f, t1, rv);
+  is(rv, NS_OK, "SetValueAtTime succeeded");
+  timeline.SetValueAtTime(0.4f, t2, rv);
+  is(rv, NS_OK, "SetValueAtTime succeeded");
+  timeline.LinearRampToValueAtTime(1.0f, t3, rv);
+  is(rv, NS_OK, "LinearRampToValueAtTime succeeded");
+  timeline.LinearRampToValueAtTime(0.15f, t4, rv);
+  is(rv, NS_OK, "LinearRampToValueAtTime succeeded");
+  timeline.ExponentialRampToValueAtTime(0.75f, t5, rv);
+  is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded");
+  timeline.ExponentialRampToValueAtTime(0.05f, t6, rv);
+  is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded");
+  // TODO: Add the SetValueCurveAtTime test
+
+  is(timeline.GetValueAtTime(0.0f), 0.2f, "Correct value");
+  is(timeline.GetValueAtTime(0.05f), 0.2f, "Correct value");
+  is(timeline.GetValueAtTime(0.1f), 0.3f, "Correct value");
+  is(timeline.GetValueAtTime(0.15f), 0.3f, "Correct value");
+  is(timeline.GetValueAtTime(0.2f), 0.4f, "Correct value");
+  is(timeline.GetValueAtTime(0.25f), (0.4f + 1.0f) / 2, "Correct value");
+  is(timeline.GetValueAtTime(0.3f), 1.0f, "Correct value");
+  is(timeline.GetValueAtTime(0.35f), (1.0f + 0.15f) / 2, "Correct value");
+  is(timeline.GetValueAtTime(0.4f), 0.15f, "Correct value");
+  is(timeline.GetValueAtTime(0.45f), (0.15f * powf(0.75f / 0.15f, 0.05f / 0.2f)), "Correct value");
+  is(timeline.GetValueAtTime(0.5f), (0.15f * powf(0.75f / 0.15f, 0.5f)), "Correct value");
+  is(timeline.GetValueAtTime(0.55f), (0.15f * powf(0.75f / 0.15f, 0.15f / 0.2f)), "Correct value");
+  is(timeline.GetValueAtTime(0.6f), 0.75f, "Correct value");
+  is(timeline.GetValueAtTime(0.65f), (0.75f * powf(0.05 / 0.75f, 0.5f)), "Correct value");
+  is(timeline.GetValueAtTime(0.7f), 0.05f, "Correct value");
+  is(timeline.GetValueAtTime(1.0f), 0.05f, "Correct value");
+}
+
+void TestInvalidEvents()
+{
+  MOZ_STATIC_ASSERT(numeric_limits<float>::has_quiet_NaN, "Platform must have a quiet NaN");
+  const float NaN = numeric_limits<float>::quiet_NaN();
+  const float Infinity = numeric_limits<float>::infinity();
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  timeline.SetValueAtTime(NaN, 0.1f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueAtTime(Infinity, 0.1f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueAtTime(-Infinity, 0.1f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.LinearRampToValueAtTime(NaN, 0.2f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.LinearRampToValueAtTime(Infinity, 0.2f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.LinearRampToValueAtTime(-Infinity, 0.2f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.ExponentialRampToValueAtTime(NaN, 0.3f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.ExponentialRampToValueAtTime(Infinity, 0.3f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.ExponentialRampToValueAtTime(-Infinity, 0.4f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetTargetAtTime(NaN, 0.4f, 1.0f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetTargetAtTime(Infinity, 0.4f, 1.0f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetTargetAtTime(-Infinity, 0.4f, 1.0f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetTargetAtTime(0.4f, NaN, 1.0f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetTargetAtTime(0.4f, Infinity, 1.0f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetTargetAtTime(0.4f, -Infinity, 1.0f, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  // TODO: Test SetValueCurveAtTime
+}
+
+void TestEventReplacement()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  is(timeline.GetEventCount(), 0, "No events yet");
+  timeline.SetValueAtTime(10.0f, 0.1f, rv);
+  is(timeline.GetEventCount(), 1, "One event scheduled now");
+  timeline.SetValueAtTime(20.0f, 0.1f, rv);
+  is(rv, NS_OK, "Event scheduling should be successful");
+  is(timeline.GetEventCount(), 1, "Event should be replaced");
+  is(timeline.GetValueAtTime(0.1f), 20.0f, "The first event should be overwritten");
+  timeline.LinearRampToValueAtTime(30.0f, 0.1f, rv);
+  is(rv, NS_OK, "Event scheduling should be successful");
+  is(timeline.GetEventCount(), 2, "Different event type should be appended");
+  is(timeline.GetValueAtTime(0.1f), 30.0f, "The first event should be overwritten");
+}
+
+void TestBeforeFirstEvent()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  timeline.SetValueAtTime(20.0f, 1.0f, rv);
+  is(timeline.GetValueAtTime(0.5f), 10.0f, "Retrun the default value before the first event");
+}
+
+void TestAfterLastValueEvent()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  timeline.SetValueAtTime(20.0f, 1.0f, rv);
+  is(timeline.GetValueAtTime(1.5f), 20.0f, "Return the last value after the last SetValue event");
+}
+
+void TestAfterLastTargetValueEvent()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  timeline.SetTargetAtTime(20.0f, 1.0f, 5.0f, rv);
+  is(timeline.GetValueAtTime(10.f), (20.f + (10.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after the last SetTarget event based on the curve");
+}
+
+void TestAfterLastTargetValueEventWithValueSet()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  timeline.SetValue(50.f);
+  timeline.SetTargetAtTime(20.0f, 1.0f, 5.0f, rv);
+  is(timeline.GetValueAtTime(10.f), (20.f + (50.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after SetValue and the last SetTarget event based on the curve");
+}
+
+void TestValue()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  is(timeline.Value(), 10.0f, "value should initially match the default value");
+  timeline.SetValue(20.0f);
+  is(timeline.Value(), 20.0f, "Should be able to set the value");
+  timeline.SetValueAtTime(20.0f, 1.0f, rv);
+  // TODO: The following check needs to change when we compute the value based on the current time of the context
+  is(timeline.Value(), 20.0f, "TODO...");
+  timeline.SetValue(30.0f);
+  is(timeline.Value(), 20.0f, "Should not be able to set the value");
+}
+
+void TestLinearRampAtZero()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  timeline.LinearRampToValueAtTime(20.0f, 0.0f, rv);
+  is(timeline.GetValueAtTime(0.0f), 20.0f, "Should get the correct value when t0 == t1 == 0");
+}
+
+void TestExponentialRampAtZero()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  timeline.ExponentialRampToValueAtTime(20.0f, 0.0f, rv);
+  is(timeline.GetValueAtTime(0.0f), 20.0f, "Should get the correct value when t0 == t1 == 0");
+}
+
+void TestLinearRampAtSameTime()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  timeline.SetValueAtTime(5.0f, 1.0f, rv);
+  timeline.LinearRampToValueAtTime(20.0f, 1.0f, rv);
+  is(timeline.GetValueAtTime(1.0f), 20.0f, "Should get the correct value when t0 == t1");
+}
+
+void TestExponentialRampAtSameTime()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  timeline.SetValueAtTime(5.0f, 1.0f, rv);
+  timeline.ExponentialRampToValueAtTime(20.0f, 1.0f, rv);
+  is(timeline.GetValueAtTime(1.0f), 20.0f, "Should get the correct value when t0 == t1");
+}
+
+void TestSetTargetZeroTimeConstant()
+{
+  Timeline timeline(10.0f, .1f, 20.0f);
+
+  ErrorResultMock rv;
+
+  timeline.SetTargetAtTime(20.0f, 1.0f, 0.0f, rv);
+  is(timeline.GetValueAtTime(10.f), 20.f, "Should get the correct value with timeConstant == 0");
+}
+
+int main()
+{
+  ScopedXPCOM xpcom("TestAudioEventTimeline");
+  if (xpcom.failed()) {
+    return 1;
+  }
+
+  TestSpecExample();
+  TestInvalidEvents();
+  TestEventReplacement();
+  TestBeforeFirstEvent();
+  TestAfterLastValueEvent();
+  TestAfterLastTargetValueEvent();
+  TestAfterLastTargetValueEventWithValueSet();
+  TestValue();
+  TestLinearRampAtZero();
+  TestExponentialRampAtZero();
+  TestLinearRampAtSameTime();
+  TestExponentialRampAtSameTime();
+  TestSetTargetZeroTimeConstant();
+
+  return gFailCount > 0;
+}
+
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/StandardInteger.h"
 #include "mozilla/Util.h"
+#include "mozilla/Likely.h"
 
 #include "nsGkAtoms.h"
 #include "nsLayoutUtils.h"
 #include "DOMSVGNumber.h"
 #include "DOMSVGLength.h"
 #include "nsSVGAngle.h"
 #include "nsCOMPtr.h"
 #include "nsIPresShell.h"
@@ -1324,17 +1325,17 @@ nsSVGSVGElement::
   SVGPreserveAspectRatio* pAROverridePtr = new SVGPreserveAspectRatio(aPAR);
   nsresult rv = SetProperty(nsGkAtoms::overridePreserveAspectRatio,
                             pAROverridePtr,
                             ReleasePreserveAspectRatioPropertyValue,
                             true);
   NS_ABORT_IF_FALSE(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
                     "Setting override value when it's already set...?"); 
 
-  if (NS_UNLIKELY(NS_FAILED(rv))) {
+  if (MOZ_UNLIKELY(NS_FAILED(rv))) {
     // property-insertion failed (e.g. OOM in property-table code)
     delete pAROverridePtr;
     return false;
   }
   return true;
 }
 
 const SVGPreserveAspectRatio*
@@ -1438,17 +1439,17 @@ nsSVGSVGElement::SetViewBoxProperty(cons
   nsSVGViewBoxRect* pViewBoxOverridePtr = new nsSVGViewBoxRect(aViewBox);
   nsresult rv = SetProperty(nsGkAtoms::viewBox,
                             pViewBoxOverridePtr,
                             ReleaseViewBoxPropertyValue,
                             true);
   NS_ABORT_IF_FALSE(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
                     "Setting override value when it's already set...?"); 
 
-  if (NS_UNLIKELY(NS_FAILED(rv))) {
+  if (MOZ_UNLIKELY(NS_FAILED(rv))) {
     // property-insertion failed (e.g. OOM in property-table code)
     delete pViewBoxOverridePtr;
     return false;
   }
   return true;
 }
 
 const nsSVGViewBoxRect*
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2145,32 +2145,33 @@ nsDocShell::GetFullscreenAllowed(bool* a
         *aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS);
         return NS_OK;
     }
 
     // Assume false until we determine otherwise...
     *aFullscreenAllowed = false;
 
     // For non-content boundaries, check that the enclosing iframe element
-    // has the mozallowfullscreen attribute set to true. If any ancestor
-    // iframe does not have mozallowfullscreen=true, then fullscreen is
+    // has the allowfullscreen attribute set to true. If any ancestor
+    // iframe does not have allowfullscreen=true, then fullscreen is
     // prohibited.
     nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(GetAsSupports(this));
     if (!win) {
         return NS_OK;
     }
     nsCOMPtr<nsIContent> frameElement = do_QueryInterface(win->GetFrameElementInternal());
     if (frameElement &&
         frameElement->IsHTML(nsGkAtoms::iframe) &&
+        !frameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) &&
         !frameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)) {
         return NS_OK;
     }
 
     // If we have no parent then we're the root docshell; no ancestor of the
-    // original docshell doesn't have a mozallowfullscreen attribute, so
+    // original docshell doesn't have a allowfullscreen attribute, so
     // report fullscreen as allowed.
     nsCOMPtr<nsIDocShellTreeItem> dsti = do_GetInterface(GetAsSupports(this));
     NS_ENSURE_TRUE(dsti, NS_OK);
 
     nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
     dsti->GetParent(getter_AddRefs(parentTreeItem));
     if (!parentTreeItem) {
         *aFullscreenAllowed = true;
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -767,24 +767,24 @@ protected:
     // transaction at the time that this DocShell begins to load
     int32_t                    mPreviousTransIndex;
     int32_t                    mLoadedTransIndex;
 
     uint32_t                   mSandboxFlags;
 
     // mFullscreenAllowed stores how we determine whether fullscreen is allowed
     // when GetFullscreenAllowed() is called. Fullscreen is allowed in a
-    // docshell when all containing iframes have the mozallowfullscreen
+    // docshell when all containing iframes have the allowfullscreen
     // attribute set to true. When mFullscreenAllowed is CHECK_ATTRIBUTES
-    // we check this docshell's containing frame for the mozallowfullscreen
+    // we check this docshell's containing frame for the allowfullscreen
     // attribute, and recurse onto the parent docshell to ensure all containing
-    // frames also have the mozallowfullscreen attribute. If we find an ancestor
+    // frames also have the allowfullscreen attribute. If we find an ancestor
     // docshell with mFullscreenAllowed not equal to CHECK_ATTRIBUTES, we've
     // reached a content boundary, and mFullscreenAllowed denotes whether the
-    // parent across the content boundary has mozallowfullscreen=true in all its
+    // parent across the content boundary has allowfullscreen=true in all its
     // containing iframes. mFullscreenAllowed defaults to CHECK_ATTRIBUTES and
     // is set otherwise when docshells which are content boundaries are created.
     enum FullscreenAllowedState {
         CHECK_ATTRIBUTES,
         PARENT_ALLOWS,
         PARENT_PROHIBITS
     };
     FullscreenAllowedState     mFullscreenAllowed;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -685,19 +685,19 @@ interface nsIDocShell : nsISupports
    * not be allowed.
    */
   [noscript, notxpcom] bool pluginsAllowedInCurrentDoc();
   
 
   /**
    * Attribute that determines whether fullscreen is allowed to be entered for
    * this subtree of the docshell tree. This is true when all iframes containing
-   * this docshell have their "mozallowfullscreen" attribute set to "true".
+   * this docshell have their "allowfullscreen" attribute set to "true".
    * fullscreenAllowed is only writable at content boundaries, where it is used
    * to propagate the value of the cross process parent's iframe's
-   * "mozallowfullscreen" attribute to the child process. Setting
+   * "allowfullscreen" attribute to the child process. Setting
    * fullscreenAllowed on docshells which aren't content boundaries throws an
    * exception.
    */
   [infallible] readonly attribute boolean fullscreenAllowed;
   
   void setFullscreenAllowed(in boolean allowed);
 };
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -542,23 +542,23 @@ WebappsApplication.prototype = {
           this._downloadError = msg.error;
           this.downloading = false;
           this._fireEvent("downloaderror", this._ondownloaderror);
         }
         break;
         case "Webapps:CheckForUpdate:Return:OK":
           for (let prop in msg.app) {
             this[prop] = msg.app[prop];
-            if (msg.event == "downloadapplied") {
-              Services.DOMRequest.fireSuccess(req, this.manifestURL);
-              this._fireEvent("downloadapplied", this._ondownloadapplied);
-            } else if (msg.event == "downloadavailable") {
-              Services.DOMRequest.fireSuccess(req, this.manifestURL);
-              this._fireEvent("downloadavailable", this._ondownloadavailable);
-            }
+          }
+          if (msg.event == "downloadapplied") {
+            Services.DOMRequest.fireSuccess(req, this.manifestURL);
+            this._fireEvent("downloadapplied", this._ondownloadapplied);
+          } else if (msg.event == "downloadavailable") {
+            Services.DOMRequest.fireSuccess(req, this.manifestURL);
+            this._fireEvent("downloadavailable", this._ondownloadavailable);
           }
           break;
         case "Webapps:CheckForUpdate:Return:KO":
           Services.DOMRequest.fireError(req, msg.error);
           break;
         case "Webapps:PackageEvent":
           if (msg.manifestURL != this.manifestURL)
             return;
@@ -575,36 +575,36 @@ WebappsApplication.prototype = {
               let app = msg.app;
               this.progress = app.progress || 0;
               this.downloadAvailable = app.downloadAvailable;
               this.downloading = app.downloading;
               this.readyToApplyDownload = app.readyToApplyDownload;
               this.downloadSize = app.downloadSize || 0;
               this.installState = app.installState;
               this.manifest = app.manifest;
-              this._fireEvent("downloaded", this._ondownloaded);
+              this._fireEvent("downloadsuccess", this._ondownloadsuccess);
               this._fireEvent("downloadapplied", this._ondownloadapplied);
               break;
             case "canceled":
               app = msg.app;
               this.progress = app.progress || 0;
               this.downloadAvailable = app.downloadAvailable;
               this.downloading = app.downloading;
               this.readyToApplyDownload = app.readyToApplyDownload;
               this.downloadSize = app.downloadSize || 0;
               this.installState = app.installState;
               this._downloadError = msg.error;
               this._fireEvent("downloaderror", this._ondownloaderror);
               break;
             case "downloaded":
               app = msg.app;
               this.downloading = app.downloading;
-              this.downloadavailable = app.downloadavailable;
+              this.downloadAvailable = app.downloadAvailable;
               this.readyToApplyDownload = app.readyToApplyDownload;
-              this._fireEvent("downloaded", this._ondownloaded);
+              this._fireEvent("downloadsuccess", this._ondownloadsuccess);
               break;
             case "applied":
               app = msg.app;
               this.readyToApplyDownload = app.readyToApplyDownload;
               this._fireEvent("downloadapplied", this._ondownloadapplied);
               break;
           }
           break;
@@ -664,17 +664,17 @@ WebappsApplicationMgmt.prototype = {
                           ["Webapps:Install:Return:OK", "Webapps:Uninstall:Return:OK"]);
   },
 
   applyDownload: function(aApp) {
     if (!aApp.readyToApplyDownload) {
       return;
     }
 
-    cpmm.sendAsyncMessage("Webapps::ApplyDownload",
+    cpmm.sendAsyncMessage("Webapps:ApplyDownload",
                           { manifestURL: aApp.manifestURL });
   },
 
   getAll: function() {
     let request = this.createRequest();
     cpmm.sendAsyncMessage("Webapps:GetAll", { oid: this._id,
                                               requestID: this.getRequestId(request),
                                               hasPrivileges: this.hasPrivileges });
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -65,17 +65,17 @@ let DOMApplicationRegistry = {
     this.messages = ["Webapps:Install", "Webapps:Uninstall",
                      "Webapps:GetSelf", "Webapps:CheckInstalled",
                      "Webapps:GetInstalled", "Webapps:GetNotInstalled",
                      "Webapps:Launch", "Webapps:GetAll",
                      "Webapps:InstallPackage", "Webapps:GetBasePath",
                      "Webapps:GetList", "Webapps:RegisterForMessages",
                      "Webapps:UnregisterForMessages",
                      "Webapps:CancelDownload", "Webapps:CheckForUpdate",
-                     "Webapps::Download", "Webapps::ApplyDownload",
+                     "Webapps:Download", "Webapps:ApplyDownload",
                      "child-process-shutdown"];
 
     this.frameMessages = ["Webapps:ClearBrowserData"];
 
     this.messages.forEach((function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }).bind(this));
 
@@ -569,17 +569,17 @@ let DOMApplicationRegistry = {
     // nsIPrefBranch throws if pref does not exist, faster to simply write
     // the pref instead of first checking if it is false.
     Services.prefs.setBoolPref("dom.mozApps.used", true);
 
     // We need to check permissions for calls coming from mozApps.mgmt.
     // These are: getAll(), getNotInstalled() and applyDownload()
     if (["Webapps:GetAll",
          "Webapps:GetNotInstalled",
-         "Webapps::ApplyDownload"].indexOf(aMessage.name) != -1) {
+         "Webapps:ApplyDownload"].indexOf(aMessage.name) != -1) {
       if (!aMessage.target.assertPermission("webapps-manage")) {
         debug("mozApps message " + aMessage.name +
         " from a content process with no 'webapps-manage' privileges.");
         return null;
       }
     }
 
     let msg = aMessage.data || {};
@@ -591,17 +591,16 @@ let DOMApplicationRegistry = {
         // always ask for UI to install
         Services.obs.notifyObservers(mm, "webapps-ask-install", JSON.stringify(msg));
         break;
       case "Webapps:GetSelf":
         this.getSelf(msg, mm);
         break;
       case "Webapps:Uninstall":
         this.uninstall(msg, mm);
-        debug("Webapps:Uninstall");
         break;
       case "Webapps:Launch":
         this.launchApp(msg, mm);
         break;
       case "Webapps:CheckInstalled":
         this.checkInstalled(msg, mm);
         break;
       case "Webapps:GetInstalled":
@@ -639,18 +638,18 @@ let DOMApplicationRegistry = {
         this.startDownload(msg.manifestURL);
         break;
       case "Webapps:CancelDownload":
         this.cancelDownload(msg.manifestURL);
         break;
       case "Webapps:CheckForUpdate":
         this.checkForUpdate(msg, mm);
         break;
-      case "Webapps::ApplyDownload":
-        this.ApplyDownload(msg.manifestURL);
+      case "Webapps:ApplyDownload":
+        this.applyDownload(msg.manifestURL);
         break;
       case "Activities:Register:OK":
         this.notifyAppsRegistryReady();
         break;
     }
   },
 
   // Some messages can be listened by several content processes:
@@ -714,84 +713,87 @@ let DOMApplicationRegistry = {
     // This is a HTTP channel.
     let download = this.downloads[aManifestURL]
     download.channel.cancel(Cr.NS_BINDING_ABORTED);
     let app = this.webapps[download.appId];
 
     app.progress = 0;
     app.installState = app.previousState;
     app.downloading = false;
-    app.downloadavailable = false;
+    app.downloadAvailable = false;
     app.downloadSize = 0;
     this._saveApps((function() {
       this.broadcastMessage("Webapps:PackageEvent",
                              { type: "canceled",
                                manifestURL:  aApp.manifestURL,
                                app: app,
                                error: "DOWNLOAD_CANCELED" });
     }).bind(this));
   },
 
-  startDownload: function cancelDownload(aManifestURL) {
-    let app = this.getAppByManifestURL(manifestURL);
+  startDownload: function startDownload(aManifestURL) {
+    debug("startDownload for " + aManifestURL);
+    let id = this._appIdForManifestURL(aManifestURL);
+    let app = this.webapps[id];
     if (!app) {
+      debug("startDownload: No app found for " + aManifestURL);
       return;
     }
 
-    let id = this._appIdForManifestURL(manifestURL);
-
     // We need to get the update manifest here, not the webapp manifest.
     let file = FileUtils.getFile(DIRECTORY_NAME,
                                  ["webapps", id, "update.webapp"], true);
 
     this._loadJSONAsync(file, (function(aJSON) {
       if (!aJSON) {
+        debug("startDownload: No update manifest found at " + file.path + " " + aManifestURL);
         return;
       }
 
-      let manifest = new ManifestHelper(aJSON, app.origin);
+      let manifest = new ManifestHelper(aJSON, app.installOrigin);
       this.downloadPackage(manifest, { manifestURL: aManifestURL,
                                        origin: app.origin }, true,
         function(aId, aManifest) {
           // Success! Keep the zip in of TmpD, we'll move it out when
           // applyDownload() will be called.
           let tmpDir = FileUtils.getDir("TmpD", ["webapps", aId], true, true);
 
           // Save the manifest in TmpD also
           let manFile = tmpDir.clone();
           manFile.append("manifest.webapp");
           DOMApplicationRegistry._writeFile(manFile,
                                             JSON.stringify(aManifest),
                                             function() { });
           // Set state and fire events.
           app.downloading = false;
-          app.downloadavailable = false;
+          app.downloadAvailable = false;
           app.readyToApplyDownload = true;
           DOMApplicationRegistry._saveApps(function() {
             debug("About to fire Webapps:PackageEvent");
             DOMApplicationRegistry.broadcastMessage("Webapps:PackageEvent",
                                                     { type: "downloaded",
-                                                      manifestURL: manifestURL,
+                                                      manifestURL: aManifestURL,
                                                       app: app,
                                                       manifest: aManifest });
           });
         });
     }).bind(this));
   },
 
   applyDownload: function applyDownload(aManifestURL) {
-    let app = this.getAppByManifestURL(manifestURL);
+    debug("applyDownload for " + aManifestURL);
+    let app = this.getAppByManifestURL(aManifestURL);
     if (!app || (app && !app.readyToApplyDownload)) {
       return;
     }
 
-    let id = this._appIdForManifestURL(aApp.manifestURL);
+    let id = this._appIdForManifestURL(app.manifestURL);
 
     // Move the application.zip and manifest.webapp files out of TmpD
-    let tmpDir = FileUtils.getDir("TmpD", ["webapps", aId], true, true);
+    let tmpDir = FileUtils.getDir("TmpD", ["webapps", id], true, true);
     let manFile = tmpDir.clone();
     manFile.append("manifest.webapp");
     let appFile = tmpDir.clone();
     appFile.append("application.zip");
 
     let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
     appFile.moveTo(dir, "application.zip");
     manFile.moveTo(dir, "manifest.webapp");
@@ -800,23 +802,23 @@ let DOMApplicationRegistry = {
       tmpDir.remove(true);
     } catch(e) { }
 
     // Get the manifest, and set properties.
     this.getManifestFor(app.origin, (function(aData) {
       app.readyToApplyDownload = false;
       this.broadcastMessage("Webapps:PackageEvent",
                             { type: "applied",
-                              manifestURL: aApp.manifestURL,
+                              manifestURL: app.manifestURL,
                               app: app,
                               manifest: aData });
       // Update the permissions for this app.
       PermissionsInstaller.installPermissions({ manifest: aData,
                                                 origin: app.origin,
-                                                manifestURL: aApp.manifestURL },
+                                                manifestURL: app.manifestURL },
                                               true);
     }).bind(this));
   },
 
   startOfflineCacheDownload: function startOfflineCacheDownload(aManifest, aApp,
                                                                 aProfileDir,
                                                                 aOfflineCacheObserver) {
     // if the manifest has an appcache_path property, use it to populate the appcache
@@ -830,32 +832,41 @@ let DOMApplicationRegistry = {
       cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
       if (aOfflineCacheObserver) {
         cacheUpdate.addObserver(aOfflineCacheObserver, false);
       }
     }
   },
 
   checkForUpdate: function(aData, aMm) {
-    let app = this.getAppByManifestURL(aData.manifestURL);
-    let installOrigin = app.installOrigin;
+    debug("checkForUpdate for " + aData.manifestURL);
+    let id = this._appIdForManifestURL(aData.manifestURL);
+    let app = this.webapps[id];
 
     if (!app) {
       aData.error = "NO_SUCH_APP";
       aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
       return;
     }
 
     function sendError(aError) {
       aData.error = aError;
       aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
     }
 
     function updatePackagedApp(aManifest) {
       debug("updatePackagedApp");
+
+      // if the app manifestURL has a app:// scheme, we can't have an
+      // update.
+      if (app.manifestURL.startsWith("app://")) {
+        aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+        return;
+      }
+
       let manifest = new ManifestHelper(aManifest, app.manifestURL);
       // A package is available: set downloadAvailable to fire the matching
       // event.
       app.downloadAvailable = true;
       app.downloadSize = manifest.size;
       aData.event = "downloadavailable";
       aData.app = {
         downloadAvailable: true,
@@ -905,56 +916,57 @@ let DOMApplicationRegistry = {
       }
 
       app.name = aManifest.name;
       app.csp = aManifest.csp || "";
 
       // Update the registry.
       this.webapps[id] = app;
 
-      this._saveApps((function() {
-        // XXX Should we fire notifications ?
-      }).bind(this));
+      this._saveApps(function() {
+        aData.event = "downloadapplied";
+        aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
+      });
 
       // Preload the appcache if needed.
       this.startOfflineCacheDownload(manifest, app);
 
       // Update the permissions for this app.
       PermissionsInstaller.installPermissions({ manifest: aManifest,
                                                 origin: app.origin,
                                                 manifestURL: aData.manifestURL },
-                                              true);
+                                                true);
     }
 
     // First, we download the manifest.
     let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
     xhr.open("GET", aData.manifestURL, true);
-    if (aData.etag) {
-      xhr.setRequestHeader("If-None-Match", aData.etag);
+    if (app.etag) {
+      xhr.setRequestHeader("If-None-Match", app.etag);
     }
 
     xhr.addEventListener("load", (function() {
       if (xhr.status == 200) {
         let manifest;
         try {
           manifest = JSON.parse(xhr.responseText);
         } catch(e) {
           sendError("MANIFEST_PARSE_ERROR");
           return;
         }
-        if (!AppsUtils.checkManifest(manifest, installOrigin)) {
+        if (!AppsUtils.checkManifest(manifest, app.installOrigin)) {
           sendError("INVALID_MANIFEST");
         } else {
           app.etag = xhr.getResponseHeader("Etag");
           app.lastCheckedUpdate = Date.now();
-          if (manifest.package_path) {
+          if (app.origin.startsWith("app://")) {
             updatePackagedApp(manifest);
           } else {
-            updateHostedApp(manifest);
+            updateHostedApp.call(this, manifest);
           }
         }
         this._saveApps();
       } else if (xhr.status == 304) {
         // The manifest has not changed. We just update lastCheckedUpdate.
         app.lastCheckedUpdate = Date.now();
         aData.event = "downloadapplied";
         aData.app = {
@@ -963,17 +975,17 @@ let DOMApplicationRegistry = {
         aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
         this._saveApps();
       } else {
         sendError("MANIFEST_URL_ERROR");
       }
     }).bind(this), false);
 
     xhr.addEventListener("error", (function() {
-      sendError(request, "NETWORK_ERROR");
+      sendError("NETWORK_ERROR");
     }).bind(this), false);
 
     xhr.send(null);
   },
 
   denyInstall: function(aData) {
     let packageId = aData.app.packageId;
     if (packageId) {
@@ -1114,24 +1126,24 @@ let DOMApplicationRegistry = {
         let manFile = dir.clone();
         manFile.append("manifest.webapp");
         DOMApplicationRegistry._writeFile(manFile,
                                           JSON.stringify(aManifest),
                                           function() { });
         // Set state and fire events.
         app.installState = "installed";
         app.downloading = false;
-        app.downloadavailable = false;
+        app.downloadAvailable = false;
         DOMApplicationRegistry._saveApps(function() {
           // Update the permissions for this app.
           PermissionsInstaller.installPermissions({ manifest: aManifest,
                                                     origin: appObject.origin,
                                                     manifestURL: appObject.manifestURL },
                                                   true);
-          debug("About to fire Webapps:PackageEvent");
+          debug("About to fire Webapps:PackageEvent 'installed'");
           DOMApplicationRegistry.broadcastMessage("Webapps:PackageEvent",
                                                   { type: "installed",
                                                     manifestURL: appObject.manifestURL,
                                                     app: app,
                                                     manifest: aManifest });
         });
       });
     }
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -548,16 +548,17 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "nsDebug.h"
 
 #ifdef MOZ_WEBRTC
 #include "nsIDOMDataChannel.h"
 #endif
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
+#include "mozilla/Likely.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
   "chrome://global/locale/dom/dom.properties";
@@ -697,16 +698,34 @@ DOMCI_DATA_NO_CLASS(DOMConstructor)
   NS_DEFINE_CLASSINFO_DATA_WITH_NAME(_class, _class, _helper, _flags)
 
 #define NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(_class, _helper, _flags)          \
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA_WITH_NAME(_class, _class, _helper, \
                                                  _flags)
 
 namespace {
 
+class IDBFactorySH : public nsDOMGenericSH
+{
+protected:
+  IDBFactorySH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
+  { }
+
+  virtual ~IDBFactorySH()
+  { }
+
+public:
+  NS_IMETHOD PostCreatePrototype(JSContext * cx, JSObject * proto);
+
+  static nsIClassInfo *doCreate(nsDOMClassInfoData *aData)
+  {
+    return new IDBFactorySH(aData);
+  }
+};
+
 class IDBEventTargetSH : public nsEventTargetSH
 {
 protected:
   IDBEventTargetSH(nsDOMClassInfoData* aData) : nsEventTargetSH(aData)
   { }
 
   virtual ~IDBEventTargetSH()
   { }
@@ -1575,17 +1594,17 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(FormData, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DesktopNotification, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DesktopNotificationCenter, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(IDBFactory, nsDOMGenericSH,
+  NS_DEFINE_CLASSINFO_DATA(IDBFactory, IDBFactorySH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA_WITH_NAME(IDBFileHandle, FileHandle, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBRequest, IDBEventTargetSH,
                            IDBEVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBDatabase, IDBEventTargetSH,
                            IDBEVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBObjectStore, nsDOMGenericSH,
@@ -6678,22 +6697,50 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
           !ConstructorEnabled(name_struct, aWin)) {
         return NS_OK;
       }
 
       if (name_struct->mPrefEnabled && !(*name_struct->mPrefEnabled)()) {
         return NS_OK;
       }
 
+      Maybe<JSAutoCompartment> ac;
+      JSObject* global;
+      bool defineOnXray = ObjectIsNativeWrapper(cx, obj);
+      if (defineOnXray) {
+        global = xpc::Unwrap(cx, obj, false);
+        if (!global) {
+          return NS_ERROR_DOM_SECURITY_ERR;
+        }
+        ac.construct(cx, global);
+      } else {
+        global = obj;
+      }
+
       bool enabled;
-      bool defined = define(cx, obj, &enabled);
-      MOZ_ASSERT_IF(defined, enabled);
+      JSObject* interfaceObject = define(cx, global, &enabled);
       if (enabled) {
-        *did_resolve = defined;
-        return defined ? NS_OK : NS_ERROR_FAILURE;
+        if (!interfaceObject) {
+          return NS_ERROR_FAILURE;
+        }
+
+        if (defineOnXray) {
+          // This really should be handled by the Xray for the window.
+          ac.destroy();
+          if (!JS_WrapObject(cx, &interfaceObject) ||
+              !JS_DefinePropertyById(cx, obj, id,
+                                     JS::ObjectValue(*interfaceObject), nullptr,
+                                     nullptr, 0)) {
+            return NS_ERROR_FAILURE;
+          }
+        }
+
+        *did_resolve = true;
+
+        return NS_OK;
       }
     }
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeInterface) {
     // We're resolving a name of a DOM interface for which there is no
     // direct DOM class, create a constructor object...
     nsRefPtr<nsDOMConstructor> constructor;
@@ -7934,16 +7981,102 @@ nsDOMMutationObserverSH::AddProperty(nsI
 void
 nsDOMMutationObserverSH::PreserveWrapper(nsISupports* aNative)
 {
   nsDOMMutationObserver* mutationObserver =
     nsDOMMutationObserver::FromSupports(aNative);
   nsContentUtils::PreserveWrapper(aNative, mutationObserver);
 }
 
+// IDBFactory helper
+
+/* static */
+template<nsresult (*func)(JSContext *, unsigned, jsval *, bool), bool aDelete>
+JSBool
+IDBFNativeShim(JSContext *cx, unsigned argc, jsval *vp)
+{
+  nsresult rv = (*func)(cx, argc, vp, aDelete);
+  if (NS_FAILED(rv)) {
+    xpc::Throw(cx, rv);
+    return false;
+  }
+
+  return true;
+}
+
+/* static */ nsresult
+IDBFOpenForPrincipal(JSContext *cx, unsigned argc, JS::Value *vp, bool aDelete)
+{
+  // Just to be on the extra-safe side
+  if (!nsContentUtils::IsCallerChrome()) {
+    MOZ_NOT_REACHED("Shouldn't be possible to get here");
+    return NS_ERROR_FAILURE;
+  }
+
+  JSObject* principalJS;
+  JSString* nameJS;
+  uint32_t version = 0;
+  if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "oS/u",
+                           &principalJS, &nameJS, &version)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (version < 1 && argc >= 3) {
+    return NS_ERROR_TYPE_ERR;
+  }
+
+  if (aDelete) {
+    version = 0;
+  }
+
+  nsDependentJSString name;
+  NS_ENSURE_TRUE(name.init(cx, nameJS), NS_ERROR_UNEXPECTED);
+
+  nsCOMPtr<nsIPrincipal> principal = do_QueryWrapper(cx, principalJS);
+  NS_ENSURE_TRUE(principal, NS_ERROR_NO_INTERFACE);
+
+  nsCString extendedOrigin;
+  nsresult rv = principal->GetExtendedOrigin(extendedOrigin);
+  NS_ENSURE_FALSE(extendedOrigin.IsEmpty(), NS_ERROR_UNEXPECTED);
+
+  nsCOMPtr<nsIIDBFactory> factory =
+    do_QueryWrapper(cx, JS_THIS_OBJECT(cx, vp));
+  NS_ENSURE_TRUE(factory, NS_ERROR_NO_INTERFACE);
+
+  nsRefPtr<indexedDB::IDBOpenDBRequest> request;
+  rv = static_cast<indexedDB::IDBFactory*>(factory.get())->
+    OpenCommon(name, version, extendedOrigin, aDelete, cx,
+               getter_AddRefs(request));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return WrapNative(cx, JS_GetGlobalForScopeChain(cx),
+                    static_cast<nsIIDBOpenDBRequest*>(request),
+                    &NS_GET_IID(nsIIDBOpenDBRequest), true, vp);
+}
+
+NS_IMETHODIMP
+IDBFactorySH::PostCreatePrototype(JSContext * cx, JSObject * proto)
+{
+  // set up our proto first
+  nsresult rv = nsDOMGenericSH::PostCreatePrototype(cx, proto);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (xpc::AccessCheck::isChrome(js::GetObjectCompartment(proto)) &&
+      (!JS_DefineFunction(cx, proto, "openForPrincipal",
+                          IDBFNativeShim<IDBFOpenForPrincipal, false>,
+                          3, JSPROP_ENUMERATE) ||
+       !JS_DefineFunction(cx, proto, "deleteForPrincipal",
+                          IDBFNativeShim<IDBFOpenForPrincipal, true>,
+                          2, JSPROP_ENUMERATE))) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  return rv;
+}
+
 // IDBEventTarget helper
 
 NS_IMETHODIMP
 IDBEventTargetSH::PreCreate(nsISupports *aNativeObj, JSContext *aCx,
                             JSObject *aGlobalObj, JSObject **aParentObj)
 {
   IDBWrapperCache *target = IDBWrapperCache::FromSupports(aNativeObj);
   JSObject *parent = target->GetParentObject();
@@ -9144,17 +9277,17 @@ nsHTMLDocumentSH::DocumentAllTagsNewReso
 {
   if (JSID_IS_STRING(id)) {
     nsDocument *doc = GetDocument(obj);
 
     JSObject *proto;
     if (!::JS_GetPrototype(cx, obj, &proto)) {
       return JS_FALSE;
     }
-    if (NS_UNLIKELY(!proto)) {
+    if (MOZ_UNLIKELY(!proto)) {
       return JS_TRUE;
     }
 
     JSBool found;
     if (!::JS_HasPropertyById(cx, proto, id, &found)) {
       return JS_FALSE;
     }
 
@@ -9848,17 +9981,17 @@ nsHTMLPluginObjElementSH::GetProperty(ns
                                       jsval *vp, bool *_retval)
 {
   JSAutoRequest ar(cx);
 
   JSObject *pi_obj;
   if (!::JS_GetPrototype(cx, obj, &pi_obj)) {
     return NS_ERROR_UNEXPECTED;
   }
-  if (NS_UNLIKELY(!pi_obj)) {
+  if (MOZ_UNLIKELY(!pi_obj)) {
     return NS_OK;
   }
 
   JSBool found = false;
 
   if (!ObjectIsNativeWrapper(cx, obj)) {
     *_retval = ::JS_HasPropertyById(cx, pi_obj, id, &found);
     if (!*_retval) {
@@ -9880,17 +10013,17 @@ nsHTMLPluginObjElementSH::SetProperty(ns
                                       jsval *vp, bool *_retval)
 {
   JSAutoRequest ar(cx);
 
   JSObject *pi_obj;
   if (!::JS_GetPrototype(cx, obj, &pi_obj)) {
     return NS_ERROR_UNEXPECTED;
   }
-  if (NS_UNLIKELY(!pi_obj)) {
+  if (MOZ_UNLIKELY(!pi_obj)) {
     return NS_OK;
   }
 
   JSBool found = false;
 
   if (!ObjectIsNativeWrapper(cx, obj)) {
     *_retval = ::JS_HasPropertyById(cx, pi_obj, id, &found);
     if (!*_retval) {
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -268,24 +268,27 @@ public:
   static jsid sOnload_id;
   static jsid sOnerror_id;
 
 protected:
   static JSPropertyOp sXPCNativeWrapperGetPropertyOp;
   static JSPropertyOp sXrayWrapperPropertyHolderGetPropertyOp;
 };
 
-
+// THIS ONE ISN'T SAFE!! It assumes that the private of the JSObject is
+// an nsISupports.
 inline
 const nsQueryInterface
 do_QueryWrappedNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj)
 {
   return nsQueryInterface(nsDOMClassInfo::GetNative(wrapper, obj));
 }
 
+// THIS ONE ISN'T SAFE!! It assumes that the private of the JSObject is
+// an nsISupports.
 inline
 const nsQueryInterfaceWithError
 do_QueryWrappedNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj,
                       nsresult *aError)
 
 {
   return nsQueryInterfaceWithError(nsDOMClassInfo::GetNative(wrapper, obj),
                                    aError);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -37,16 +37,17 @@
 #include "jsfriendapi.h"        // for JS_GetGlobalForFrame
 #include "jswrapper.h"
 #include "nsReadableUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsJSEnvironment.h"
 #include "nsCharSeparatedTokenizer.h" // for Accept-Language parsing
 #include "nsUnicharUtils.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/Likely.h"
 
 // Other Classes
 #include "nsEventListenerManager.h"
 #include "nsEscape.h"
 #include "nsStyleCoord.h"
 #include "nsMimeTypeArray.h"
 #include "nsNetUtil.h"
 #include "nsICachingChannel.h"
@@ -1281,17 +1282,17 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_
   return tmp->IsBlackForCC();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow)
   return tmp->IsBlackForCC();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
-  if (NS_UNLIKELY(cb.WantDebugInfo())) {
+  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     char name[512];
     PR_snprintf(name, sizeof(name), "nsGlobalWindow #%ld", tmp->mWindowID);
     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
   } else {
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow, tmp->mRefCnt.get())
   }
 
   if (!cb.WantAllTraces() && tmp->IsBlackForCC()) {
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -15,16 +15,17 @@
 #include "nsContentUtils.h"
 #include "nsJSEnvironment.h"
 #include "nsServiceManagerUtils.h"
 #include "nsError.h"
 #include "nsGlobalWindow.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsAlgorithm.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Likely.h"
 
 static const char kSetIntervalStr[] = "setInterval";
 static const char kSetTimeoutStr[] = "setTimeout";
 
 // Our JS nsIScriptTimeoutHandler implementation.
 class nsJSScriptTimeoutHandler MOZ_FINAL : public nsIScriptTimeoutHandler
 {
 public:
@@ -71,17 +72,17 @@ private:
 
 // nsJSScriptTimeoutHandler
 // QueryInterface implementation for nsJSScriptTimeoutHandler
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSScriptTimeoutHandler)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSScriptTimeoutHandler)
   tmp->ReleaseJSObjects();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler)
-  if (NS_UNLIKELY(cb.WantDebugInfo())) {
+  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     nsAutoCString name("nsJSScriptTimeoutHandler");
     if (tmp->mExpr) {
       name.AppendLiteral(" [");
       name.Append(tmp->mFileName);
       name.AppendLiteral(":");
       name.AppendInt(tmp->mLineNo);
       name.AppendLiteral("]");
     }
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -32,16 +32,17 @@
 #include "nsCRT.h"
 #include "nsIProtocolHandler.h"
 #include "nsReadableUtils.h"
 #include "nsITextToSubURI.h"
 #include "nsJSUtils.h"
 #include "jsfriendapi.h"
 #include "nsContentUtils.h"
 #include "nsEventStateManager.h"
+#include "mozilla/Likely.h"
 
 static nsresult
 GetDocumentCharacterSetForURI(const nsAString& aHref, nsACString& aCharset)
 {
   aCharset.Truncate();
 
   nsresult rv;
 
@@ -934,16 +935,16 @@ nsLocation::GetSourceBaseURL(JSContext* 
   return NS_OK;
 }
 
 bool
 nsLocation::CallerSubsumes()
 {
   // Get the principal associated with the location object.
   nsCOMPtr<nsIDOMWindow> outer = do_QueryReferent(mOuter);
-  if (NS_UNLIKELY(!outer))
+  if (MOZ_UNLIKELY(!outer))
     return false;
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(outer);
   bool subsumes = false;
   nsresult rv = nsContentUtils::GetSubjectPrincipal()->Subsumes(sop->GetPrincipal(), &subsumes);
   NS_ENSURE_SUCCESS(rv, false);
   return subsumes;
 }
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -141,39 +141,56 @@ InterfaceObjectToString(JSContext* cx, u
   str.Append('\n');
   str.AppendLiteral("    [native code]");
   str.Append('\n');
   str.AppendLiteral("}");
 
   return xpc::NonVoidStringToJsval(cx, str, vp);
 }
 
+JSBool
+Constructor(JSContext* cx, unsigned argc, JS::Value* vp)
+{
+  JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
+  const JS::Value& v =
+    js::GetFunctionNativeReserved(callee,
+                                  CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
+  JSNativeHolder* nativeHolder = static_cast<JSNativeHolder*>(v.toPrivate());
+  return (nativeHolder->mNative)(cx, argc, vp);
+}
+
 static JSObject*
-CreateInterfaceObject(JSContext* cx, JSObject* global, JSObject* receiver,
-                      JSClass* constructorClass, JSNative constructorNative,
-                      unsigned ctorNargs, JSObject* proto,
+CreateInterfaceObject(JSContext* cx, JSObject* global,
+                      JSClass* constructorClass,
+                      JSNativeHolder* constructorNative,
+                      unsigned ctorNargs,
+                      JSObject* proto,
                       const NativeProperties* properties,
                       const NativeProperties* chromeOnlyProperties,
                       const char* name)
 {
   JSObject* constructor;
   if (constructorClass) {
     JSObject* functionProto = JS_GetFunctionPrototype(cx, global);
     if (!functionProto) {
       return NULL;
     }
     constructor = JS_NewObject(cx, constructorClass, functionProto, global);
   } else {
     MOZ_ASSERT(constructorNative);
-    JSFunction* fun = JS_NewFunction(cx, constructorNative, ctorNargs,
-                                     JSFUN_CONSTRUCTOR, global, name);
+    JSFunction* fun = js::NewFunctionWithReserved(cx, Constructor, ctorNargs,
+                                                  JSFUN_CONSTRUCTOR, global,
+                                                  name);
     if (!fun) {
       return NULL;
     }
     constructor = JS_GetFunctionObject(fun);
+    js::SetFunctionNativeReserved(constructor,
+                                  CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT,
+                                  js::PrivateValue(constructorNative));
   }
   if (!constructor) {
     return NULL;
   }
 
   if (constructorClass) {
     JSFunction* toString = js::DefineFunctionWithReserved(cx, constructor,
                                                           "toString",
@@ -196,46 +213,57 @@ CreateInterfaceObject(JSContext* cx, JSO
   }
 
   if (properties) {
     if (properties->staticMethods &&
         !DefinePrefable(cx, constructor, properties->staticMethods)) {
       return nullptr;
     }
 
+    if (properties->staticAttributes &&
+        !DefinePrefable(cx, constructor, properties->staticAttributes)) {
+      return nullptr;
+    }
+
     if (properties->constants &&
         !DefinePrefable(cx, constructor, properties->constants)) {
       return nullptr;
     }
   }
 
   if (chromeOnlyProperties) {
     if (chromeOnlyProperties->staticMethods &&
         !DefinePrefable(cx, constructor, chromeOnlyProperties->staticMethods)) {
       return nullptr;
     }
 
+    if (chromeOnlyProperties->staticAttributes &&
+        !DefinePrefable(cx, constructor,
+                        chromeOnlyProperties->staticAttributes)) {
+      return nullptr;
+    }
+
     if (chromeOnlyProperties->constants &&
         !DefinePrefable(cx, constructor, chromeOnlyProperties->constants)) {
       return nullptr;
     }
   }
 
   if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) {
     return NULL;
   }
 
   JSBool alreadyDefined;
-  if (!JS_AlreadyHasOwnProperty(cx, receiver, name, &alreadyDefined)) {
+  if (!JS_AlreadyHasOwnProperty(cx, global, name, &alreadyDefined)) {
     return NULL;
   }
 
   // This is Enumerable: False per spec.
   if (!alreadyDefined &&
-      !JS_DefineProperty(cx, receiver, name, OBJECT_TO_JSVAL(constructor), NULL,
+      !JS_DefineProperty(cx, global, name, OBJECT_TO_JSVAL(constructor), NULL,
                          NULL, 0)) {
     return NULL;
   }
 
   return constructor;
 }
 
 static JSObject*
@@ -282,67 +310,83 @@ CreateInterfacePrototypeObject(JSContext
         !DefinePrefable(cx, ourProto, chromeOnlyProperties->constants)) {
       return nullptr;
     }
   }
 
   return ourProto;
 }
 
-JSObject*
-CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver,
-                       JSObject* protoProto, JSClass* protoClass,
-                       JSClass* constructorClass, JSNative constructor,
-                       unsigned ctorNargs, const DOMClass* domClass,
+void
+CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* protoProto,
+                       JSClass* protoClass, JSObject** protoCache,
+                       JSClass* constructorClass, JSNativeHolder* constructor,
+                       unsigned ctorNargs, JSObject** constructorCache,
+                       const DOMClass* domClass,
                        const NativeProperties* properties,
                        const NativeProperties* chromeOnlyProperties,
                        const char* name)
 {
   MOZ_ASSERT(protoClass || constructorClass || constructor,
              "Need at least one class or a constructor!");
   MOZ_ASSERT(!((properties &&
                 (properties->methods || properties->attributes)) ||
                (chromeOnlyProperties &&
                 (chromeOnlyProperties->methods ||
                  chromeOnlyProperties->attributes))) || protoClass,
              "Methods or properties but no protoClass!");
-  MOZ_ASSERT(!((properties && properties->staticMethods) ||
-               (chromeOnlyProperties && chromeOnlyProperties->staticMethods)) ||
+  MOZ_ASSERT(!((properties &&
+                (properties->staticMethods || properties->staticAttributes)) ||
+               (chromeOnlyProperties &&
+                (chromeOnlyProperties->staticMethods ||
+                 chromeOnlyProperties->staticAttributes))) ||
              constructorClass || constructor,
              "Static methods but no constructorClass or constructor!");
   MOZ_ASSERT(bool(name) == bool(constructorClass || constructor),
              "Must have name precisely when we have an interface object");
   MOZ_ASSERT(!constructorClass || !constructor);
+  MOZ_ASSERT(!protoClass == !protoCache,
+             "If, and only if, there is an interface prototype object we need "
+             "to cache it");
+  MOZ_ASSERT(!(constructorClass || constructor) == !constructorCache,
+             "If, and only if, there is an interface object we need to cache "
+             "it");
 
   JSObject* proto;
   if (protoClass) {
     proto = CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
                                            properties, chromeOnlyProperties);
     if (!proto) {
-      return NULL;
+      return;
     }
 
     js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT,
                         JS::PrivateValue(const_cast<DOMClass*>(domClass)));
+
+    *protoCache = proto;
   }
   else {
     proto = NULL;
   }
 
   JSObject* interface;
   if (constructorClass || constructor) {
-    interface = CreateInterfaceObject(cx, global, receiver, constructorClass,
-                                      constructor, ctorNargs, proto,
-                                      properties, chromeOnlyProperties, name);
+    interface = CreateInterfaceObject(cx, global, constructorClass, constructor,
+                                      ctorNargs, proto, properties,
+                                      chromeOnlyProperties, name);
     if (!interface) {
-      return NULL;
+      if (protoCache) {
+        // If we fail we need to make sure to clear the value of protoCache we
+        // set above.
+        *protoCache = nullptr;
+      }
+      return;
     }
+    *constructorCache = interface;
   }
-
-  return protoClass ? proto : interface;
 }
 
 static bool
 NativeInterface2JSObjectAndThrowIfFailed(XPCLazyCallContext& aLccx,
                                          JSContext* aCx,
                                          JS::Value* aRetval,
                                          xpcObjectHelper& aHelper,
                                          const nsIID* aIID,
@@ -467,31 +511,131 @@ QueryInterface(JSContext* cx, unsigned a
 }
 
 JSBool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
 {
   return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
 }
 
+inline const NativePropertyHooks*
+GetNativePropertyHooks(JSContext *cx, JSObject *obj, DOMObjectType& type)
+{
+  const DOMClass* domClass;
+  if (GetDOMClass(obj, domClass) != eNonDOMObject) {
+    type = eInstance;
+    return domClass->mNativeHooks;
+  }
+
+  if (JS_ObjectIsFunction(cx, obj)) {
+    MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
+    type = eInterface;
+    const JS::Value& v =
+      js::GetFunctionNativeReserved(obj,
+                                    CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
+    JSNativeHolder* nativeHolder = static_cast<JSNativeHolder*>(v.toPrivate());
+    return nativeHolder->mPropertyHooks;
+  }
+
+  MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));
+  const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
+    DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
+  type = ifaceAndProtoJSClass->mType;
+  return ifaceAndProtoJSClass->mNativeHooks;
+}
+
+bool
+XrayResolveOwnProperty(JSContext* cx, JSObject* wrapper, JSObject* obj, jsid id,
+                       bool set, JSPropertyDescriptor* desc)
+{
+  DOMObjectType type;
+  const NativePropertyHooks *nativePropertyHooks =
+    GetNativePropertyHooks(cx, obj, type);
+
+  return type != eInstance || !nativePropertyHooks->mResolveOwnProperty ||
+         nativePropertyHooks->mResolveOwnProperty(cx, wrapper, obj, id, set,
+                                                  desc);
+}
+
+static bool
+XrayResolveAttribute(JSContext* cx, JSObject* wrapper, jsid id,
+                     Prefable<JSPropertySpec>* attributes, jsid* attributeIds,
+                     JSPropertySpec* attributeSpecs, JSPropertyDescriptor* desc)
+{
+  for (; attributes->specs; ++attributes) {
+    if (attributes->enabled) {
+      // Set i to be the index into our full list of ids/specs that we're
+      // looking at now.
+      size_t i = attributes->specs - attributeSpecs;
+      for ( ; attributeIds[i] != JSID_VOID; ++i) {
+        if (id == attributeIds[i]) {
+          JSPropertySpec& attrSpec = attributeSpecs[i];
+          // Because of centralization, we need to make sure we fault in the
+          // JitInfos as well. At present, until the JSAPI changes, the easiest
+          // way to do this is wrap them up as functions ourselves.
+          desc->attrs = attrSpec.flags & ~JSPROP_NATIVE_ACCESSORS;
+          // They all have getters, so we can just make it.
+          JSObject *global = JS_GetGlobalForObject(cx, wrapper);
+          JSFunction *fun = JS_NewFunction(cx, (JSNative)attrSpec.getter.op,
+                                           0, 0, global, nullptr);
+          if (!fun)
+            return false;
+          SET_JITINFO(fun, attrSpec.getter.info);
+          JSObject *funobj = JS_GetFunctionObject(fun);
+          desc->getter = js::CastAsJSPropertyOp(funobj);
+          desc->attrs |= JSPROP_GETTER;
+          if (attrSpec.setter.op) {
+            // We have a setter! Make it.
+            fun = JS_NewFunction(cx, (JSNative)attrSpec.setter.op, 1, 0,
+                                 global, nullptr);
+            if (!fun)
+              return false;
+            SET_JITINFO(fun, attrSpec.setter.info);
+            funobj = JS_GetFunctionObject(fun);
+            desc->setter = js::CastAsJSStrictPropertyOp(funobj);
+            desc->attrs |= JSPROP_SETTER;
+          } else {
+            desc->setter = nullptr;
+          }
+          desc->obj = wrapper;
+          return true;
+        }
+      }
+    }
+  }
+  return true;
+}
+
 static bool
 XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
-                    JSPropertyDescriptor* desc,
+                    JSPropertyDescriptor* desc, DOMObjectType type,
                     const NativeProperties* nativeProperties)
 {
-  if (nativeProperties->methods) {
+  Prefable<JSFunctionSpec>* methods;
+  jsid* methodIds;
+  JSFunctionSpec* methodsSpecs;
+  if (type == eInterface) {
+    methods = nativeProperties->staticMethods;
+    methodIds = nativeProperties->staticMethodIds;
+    methodsSpecs = nativeProperties->staticMethodsSpecs;
+  } else {
+    methods = nativeProperties->methods;
+    methodIds = nativeProperties->methodIds;
+    methodsSpecs = nativeProperties->methodsSpecs;
+  }
+  if (methods) {
     Prefable<JSFunctionSpec>* method;
-    for (method = nativeProperties->methods; method->specs; ++method) {
+    for (method = methods; method->specs; ++method) {
       if (method->enabled) {
         // Set i to be the index into our full list of ids/specs that we're
         // looking at now.
-        size_t i = method->specs - nativeProperties->methodsSpecs;
-        for ( ; nativeProperties->methodIds[i] != JSID_VOID; ++i) {
-          if (id == nativeProperties->methodIds[i]) {
-            JSFunctionSpec& methodSpec = nativeProperties->methodsSpecs[i];
+        size_t i = method->specs - methodsSpecs;
+        for ( ; methodIds[i] != JSID_VOID; ++i) {
+          if (id == methodIds[i]) {
+            JSFunctionSpec& methodSpec = methodsSpecs[i];
             JSFunction *fun = JS_NewFunctionById(cx, methodSpec.call.op,
                                                  methodSpec.nargs, 0,
                                                  wrapper, id);
             if (!fun) {
               return false;
             }
             SET_JITINFO(fun, methodSpec.call.info);
             JSObject *funobj = JS_GetFunctionObject(fun);
@@ -502,68 +646,52 @@ XrayResolveProperty(JSContext* cx, JSObj
             desc->getter = nullptr;
            return true;
           }
         }
       }
     }
   }
 
-  JSPropertySpec* attributeSpecs = nativeProperties->attributeSpecs;
-  Prefable<JSPropertySpec>* attr = nativeProperties->attributes;
-  jsid* attributeIds = nativeProperties->attributeIds;
-  // Do the attribute stuff for attributes, then for unforgeable attributes
-  for (int attrIteration = 0; attrIteration < 2; ++attrIteration) {
-    if (attr) {
-      for (; attr->specs; ++attr) {
-        if (attr->enabled) {
-          // Set i to be the index into our full list of ids/specs that we're
-          // looking at now.
-          size_t i = attr->specs - attributeSpecs;
-          for ( ; attributeIds[i] != JSID_VOID; ++i) {
-            if (id == attributeIds[i]) {
-              JSPropertySpec& attrSpec = attributeSpecs[i];
-              // Because of centralization, we need to make sure we fault in the
-              // JitInfos as well. At present, until the JSAPI changes, the easiest
-              // way to do this is wrap them up as functions ourselves.
-              desc->attrs = attrSpec.flags & ~JSPROP_NATIVE_ACCESSORS;
-              // They all have getters, so we can just make it.
-              JSObject *global = JS_GetGlobalForObject(cx, wrapper);
-              JSFunction *fun = JS_NewFunction(cx, (JSNative)attrSpec.getter.op,
-                                               0, 0, global, nullptr);
-              if (!fun)
-                return false;
-              SET_JITINFO(fun, attrSpec.getter.info);
-              JSObject *funobj = JS_GetFunctionObject(fun);
-              desc->getter = js::CastAsJSPropertyOp(funobj);
-              desc->attrs |= JSPROP_GETTER;
-              if (attrSpec.setter.op) {
-                // We have a setter! Make it.
-                fun = JS_NewFunction(cx, (JSNative)attrSpec.setter.op, 1, 0,
-                                     global, nullptr);
-                if (!fun)
-                  return false;
-                SET_JITINFO(fun, attrSpec.setter.info);
-                funobj = JS_GetFunctionObject(fun);
-                desc->setter = js::CastAsJSStrictPropertyOp(funobj);
-                desc->attrs |= JSPROP_SETTER;
-              } else {
-                desc->setter = nullptr;
-              }
-              desc->obj = wrapper;
-              return true;
-            }
-          }
-        }
+  if (type == eInterface) {
+    if (nativeProperties->staticAttributes) {
+      if (!XrayResolveAttribute(cx, wrapper, id,
+                                nativeProperties->staticAttributes,
+                                nativeProperties->staticAttributeIds,
+                                nativeProperties->staticAttributeSpecs, desc)) {
+        return false;
+      }
+      if (desc->obj) {
+        return true;
       }
     }
-
-    attributeSpecs = nativeProperties->unforgeableAttributeSpecs;
-    attr = nativeProperties->unforgeableAttributes;
-    attributeIds = nativeProperties->unforgeableAttributeIds;
+  } else {
+    if (nativeProperties->attributes) {
+      if (!XrayResolveAttribute(cx, wrapper, id,
+                                nativeProperties->attributes,
+                                nativeProperties->attributeIds,
+                                nativeProperties->attributeSpecs, desc)) {
+        return false;
+      }
+      if (desc->obj) {
+        return true;
+      }
+    }
+    if (nativeProperties->unforgeableAttributes) {
+      if (!XrayResolveAttribute(cx, wrapper, id,
+                                nativeProperties->unforgeableAttributes,
+                                nativeProperties->unforgeableAttributeIds,
+                                nativeProperties->unforgeableAttributeSpecs,
+                                desc)) {
+        return false;
+      }
+      if (desc->obj) {
+        return true;
+      }
+    }
   }
 
   if (nativeProperties->constants) {
     Prefable<ConstantSpec>* constant;
     for (constant = nativeProperties->constants; constant->specs; ++constant) {
       if (constant->enabled) {
         // Set i to be the index into our full list of ids/specs that we're
         // looking at now.
@@ -578,82 +706,189 @@ XrayResolveProperty(JSContext* cx, JSObj
         }
       }
     }
   }
 
   return true;
 }
 
+static bool
+ResolvePrototypeOrConstructor(JSContext* cx, JSObject* wrapper, JSObject* obj,
+                              size_t protoAndIfaceArrayIndex, unsigned attrs,
+                              JSPropertyDescriptor* desc)
+{
+  JSObject* global = js::GetGlobalForObjectCrossCompartment(obj);
+  {
+    JSAutoCompartment ac(cx, global);
+    JSObject** protoAndIfaceArray = GetProtoAndIfaceArray(global);
+    JSObject* protoOrIface = protoAndIfaceArray[protoAndIfaceArrayIndex];
+    if (!protoOrIface) {
+      return false;
+    }
+    desc->obj = wrapper;
+    desc->shortid = 0;
+    desc->attrs = attrs;
+    desc->getter = JS_PropertyStub;
+    desc->setter = JS_StrictPropertyStub;
+    desc->value = JS::ObjectValue(*protoOrIface);
+  }
+  return JS_WrapPropertyDescriptor(cx, desc);
+}
+
 bool
-XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
-                    JSPropertyDescriptor* desc,
-                    const NativeProperties* nativeProperties,
-                    const NativeProperties* chromeOnlyNativeProperties)
+XrayResolveNativeProperty(JSContext* cx, JSObject* wrapper,
+                          const NativePropertyHooks* nativePropertyHooks,
+                          DOMObjectType type, JSObject* obj, jsid id,
+                          JSPropertyDescriptor* desc)
 {
-  if (nativeProperties &&
-      !XrayResolveProperty(cx, wrapper, id, desc, nativeProperties)) {
+  if (type == eInterface && IdEquals(id, "prototype")) {
+    return nativePropertyHooks->mPrototypeID == prototypes::id::_ID_Count ||
+           ResolvePrototypeOrConstructor(cx, wrapper, obj,
+                                         nativePropertyHooks->mPrototypeID,
+                                         JSPROP_PERMANENT | JSPROP_READONLY,
+                                         desc);
+  }
+
+  if (type == eInterfacePrototype && IdEquals(id, "constructor")) {
+    return nativePropertyHooks->mConstructorID == constructors::id::_ID_Count ||
+           ResolvePrototypeOrConstructor(cx, wrapper, obj,
+                                         nativePropertyHooks->mConstructorID,
+                                         0, desc);
+  }
+
+  const NativePropertiesHolder& nativeProperties =
+    nativePropertyHooks->mNativeProperties;
+
+  if (nativeProperties.regular &&
+      !XrayResolveProperty(cx, wrapper, id, desc, type,
+                           nativeProperties.regular)) {
     return false;
   }
 
   if (!desc->obj &&
-      chromeOnlyNativeProperties &&
+      nativeProperties.chromeOnly &&
       xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
-      !XrayResolveProperty(cx, wrapper, id, desc, chromeOnlyNativeProperties)) {
+      !XrayResolveProperty(cx, wrapper, id, desc, type,
+                           nativeProperties.chromeOnly)) {
     return false;
   }
 
   return true;
 }
 
 bool
-XrayEnumerateProperties(JS::AutoIdVector& props,
+XrayResolveNativeProperty(JSContext* cx, JSObject* wrapper, JSObject* obj,
+                          jsid id, JSPropertyDescriptor* desc)
+{
+  DOMObjectType type;
+  const NativePropertyHooks* nativePropertyHooks =
+    GetNativePropertyHooks(cx, obj, type);
+
+  if (type == eInstance) {
+    // Force the type to be eInterfacePrototype, since we need to walk the
+    // prototype chain.
+    type = eInterfacePrototype;
+  }
+
+  if (type == eInterfacePrototype) {
+    do {
+      if (!XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type,
+                                     obj, id, desc)) {
+        return false;
+      }
+
+      if (desc->obj) {
+        return true;
+      }
+    } while ((nativePropertyHooks = nativePropertyHooks->mProtoHooks));
+
+    return true;
+  }
+
+  return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type, obj,
+                                   id, desc);
+}
+
+bool
+XrayEnumerateAttributes(Prefable<JSPropertySpec>* attributes,
+                        jsid* attributeIds, JSPropertySpec* attributeSpecs,
+                        JS::AutoIdVector& props)
+{
+  for (; attributes->specs; ++attributes) {
+    if (attributes->enabled) {
+      // Set i to be the index into our full list of ids/specs that we're
+      // looking at now.
+      size_t i = attributes->specs - attributeSpecs;
+      for ( ; attributeIds[i] != JSID_VOID; ++i) {
+        if ((attributeSpecs[i].flags & JSPROP_ENUMERATE) &&
+            !props.append(attributeIds[i])) {
+          return false;
+        }
+      }
+    }
+  }
+  return true;
+}
+
+bool
+XrayEnumerateProperties(JS::AutoIdVector& props, DOMObjectType type,
                         const NativeProperties* nativeProperties)
 {
-  if (nativeProperties->methods) {
+  Prefable<JSFunctionSpec>* methods;
+  jsid* methodIds;
+  JSFunctionSpec* methodsSpecs;
+  if (type == eInterface) {
+    methods = nativeProperties->staticMethods;
+    methodIds = nativeProperties->staticMethodIds;
+    methodsSpecs = nativeProperties->staticMethodsSpecs;
+  } else {
+    methods = nativeProperties->methods;
+    methodIds = nativeProperties->methodIds;
+    methodsSpecs = nativeProperties->methodsSpecs;
+  }
+  if (methods) {
     Prefable<JSFunctionSpec>* method;
-    for (method = nativeProperties->methods; method->specs; ++method) {
+    for (method = methods; method->specs; ++method) {
       if (method->enabled) {
         // Set i to be the index into our full list of ids/specs that we're
         // looking at now.
-        size_t i = method->specs - nativeProperties->methodsSpecs;
-        for ( ; nativeProperties->methodIds[i] != JSID_VOID; ++i) {
-          if ((nativeProperties->methodsSpecs[i].flags & JSPROP_ENUMERATE) &&
-              !props.append(nativeProperties->methodIds[i])) {
+        size_t i = method->specs - methodsSpecs;
+        for ( ; methodIds[i] != JSID_VOID; ++i) {
+          if ((methodsSpecs[i].flags & JSPROP_ENUMERATE) &&
+              !props.append(methodIds[i])) {
             return false;
           }
         }
       }
     }
   }
 
-  JSPropertySpec* attributeSpecs = nativeProperties->attributeSpecs;
-  Prefable<JSPropertySpec>* attr = nativeProperties->attributes;
-  jsid* attributeIds = nativeProperties->attributeIds;
-  // Do the attribute stuff for attributes, then for unforgeable attributes
-  for (int attrIteration = 0; attrIteration < 2; ++attrIteration) {
-    if (attr) {
-      for (; attr->specs; ++attr) {
-        if (attr->enabled) {
-          // Set i to be the index into our full list of ids/specs that we're
-          // looking at now.
-          size_t i = attr->specs - attributeSpecs;
-          for ( ; attributeIds[i] != JSID_VOID; ++i) {
-            if ((attributeSpecs[i].flags & JSPROP_ENUMERATE) &&
-                !props.append(attributeIds[i])) {
-              return false;
-            }
-          }
-        }
-      }
+  if (type == eInterface) {
+    if (nativeProperties->staticAttributes &&
+        !XrayEnumerateAttributes(nativeProperties->staticAttributes,
+                                 nativeProperties->staticAttributeIds,
+                                 nativeProperties->staticAttributeSpecs,
+                                 props)) {
+      return false;
     }
-
-    attributeSpecs = nativeProperties->unforgeableAttributeSpecs;
-    attr = nativeProperties->unforgeableAttributes;
-    attributeIds = nativeProperties->unforgeableAttributeIds;
+  } else {
+    if (nativeProperties->attributes &&
+        !XrayEnumerateAttributes(nativeProperties->attributes,
+                                 nativeProperties->attributeIds,
+                                 nativeProperties->attributeSpecs, props)) {
+      return false;
+    }
+    if (nativeProperties->unforgeableAttributes &&
+        !XrayEnumerateAttributes(nativeProperties->unforgeableAttributes,
+                                 nativeProperties->unforgeableAttributeIds,
+                                 nativeProperties->unforgeableAttributeSpecs,
+                                 props)) {
+      return false;
+    }
   }
 
   if (nativeProperties->constants) {
     Prefable<ConstantSpec>* constant;
     for (constant = nativeProperties->constants; constant->specs; ++constant) {
       if (constant->enabled) {
         // Set i to be the index into our full list of ids/specs that we're
         // looking at now.
@@ -666,36 +901,102 @@ XrayEnumerateProperties(JS::AutoIdVector
       }
     }
   }
 
   return true;
 }
 
 bool
-XrayEnumerateProperties(JSObject* wrapper,
-                        JS::AutoIdVector& props,
-                        const NativeProperties* nativeProperties,
-                        const NativeProperties* chromeOnlyNativeProperties)
+XrayEnumerateNativeProperties(JSContext* cx, JSObject* wrapper,
+                              const NativePropertyHooks* nativePropertyHooks,
+                              DOMObjectType type, JSObject* obj,
+                              JS::AutoIdVector& props)
 {
-  if (nativeProperties &&
-      !XrayEnumerateProperties(props, nativeProperties)) {
+  if (type == eInterface &&
+      nativePropertyHooks->mPrototypeID != prototypes::id::_ID_Count &&
+      !AddStringToIDVector(cx, props, "prototype")) {
     return false;
   }
 
-  if (chromeOnlyNativeProperties &&
+  if (type == eInterfacePrototype &&
+      nativePropertyHooks->mConstructorID != constructors::id::_ID_Count &&
+      !AddStringToIDVector(cx, props, "constructor")) {
+    return false;
+  }
+
+  const NativePropertiesHolder& nativeProperties =
+    nativePropertyHooks->mNativeProperties;
+
+  if (nativeProperties.regular &&
+      !XrayEnumerateProperties(props, type, nativeProperties.regular)) {
+    return false;
+  }
+
+  if (nativeProperties.chromeOnly &&
       xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
-      !XrayEnumerateProperties(props, chromeOnlyNativeProperties)) {
+      !XrayEnumerateProperties(props, type, nativeProperties.chromeOnly)) {
     return false;
   }
 
   return true;
 }
 
 bool
+XrayEnumerateProperties(JSContext* cx, JSObject* wrapper, JSObject* obj,
+                        bool ownOnly, JS::AutoIdVector& props)
+{
+  DOMObjectType type;
+  const NativePropertyHooks* nativePropertyHooks =
+    GetNativePropertyHooks(cx, obj, type);
+
+  if (type == eInstance) {
+    if (nativePropertyHooks->mEnumerateOwnProperties &&
+        !nativePropertyHooks->mEnumerateOwnProperties(cx, wrapper, obj,
+                                                      props)) {
+      return false;
+    }
+
+    if (ownOnly) {
+      return true;
+    }
+
+    // Force the type to be eInterfacePrototype, since we need to walk the
+    // prototype chain.
+    type = eInterfacePrototype;
+  }
+
+  if (type == eInterfacePrototype) {
+    do {
+      if (!XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type,
+                                         obj, props)) {
+        return false;
+      }
+    } while ((nativePropertyHooks = nativePropertyHooks->mProtoHooks));
+
+    return true;
+  }
+
+  return XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type,
+                                       obj, props);
+}
+
+NativePropertyHooks sWorkerNativePropertyHooks = {
+  nullptr,
+  nullptr,
+  {
+    nullptr,
+    nullptr
+  },
+  prototypes::id::_ID_Count,
+  constructors::id::_ID_Count,
+  nullptr
+};
+
+bool
 GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
                        JS::Value* vp)
 {
   JSObject* proto;
   if (!js::GetObjectProto(cx, proxy, &proto)) {
     return false;
   }
   if (!proto) {
@@ -743,31 +1044,43 @@ WrapCallbackInterface(JSContext *cx, JSO
   MOZ_ASSERT(NS_SUCCEEDED(rv) && obj, "What are we wrapping?");
   *vp = JS::ObjectValue(*obj);
   return JS_WrapValue(cx, vp);
 }
 
 JSObject*
 GetXrayExpandoChain(JSObject* obj)
 {
-  MOZ_ASSERT(IsDOMObject(obj));
-  JS::Value v = IsDOMProxy(obj) ? js::GetProxyExtra(obj, JSPROXYSLOT_XRAY_EXPANDO)
-                                : js::GetReservedSlot(obj, DOM_XRAY_EXPANDO_SLOT);
+  js::Class* clasp = js::GetObjectClass(obj);
+  JS::Value v;
+  if (IsDOMClass(clasp) || IsDOMIfaceAndProtoClass(clasp)) {
+    v = js::GetReservedSlot(obj, DOM_XRAY_EXPANDO_SLOT);
+  } else if (js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) {
+    MOZ_ASSERT(js::GetProxyHandler(obj)->family() == ProxyFamily());
+    v = js::GetProxyExtra(obj, JSPROXYSLOT_XRAY_EXPANDO);
+  } else {
+    MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
+    v = js::GetFunctionNativeReserved(obj, CONSTRUCTOR_XRAY_EXPANDO_SLOT);
+  }
   return v.isUndefined() ? nullptr : &v.toObject();
 }
 
 void
 SetXrayExpandoChain(JSObject* obj, JSObject* chain)
 {
-  MOZ_ASSERT(IsDOMObject(obj));
   JS::Value v = chain ? JS::ObjectValue(*chain) : JSVAL_VOID;
-  if (IsDOMProxy(obj)) {
+  js::Class* clasp = js::GetObjectClass(obj);
+  if (IsDOMClass(clasp) || IsDOMIfaceAndProtoClass(clasp)) {
+    js::SetReservedSlot(obj, DOM_XRAY_EXPANDO_SLOT, v);
+  } else if (js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) {
+    MOZ_ASSERT(js::GetProxyHandler(obj)->family() == ProxyFamily());
     js::SetProxyExtra(obj, JSPROXYSLOT_XRAY_EXPANDO, v);
   } else {
-    js::SetReservedSlot(obj, DOM_XRAY_EXPANDO_SLOT, v);
+    MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
+    js::SetFunctionNativeReserved(obj, CONSTRUCTOR_XRAY_EXPANDO_SLOT, v);
   }
 }
 
 JSContext*
 MainThreadDictionaryBase::ParseJSON(const nsAString& aJSON,
                                     mozilla::Maybe<JSAutoRequest>& aAr,
                                     mozilla::Maybe<JSAutoCompartment>& aAc,
                                     JS::Value& aVal)
@@ -783,10 +1096,87 @@ MainThreadDictionaryBase::ParseJSON(cons
   if (!JS_ParseJSON(cx,
                     static_cast<const jschar*>(PromiseFlatString(aJSON).get()),
                     aJSON.Length(), &aVal)) {
     return nullptr;
   }
   return cx;
 }
 
+static JSString*
+ConcatJSString(JSContext* cx, const char* pre, JSString* str, const char* post)
+{
+  if (!str) {
+    return nullptr;
+  }
+
+  JSString* preString = JS_NewStringCopyN(cx, pre, strlen(pre));
+  JSString* postString = JS_NewStringCopyN(cx, post, strlen(post));
+  if (!preString || !postString) {
+    return nullptr;
+  }
+
+  str = JS_ConcatStrings(cx, preString, str);
+  if (!str) {
+    return nullptr;
+  }
+
+  return JS_ConcatStrings(cx, str, postString);
+}
+
+bool
+NativeToString(JSContext* cx, JSObject* wrapper, JSObject* obj, const char* pre,
+               const char* post, JS::Value* v)
+{
+  JSPropertyDescriptor toStringDesc;
+  toStringDesc.obj = nullptr;
+  toStringDesc.attrs = 0;
+  toStringDesc.shortid = 0;
+  toStringDesc.getter = nullptr;
+  toStringDesc.setter = nullptr;
+  toStringDesc.value = JS::UndefinedValue();
+  if (!XrayResolveNativeProperty(cx, wrapper, obj,
+                                 nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING),
+                                 &toStringDesc)) {
+    return false;
+  }
+
+  JSString* str;
+  {
+    JSAutoCompartment ac(cx, obj);
+    if (toStringDesc.obj) {
+      JS::Value toString = toStringDesc.value;
+      if (!JS_WrapValue(cx, &toString)) {
+        return false;
+      }
+      MOZ_ASSERT(JS_ObjectIsCallable(cx, &toString.toObject()));
+      JS::Value toStringResult;
+      if (JS_CallFunctionValue(cx, obj, toString, 0, nullptr,
+                               &toStringResult)) {
+        str = toStringResult.toString();
+      } else {
+        str = nullptr;
+      }
+    } else {
+      if (IsDOMProxy(obj)) {
+        str = js::GetProxyHandler(obj)->obj_toString(cx, obj);
+      } else if (IsDOMClass(JS_GetClass(obj)) ||
+                 IsDOMIfaceAndProtoClass(JS_GetClass(obj))) {
+        str = ConcatJSString(cx, "[object ",
+                             JS_NewStringCopyZ(cx, JS_GetClass(obj)->name),
+                                               "]");
+      } else if (JS_IsNativeFunction(obj, Constructor)) {
+        str = JS_DecompileFunction(cx, JS_GetObjectFunction(obj), 0);
+      }
+      str = ConcatJSString(cx, pre, str, post);
+    }
+  }
+
+  if (!str) {
+    return false;
+  }
+
+  v->setString(str);
+  return JS_WrapValue(cx, v);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -63,28 +63,43 @@ template<bool mainThread>
 inline bool
 ThrowMethodFailedWithDetails(JSContext* cx, const ErrorResult& rv,
                              const char* /* ifaceName */,
                              const char* /* memberName */)
 {
   return Throw<mainThread>(cx, rv.ErrorCode());
 }
 
+// Returns true if the JSClass is used for DOM objects.
 inline bool
 IsDOMClass(const JSClass* clasp)
 {
   return clasp->flags & JSCLASS_IS_DOMJSCLASS;
 }
 
 inline bool
 IsDOMClass(const js::Class* clasp)
 {
   return IsDOMClass(Jsvalify(clasp));
 }
 
+// Returns true if the JSClass is used for DOM interface and interface 
+// prototype objects.
+inline bool
+IsDOMIfaceAndProtoClass(const JSClass* clasp)
+{
+  return clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS;
+}
+
+inline bool
+IsDOMIfaceAndProtoClass(const js::Class* clasp)
+{
+  return IsDOMIfaceAndProtoClass(Jsvalify(clasp));
+}
+
 // It's ok for eRegularDOMObject and eProxyDOMObject to be the same, but
 // eNonDOMObject should always be different from the other two. This enum
 // shouldn't be used to differentiate between non-proxy and proxy bindings.
 enum DOMObjectSlot {
   eNonDOMObject = -1,
   eRegularDOMObject = DOM_OBJECT_SLOT,
   eProxyDOMObject = DOM_PROXY_OBJECT_SLOT
 };
@@ -163,19 +178,17 @@ UnwrapDOMObjectToISupports(JSObject* obj
   result = UnwrapDOMObject<nsISupports>(obj, slot);
   return true;
 }
 
 inline bool
 IsDOMObject(JSObject* obj)
 {
   js::Class* clasp = js::GetObjectClass(obj);
-  return IsDOMClass(clasp) ||
-         ((js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) &&
-          js::GetProxyHandler(obj)->family() == ProxyFamily());
+  return IsDOMClass(clasp) || IsDOMProxy(obj, clasp);
 }
 
 // Some callers don't want to set an exception when unwrapping fails
 // (for example, overload resolution uses unwrapping to tell what sort
 // of thing it's looking at).
 // U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>).
 template <prototypes::ID PrototypeID, class T, typename U>
 inline nsresult
@@ -270,18 +283,23 @@ IsPlatformObject(JSContext* cx, JSObject
 template <class T, typename U>
 inline nsresult
 UnwrapObject(JSContext* cx, JSObject* obj, U& value)
 {
   return UnwrapObject<static_cast<prototypes::ID>(
            PrototypeIDMap<T>::PrototypeID), T>(cx, obj, value);
 }
 
-const size_t kProtoAndIfaceCacheCount =
-  prototypes::id::_ID_Count + constructors::id::_ID_Count;
+// The items in the protoAndIfaceArray are indexed by the prototypes::id::ID and
+// constructors::id::ID enums, in that order. The end of the prototype objects
+// should be the start of the interface objects.
+MOZ_STATIC_ASSERT((size_t)constructors::id::_ID_Start ==
+                  (size_t)prototypes::id::_ID_Count,
+                  "Overlapping or discontiguous indexes.");
+const size_t kProtoAndIfaceCacheCount = constructors::id::_ID_Count;
 
 inline void
 AllocateProtoAndIfaceCache(JSObject* obj)
 {
   MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
   MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
 
   // Important: The () at the end ensure zero-initialization
@@ -318,61 +336,68 @@ DestroyProtoAndIfaceCache(JSObject* obj)
 }
 
 /**
  * Add constants to an object.
  */
 bool
 DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs);
 
+struct JSNativeHolder
+{
+  JSNative mNative;
+  const NativePropertyHooks* mPropertyHooks;
+};
+
 /*
  * Create a DOM interface object (if constructorClass is non-null) and/or a
  * DOM interface prototype object (if protoClass is non-null).
  *
  * global is used as the parent of the interface object and the interface
  *        prototype object
- * receiver is the object on which we need to define the interface object as a
- *          property
  * protoProto is the prototype to use for the interface prototype object.
  * protoClass is the JSClass to use for the interface prototype object.
  *            This is null if we should not create an interface prototype
  *            object.
+ * protoCache a pointer to a JSObject pointer where we should cache the
+ *            interface prototype object. This must be null if protoClass is and
+ *            vice versa.
  * constructorClass is the JSClass to use for the interface object.
  *                  This is null if we should not create an interface object or
  *                  if it should be a function object.
- * constructor is the JSNative to use as a constructor.  If this is non-null, it
- *             should be used as a JSNative to back the interface object, which
- *             should be a Function.  If this is null, then we should create an
- *             object of constructorClass, unless that's also null, in which
- *             case we should not create an interface object at all.
+ * constructor holds the JSNative to back the interface object which should be a
+ *             Function, unless constructorClass is non-null in which case it is
+ *             ignored. If this is null and constructorClass is also null then
+ *             we should not create an interface object at all.
  * ctorNargs is the length of the constructor function; 0 if no constructor
+ * constructorCache a pointer to a JSObject pointer where we should cache the
+ *                  interface object. This must be null if both constructorClass
+ *                  and constructor are null, and non-null otherwise.
  * domClass is the DOMClass of instance objects for this class.  This can be
  *          null if this is not a concrete proto.
  * properties contains the methods, attributes and constants to be defined on
  *            objects in any compartment.
  * chromeProperties contains the methods, attributes and constants to be defined
  *                  on objects in chrome compartments. This must be null if the
  *                  interface doesn't have any ChromeOnly properties or if the
  *                  object is being created in non-chrome compartment.
  *
- * At least one of protoClass and constructorClass should be non-null.
- * If constructorClass is non-null, the resulting interface object will be
- * defined on the given global with property name |name|, which must also be
- * non-null.
- *
- * returns the interface prototype object if protoClass is non-null, else it
- * returns the interface object.
+ * At least one of protoClass, constructorClass or constructor should be
+ * non-null. If constructorClass or constructor are non-null, the resulting
+ * interface object will be defined on the given global with property name
+ * |name|, which must also be non-null.
  */
-JSObject*
-CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver,
-                       JSObject* protoProto, JSClass* protoClass,
-                       JSClass* constructorClass, JSNative constructor,
-                       unsigned ctorNargs, const DOMClass* domClass,
-                       const NativeProperties* properties,
-                       const NativeProperties* chromeProperties,
+void
+CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* protoProto,
+                       JSClass* protoClass, JSObject** protoCache,
+                       JSClass* constructorClass, JSNativeHolder* constructor,
+                       unsigned ctorNargs, JSObject** constructorCache,
+                       const DOMClass* domClass,
+                       const NativeProperties* regularProperties,
+                       const NativeProperties* chromeOnlyProperties,
                        const char* name);
 
 /*
  * Define the unforgeable attributes on an object.
  */
 bool
 DefineUnforgeableAttributes(JSContext* cx, JSObject* obj,
                             Prefable<JSPropertySpec>* props);
@@ -1239,29 +1264,105 @@ public:
     const T& Value() const {
       return *storage.addr();
     }
     void Destroy() {
       storage.addr()->~T();
     }
 };
 
+inline bool
+IdEquals(jsid id, const char* string)
+{
+  return JSID_IS_STRING(id) &&
+         JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
+}
+
+inline bool
+AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
+{
+  return vector.growBy(1) &&
+         InternJSString(cx, vector[vector.length() - 1], name);
+}
+
 // Implementation of the bits that XrayWrapper needs
+
+/**
+ * This resolves indexed or named properties of obj.
+ *
+ * wrapper is the Xray JS object.
+ * obj is the target object of the Xray, a binding's instance object or a
+ *     interface or interface prototype object.
+ */
 bool
-XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
-                    JSPropertyDescriptor* desc,
-                    const NativeProperties* nativeProperties,
-                    const NativeProperties* chromeOnlyNativeProperties);
+XrayResolveOwnProperty(JSContext* cx, JSObject* wrapper, JSObject* obj,
+                       jsid id, bool set, JSPropertyDescriptor* desc);
+
+/**
+ * This resolves operations, attributes and constants of the interfaces for obj.
+ *
+ * wrapper is the Xray JS object.
+ * obj is the target object of the Xray, a binding's instance object or a
+ *     interface or interface prototype object.
+ */
+bool
+XrayResolveNativeProperty(JSContext* cx, JSObject* wrapper, JSObject* obj,
+                          jsid id, JSPropertyDescriptor* desc);
 
+/**
+ * This enumerates indexed or named properties of obj and operations, attributes
+ * and constants of the interfaces for obj.
+ *
+ * wrapper is the Xray JS object.
+ * obj is the target object of the Xray, a binding's instance object or a
+ *     interface or interface prototype object.
+ */
 bool
-XrayEnumerateProperties(JSObject* wrapper,
-                        JS::AutoIdVector& props,
-                        const NativeProperties* nativeProperties,
-                        const NativeProperties* chromeOnlyNativeProperties);
+XrayEnumerateProperties(JSContext* cx, JSObject* wrapper, JSObject* obj,
+                        bool ownOnly, JS::AutoIdVector& props);
+
+extern NativePropertyHooks sWorkerNativePropertyHooks;
+
+// We use one constructor JSNative to represent all DOM interface objects (so
+// we can easily detect when we need to wrap them in an Xray wrapper). We store
+// the real JSNative in the mNative member of a JSNativeHolder in the
+// CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
+// specific interface object. We also store the NativeProperties in the
+// JSNativeHolder. The CONSTRUCTOR_XRAY_EXPANDO_SLOT is used to store the
+// expando chain of the Xray for the interface object.
+// Note that some interface objects are not yet a JSFunction but a normal
+// JSObject with a DOMJSClass, those do not use these slots.
+
+enum {
+  CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0,
+  CONSTRUCTOR_XRAY_EXPANDO_SLOT
+};
 
+JSBool
+Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
+
+inline bool
+UseDOMXray(JSObject* obj)
+{
+  const js::Class* clasp = js::GetObjectClass(obj);
+  return IsDOMClass(clasp) ||
+         IsDOMProxy(obj, clasp) ||
+         JS_IsNativeFunction(obj, Constructor) ||
+         IsDOMIfaceAndProtoClass(clasp);
+}
+
+#ifdef DEBUG
+inline bool
+HasConstructor(JSObject* obj)
+{
+  return JS_IsNativeFunction(obj, Constructor) ||
+         js::GetObjectClass(obj)->construct;
+}
+ #endif
+ 
 // Transfer reference in ptr to smartPtr.
 template<class T>
 inline void
 Take(nsRefPtr<T>& smartPtr, T* ptr)
 {
   smartPtr = dont_AddRef(ptr);
 }
 
@@ -1287,12 +1388,30 @@ struct MainThreadDictionaryBase
 {
 protected:
   JSContext* ParseJSON(const nsAString& aJSON,
                        mozilla::Maybe<JSAutoRequest>& aAr,
                        mozilla::Maybe<JSAutoCompartment>& aAc,
                        JS::Value& aVal);
 };
 
+/**
+ * This creates a JSString containing the value that the toString function for
+ * obj should create according to the WebIDL specification, ignoring any
+ * modifications by script. The value is prefixed with pre and postfixed with
+ * post, unless this is called for an object that has a stringifier. It is
+ * specifically for use by Xray code.
+ *
+ * wrapper is the Xray JS object.
+ * obj is the target object of the Xray, a binding's instance object or a
+ *     interface or interface prototype object.
+ * pre is a string that should be prefixed to the value.
+ * post is a string that should be prefixed to the value.
+ * v contains the JSString for the value if the function returns true.
+ */
+bool
+NativeToString(JSContext* cx, JSObject* wrapper, JSObject* obj, const char* pre,
+               const char* post, JS::Value* v);
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -91,16 +91,20 @@ DOMInterfaces = {
     'implicitJSContext': [ 'createBuffer' ],
     'nativeOwnership': 'refcounted'
 },
 
 'AudioNode' : {
     'concrete': False,
 },
 
+'AudioParam' : {
+    'nativeOwnership': 'refcounted'
+},
+
 'AudioSourceNode': {
     'concrete': False,
 },
 
 'Blob': [
 {
     'headerFile': 'nsIDOMFile.h',
 },
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -57,56 +57,90 @@ class CGThing():
     def define(self):
         """Produce code for a cpp file."""
         assert(False) # Override me!
 
 class CGNativePropertyHooks(CGThing):
     """
     Generate a NativePropertyHooks for a given descriptor
     """
-    def __init__(self, descriptor):
+    def __init__(self, descriptor, properties):
         CGThing.__init__(self)
         self.descriptor = descriptor
+        self.properties = properties
     def declare(self):
         if self.descriptor.workers:
             return ""
-        return "extern const NativePropertyHooks NativeHooks;\n"
+        return "extern const NativePropertyHooks sNativePropertyHooks;\n"
     def define(self):
         if self.descriptor.workers:
             return ""
         if self.descriptor.concrete and self.descriptor.proxy:
             resolveOwnProperty = "ResolveOwnProperty"
             enumerateOwnProperties = "EnumerateOwnProperties"
         else:
-            enumerateOwnProperties = resolveOwnProperty = "NULL"
+            resolveOwnProperty = "nullptr"
+            enumerateOwnProperties = "nullptr"
+        if self.properties.hasNonChromeOnly():
+            regular = "&sNativeProperties"
+        else:
+            regular = "nullptr"
+        if self.properties.hasChromeOnly():
+            chrome = "&sChromeOnlyNativeProperties"
+        else:
+            chrome = "nullptr"
+        constructorID = "constructors::id::"
+        if self.descriptor.interface.hasInterfaceObject():
+            constructorID += self.descriptor.name
+        else:
+            constructorID += "_ID_Count"
+        prototypeID = "prototypes::id::"
+        if self.descriptor.interface.hasInterfacePrototypeObject():
+            prototypeID += self.descriptor.name
+        else:
+            prototypeID += "_ID_Count"
         parent = self.descriptor.interface.parent
-        parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::NativeHooks"
+        parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::sNativePropertyHooks"
                        if parent else 'NULL')
-        return """
-const NativePropertyHooks NativeHooks = { %s, ResolveProperty, %s, EnumerateProperties, %s };
-""" % (resolveOwnProperty, enumerateOwnProperties, parentHooks)
+
+        return CGWrapper(CGIndenter(CGList([CGGeneric(resolveOwnProperty),
+                                            CGGeneric(enumerateOwnProperties),
+                                            CGWrapper(CGList([CGGeneric(regular),
+                                                              CGGeneric(chrome)],
+                                                             ", "),
+                                                      pre="{ ", post=" }"),
+                                            CGGeneric(prototypeID),
+                                            CGGeneric(constructorID),
+                                            CGGeneric(parentHooks)],
+                                           ",\n")),
+                         pre="const NativePropertyHooks sNativePropertyHooks = {\n",
+                         post="\n};\n").define()
+
+def NativePropertyHooks(descriptor):
+    return "&sWorkerNativePropertyHooks" if descriptor.workers else "&sNativePropertyHooks"
 
 def DOMClass(descriptor):
         protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
         # Pad out the list to the right length with _ID_Count so we
         # guarantee that all the lists are the same length.  _ID_Count
         # is never the ID of any prototype, so it's safe to use as
         # padding.
         protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
         prototypeChainString = ', '.join(protoList)
-        nativeHooks = "NULL" if descriptor.workers else "&NativeHooks"
         if descriptor.workers or descriptor.nativeOwnership != 'refcounted':
             participant = "nullptr"
         else:
             participant = "NS_CYCLE_COLLECTION_PARTICIPANT(%s)" % descriptor.nativeType
         return """{
   { %s },
-  %s, %s, %s
+  %s,
+  %s,
+  %s
 }""" % (prototypeChainString, toStringBool(descriptor.nativeOwnership == 'nsisupports'),
-        nativeHooks,
+        NativePropertyHooks(descriptor),
         participant)
 
 class CGDOMJSClass(CGThing):
     """
     Generate a DOMJSClass for a given descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
@@ -139,74 +173,89 @@ DOMJSClass Class = {
 %s
 };
 """ % (self.descriptor.interface.identifier.name,
        ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers and self.descriptor.wrapperCache else 'JS_PropertyStub',
        FINALIZE_HOOK_NAME, traceHook,
        CGIndenter(CGGeneric(DOMClass(self.descriptor))).define())
 
 class CGPrototypeJSClass(CGThing):
-    def __init__(self, descriptor):
+    def __init__(self, descriptor, properties):
         CGThing.__init__(self)
         self.descriptor = descriptor
+        self.properties = properties
     def declare(self):
         # We're purely for internal consumption
         return ""
     def define(self):
-        return """static JSClass PrototypeClass = {
-  "%sPrototype",
-  JSCLASS_HAS_RESERVED_SLOTS(1),
-  JS_PropertyStub,       /* addProperty */
-  JS_PropertyStub,       /* delProperty */
-  JS_PropertyStub,       /* getProperty */
-  JS_StrictPropertyStub, /* setProperty */
-  JS_EnumerateStub,
-  JS_ResolveStub,
-  JS_ConvertStub,
-  NULL,                  /* finalize */
-  NULL,                  /* checkAccess */
-  NULL,                  /* call */
-  NULL,                  /* hasInstance */
-  NULL,                  /* construct */
-  NULL,                  /* trace */
-  JSCLASS_NO_INTERNAL_MEMBERS
+        return """static DOMIfaceAndProtoJSClass PrototypeClass = {
+  {
+    "%sPrototype",
+    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
+    JS_PropertyStub,       /* addProperty */
+    JS_PropertyStub,       /* delProperty */
+    JS_PropertyStub,       /* getProperty */
+    JS_StrictPropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    nullptr,               /* finalize */
+    nullptr,               /* checkAccess */
+    nullptr,               /* call */
+    nullptr,               /* hasInstance */
+    nullptr,               /* construct */
+    nullptr,               /* trace */
+    JSCLASS_NO_INTERNAL_MEMBERS
+  },
+  eInterfacePrototype,
+  %s
 };
-""" % (self.descriptor.interface.identifier.name)
+""" % (self.descriptor.interface.identifier.name,
+       NativePropertyHooks(self.descriptor))
 
 class CGInterfaceObjectJSClass(CGThing):
-    def __init__(self, descriptor):
+    def __init__(self, descriptor, properties):
         CGThing.__init__(self)
         self.descriptor = descriptor
+        self.properties = properties
     def declare(self):
         # We're purely for internal consumption
         return ""
     def define(self):
         if not self.descriptor.hasInstanceInterface:
             return ""
-        ctorname = "NULL" if not self.descriptor.interface.ctor() else CONSTRUCT_HOOK_NAME
+        if self.descriptor.interface.ctor():
+            ctorname = CONSTRUCT_HOOK_NAME
+        else:
+            ctorname = "ThrowingConstructor"
         hasinstance = HASINSTANCE_HOOK_NAME
         return """
-static JSClass InterfaceObjectClass = {
-  "Function", 0,
-  JS_PropertyStub,       /* addProperty */
-  JS_PropertyStub,       /* delProperty */
-  JS_PropertyStub,       /* getProperty */
-  JS_StrictPropertyStub, /* setProperty */
-  JS_EnumerateStub,
-  JS_ResolveStub,
-  JS_ConvertStub,
-  NULL,                  /* finalize */
-  NULL,                  /* checkAccess */
-  %s, /* call */
-  %s, /* hasInstance */
-  %s, /* construct */
-  NULL,                  /* trace */
-  JSCLASS_NO_INTERNAL_MEMBERS
+static DOMIfaceAndProtoJSClass InterfaceObjectClass = {
+  {
+    "Function",
+    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
+    JS_PropertyStub,       /* addProperty */
+    JS_PropertyStub,       /* delProperty */
+    JS_PropertyStub,       /* getProperty */
+    JS_StrictPropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    nullptr,               /* finalize */
+    nullptr,               /* checkAccess */
+    %s, /* call */
+    %s, /* hasInstance */
+    %s, /* construct */
+    nullptr,               /* trace */
+    JSCLASS_NO_INTERNAL_MEMBERS
+  },
+  eInterface,
+  %s
 };
-""" % (ctorname, hasinstance, ctorname)
+""" % (ctorname, hasinstance, ctorname, NativePropertyHooks(self.descriptor))
 
 class CGList(CGThing):
     """
     Generate code for a list of GCThings.  Just concatenates them together, with
     an optional joiner string.  "\n" is a common joiner.
     """
     def __init__(self, children, joiner=""):
         CGThing.__init__(self)
@@ -800,16 +849,28 @@ class CGClassConstructHook(CGAbstractSta
             preArgs = ["global"]
 
         name = self._ctor.identifier.name
         nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
         callGenerator = CGMethodCall(preArgs, nativeName, True,
                                      self.descriptor, self._ctor)
         return preamble + callGenerator.define();
 
+class CGClassConstructHookHolder(CGGeneric):
+    def __init__(self, descriptor):
+        if descriptor.interface.ctor():
+            constructHook = CONSTRUCT_HOOK_NAME
+        else:
+            constructHook = "ThrowingConstructor"
+        CGGeneric.__init__(self,
+                           "JSNativeHolder " + CONSTRUCT_HOOK_NAME + "_holder = {\n" +
+                           "  " + constructHook + ",\n" +
+                           "  " + NativePropertyHooks(descriptor) + "\n" +
+                           "};\n")
+
 class CGClassHasInstanceHook(CGAbstractStaticMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'),
                 Argument('JSMutableHandleValue', 'vp'), Argument('JSBool*', 'bp')]
         CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
                                         'JSBool', args)
 
     def define(self):
@@ -1007,26 +1068,28 @@ class MethodDefiner(PropertyDefiner):
         PropertyDefiner.__init__(self, descriptor, name)
 
         # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
         #       We should be able to check for special operations without an
         #       identifier. For now we check if the name starts with __
         methods = [m for m in descriptor.interface.members if
                    m.isMethod() and m.isStatic() == static and
                    not m.isIdentifierLess()]
-        self.chrome = [{"name": m.identifier.name,
-                        "length": methodLength(m),
-                        "flags": "JSPROP_ENUMERATE",
-                        "pref": PropertyDefiner.getControllingPref(m) }
-                       for m in methods if isChromeOnly(m)]
-        self.regular = [{"name": m.identifier.name,
-                         "length": methodLength(m),
-                         "flags": "JSPROP_ENUMERATE",
-                         "pref": PropertyDefiner.getControllingPref(m) }
-                        for m in methods if not isChromeOnly(m)]
+        self.chrome = []
+        self.regular = []
+        for m in methods:
+            method = { "name": m.identifier.name,
+                       "methodInfo": not m.isStatic(),
+                       "length": methodLength(m),
+                       "flags": "JSPROP_ENUMERATE",
+                       "pref": PropertyDefiner.getControllingPref(m) }
+            if isChromeOnly(m):
+                self.chrome.append(method)
+            else:
+                self.regular.append(method)
 
         # FIXME Check for an existing iterator on the interface first.
         if any(m.isGetter() and m.isIndexed() for m in methods):
             self.regular.append({"name": 'iterator',
                                  "methodInfo": False,
                                  "nativeName": "JS_ArrayIterator",
                                  "length": 0,
                                  "flags": "JSPROP_ENUMERATE",
@@ -1080,25 +1143,37 @@ class MethodDefiner(PropertyDefiner):
         return self.generatePrefableArray(
             array, name,
             '  JS_FNINFO("%s", %s, %s, %s, %s)',
             '  JS_FS_END',
             'JSFunctionSpec',
             pref, specData, doIdArrays)
 
 class AttrDefiner(PropertyDefiner):
-    def __init__(self, descriptor, name, unforgeable):
+    def __init__(self, descriptor, name, static, unforgeable=False):
+        assert not (static and unforgeable)
         PropertyDefiner.__init__(self, descriptor, name)
         self.name = name
-        attributes = [m for m in descriptor.interface.members
-                      if m.isAttr() and m.isUnforgeable() == unforgeable]
+        attributes = [m for m in descriptor.interface.members if
+                      m.isAttr() and m.isStatic() == static and
+                      m.isUnforgeable() == unforgeable]
         self.chrome = [m for m in attributes if isChromeOnly(m)]
         self.regular = [m for m in attributes if not isChromeOnly(m)]
+        self.static = static
         self.unforgeable = unforgeable
 
+        if static:
+            if not descriptor.interface.hasInterfaceObject():
+                # static attributes go on the interface object
+                assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
+        else:
+            if not descriptor.interface.hasInterfacePrototypeObject():
+                # non-static attributes go on the interface prototype object
+                assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
+
         if unforgeable and len(attributes) != 0 and descriptor.proxy:
             raise TypeError("Unforgeable properties are not supported on "
                             "proxy bindings without [NamedPropertiesObject].  "
                             "And not even supported on the ones with "
                             "[NamedPropertiesObject] yet, but we should fix "
                             "that, since they're safe there.")
 
     def generateArray(self, array, name, doIdArrays):
@@ -1106,30 +1181,36 @@ class AttrDefiner(PropertyDefiner):
             return ""
 
         def flags(attr):
             unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else ""
             return ("JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS" +
                     unforgeable)
 
         def getter(attr):
-            native = ("genericLenientGetter" if attr.hasLenientThis()
-                      else "genericGetter")
-            return ("{(JSPropertyOp)%(native)s, &%(name)s_getterinfo}"
-                    % {"name" : attr.identifier.name,
-                       "native" : native})
+            if self.static:
+                accessor = 'get_' + attr.identifier.name
+                jitinfo = "nullptr"
+            else:
+                accessor = ("genericLenientGetter" if attr.hasLenientThis()
+                            else "genericGetter")
+                jitinfo = "&%s_getterinfo" % attr.identifier.name
+            return "{ (JSPropertyOp)%s, %s }" % (accessor, jitinfo)
 
         def setter(attr):
-            if attr.readonly and attr.getExtendedAttribute("PutForwards") is None:
-                return "JSOP_NULLWRAPPER"
-            native = ("genericLenientSetter" if attr.hasLenientThis()
-                      else "genericSetter")
-            return ("{(JSStrictPropertyOp)%(native)s, &%(name)s_setterinfo}"
-                    % {"name" : attr.identifier.name,
-                       "native" : native})
+            if self.static:
+                accessor = 'set_' + attr.identifier.name
+                jitinfo = "nullptr"
+            else:
+                if attr.readonly and attr.getExtendedAttribute("PutForwards") is None:
+                    return "JSOP_NULLWRAPPER"
+                accessor = ("genericLenientSetter" if attr.hasLenientThis()
+                            else "genericSetter")
+                jitinfo = "&%s_setterinfo" % attr.identifier.name
+            return "{ (JSStrictPropertyOp)%s, %s }" % (accessor, jitinfo)
 
         def specData(attr):
             return (attr.identifier.name, flags(attr), getter(attr),
                     setter(attr))
 
         return self.generatePrefableArray(
             array, name,
             '  { "%s", 0, %s, %s, %s}',
@@ -1160,27 +1241,30 @@ class ConstDefiner(PropertyDefiner):
             array, name,
             '  { "%s", %s }',
             '  { 0, JSVAL_VOID }',
             'ConstantSpec',
             PropertyDefiner.getControllingPref, specData, doIdArrays)
 
 class PropertyArrays():
     def __init__(self, descriptor):
-        self.staticMethods = MethodDefiner(descriptor, "StaticMethods", True)
-        self.methods = MethodDefiner(descriptor, "Methods", False)
-        self.attrs = AttrDefiner(descriptor, "Attributes", unforgeable=False)
+        self.staticMethods = MethodDefiner(descriptor, "StaticMethods",
+                                           static=True)
+        self.staticAttrs = AttrDefiner(descriptor, "StaticAttributes",
+                                       static=True)
+        self.methods = MethodDefiner(descriptor, "Methods", static=False)
+        self.attrs = AttrDefiner(descriptor, "Attributes", static=False)
         self.unforgeableAttrs = AttrDefiner(descriptor, "UnforgeableAttributes",
-                                            unforgeable=True)
+                                            static=False, unforgeable=True)
         self.consts = ConstDefiner(descriptor, "Constants")
 
     @staticmethod
     def arrayNames():
-        return [ "staticMethods", "methods", "attrs", "unforgeableAttrs",
-                 "consts" ]
+        return [ "staticMethods", "staticAttrs", "methods", "attrs",
+                 "unforgeableAttrs", "consts" ]
 
     @staticmethod
     def xrayRelevantArrayNames():
         return [ "methods", "attrs", "unforgeableAttrs", "consts" ]
 
     def hasChromeOnly(self):
         return any(getattr(self, a).hasChromeOnly() for a in self.arrayNames())
     def hasNonChromeOnly(self):
@@ -1228,26 +1312,26 @@ class CGNativeProperties(CGList):
 class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
     """
     Generate the CreateInterfaceObjects method for an interface descriptor.
 
     properties should be a PropertyArrays instance.
     """
     def __init__(self, descriptor, properties):
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
-                Argument('JSObject*', 'aReceiver')]
-        CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'JSObject*', args)
+                Argument('JSObject**', 'protoAndIfaceArray')]
+        CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
         self.properties = properties
     def definition_body(self):
         protoChain = self.descriptor.prototypeChain
         if len(protoChain) == 1:
             getParentProto = "JS_GetObjectPrototype(aCx, aGlobal)"
         else:
             parentProtoName = self.descriptor.prototypeChain[-2]
-            getParentProto = ("%s::GetProtoObject(aCx, aGlobal, aReceiver)" %
+            getParentProto = ("%s::GetProtoObject(aCx, aGlobal)" %
                               toBindingNamespace(parentProtoName))
 
         needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
         needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject()
 
         # if we don't need to create anything, why are we generating this?
         assert needInterfaceObject or needInterfacePrototypeObject
 
@@ -1270,17 +1354,17 @@ class CGCreateInterfaceObjectsMethod(CGA
                 initIds = CGWrapper(initIds, pre="(", post=")", reindent=True)
             initIds = CGList(
                 [CGGeneric("%s_ids[0] == JSID_VOID &&" % idsToInit[0]), initIds],
                 "\n")
             initIds = CGWrapper(initIds, pre="if (", post=") {", reindent=True)
             initIds = CGList(
                 [initIds,
                  CGGeneric(("  %s_ids[0] = JSID_VOID;\n"
-                            "  return NULL;") % idsToInit[0]),
+                            "  return;") % idsToInit[0]),
                  CGGeneric("}")],
                 "\n")
         else:
             initIds = None
 
         prefCacheData = []
         for var in self.properties.arrayNames():
             props = getattr(self.properties, var)
@@ -1294,30 +1378,43 @@ class CGCreateInterfaceObjectsMethod(CGA
                                        "if (!sPrefCachesInited) {\n"
                                        "  sPrefCachesInited = true;\n"),
                                   post="\n}")
         else:
             prefCache = None
             
         getParentProto = ("JSObject* parentProto = %s;\n" +
                           "if (!parentProto) {\n" +
-                          "  return NULL;\n" +
+                          "  return;\n" +
                           "}\n") % getParentProto
 
-        needInterfaceObjectClass = (needInterfaceObject and
-                                    self.descriptor.hasInstanceInterface)
         needConstructor = (needInterfaceObject and
                            not self.descriptor.hasInstanceInterface)
+        constructHook = "&" + CONSTRUCT_HOOK_NAME + "_holder"
         if self.descriptor.interface.ctor():
-            constructHook = CONSTRUCT_HOOK_NAME
             constructArgs = methodLength(self.descriptor.interface.ctor())
         else:
-            constructHook = "ThrowingConstructor"
             constructArgs = 0
 
+        if needInterfacePrototypeObject:
+            protoClass = "&PrototypeClass.mBase"
+            protoCache = "&protoAndIfaceArray[prototypes::id::%s]" % self.descriptor.name
+        else:
+            protoClass = "nullptr"
+            protoCache = "nullptr"
+        if needInterfaceObject:
+            if self.descriptor.hasInstanceInterface:
+                interfaceClass = "&InterfaceObjectClass.mBase"
+            else:
+                interfaceClass = "nullptr"
+            interfaceCache = "&protoAndIfaceArray[constructors::id::%s]" % self.descriptor.name
+        else:
+            interfaceClass = "nullptr"
+            interfaceCache = "nullptr"
+
         if self.descriptor.concrete:
             if self.descriptor.proxy:
                 domClass = "&Class"
             else:
                 domClass = "&Class.mClass"
         else:
             domClass = "nullptr"
 
@@ -1325,64 +1422,58 @@ class CGCreateInterfaceObjectsMethod(CGA
             properties = "&sNativeProperties"
         else:
             properties = "nullptr"
         if self.properties.hasChromeOnly():
             accessCheck = GetAccessCheck(self.descriptor, "aGlobal")
             chromeProperties = accessCheck + " ? &sChromeOnlyNativeProperties : nullptr"
         else:
             chromeProperties = "nullptr"
-        call = """return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,
-                                   %s, %s, %s, %d,
-                                   %s,
-                                   %s,
-                                   %s,
-                                   %s);""" % (
-            "&PrototypeClass" if needInterfacePrototypeObject else "NULL",
-            "&InterfaceObjectClass" if needInterfaceObjectClass else "NULL",
-            constructHook if needConstructor else "NULL",
-            constructArgs,
+        call = ("dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,\n"
+                "                            %s, %s,\n"
+                "                            %s, %s, %d, %s,\n"
+                "                            %s,\n"
+                "                            %s,\n"
+                "                            %s,\n"
+                "                            %s);" % (
+            protoClass, protoCache,
+            interfaceClass, constructHook if needConstructor else "nullptr",
+            constructArgs, interfaceCache,
             domClass,
             properties,
             chromeProperties,
-            '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL")
+            '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL"))
         functionBody = CGList(
             [CGGeneric(getParentProto), initIds, prefCache, CGGeneric(call)],
             "\n\n")
         return CGIndenter(functionBody).define()
 
 class CGGetPerInterfaceObject(CGAbstractMethod):
     """
     A method for getting a per-interface object (a prototype object or interface
     constructor object).
     """
     def __init__(self, descriptor, name, idPrefix=""):
-        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
-                Argument('JSObject*', 'aReceiver')]
+        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
         CGAbstractMethod.__init__(self, descriptor, name,
                                   'JSObject*', args, inline=True)
         self.id = idPrefix + "id::" + self.descriptor.name
     def definition_body(self):
         return """
 
-  /* aGlobal and aReceiver are usually the same, but they can be different
-     too. For example a sandbox often has an xray wrapper for a window as the
-     prototype of the sandbox's global. In that case aReceiver is the xray
-     wrapper and aGlobal is the sandbox's global.
-   */
-
   /* Make sure our global is sane.  Hopefully we can remove this sometime */
   if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) {
     return NULL;
   }
   /* Check to see whether the interface objects are already installed */
   JSObject** protoAndIfaceArray = GetProtoAndIfaceArray(aGlobal);
   JSObject* cachedObject = protoAndIfaceArray[%s];
   if (!cachedObject) {
-    protoAndIfaceArray[%s] = cachedObject = CreateInterfaceObjects(aCx, aGlobal, aReceiver);
+    CreateInterfaceObjects(aCx, aGlobal, protoAndIfaceArray);
+    cachedObject = protoAndIfaceArray[%s];
   }
 
   /* cachedObject might _still_ be null, but that's OK */
   return cachedObject;""" % (self.id, self.id)
 
 class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
     """
     A method for getting the interface prototype object.
@@ -1436,43 +1527,35 @@ def CheckPref(descriptor, globalName, va
 """ % (globalName, failureCode, wrapperCache, failureCode)
 
 class CGDefineDOMInterfaceMethod(CGAbstractMethod):
     """
     A method for resolve hooks to try to lazily define the interface object for
     a given interface.
     """
     def __init__(self, descriptor):
-        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aReceiver'),
+        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
                 Argument('bool*', 'aEnabled')]
-        CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args)
+        CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'JSObject*', args)
 
     def declare(self):
         if self.descriptor.workers:
             return ''
         return CGAbstractMethod.declare(self)
 
     def define(self):
         if self.descriptor.workers:
             return ''
         return CGAbstractMethod.define(self)
 
     def definition_body(self):
-        if self.descriptor.interface.hasInterfacePrototypeObject():
-            # We depend on GetProtoObject defining an interface constructor
-            # object as needed.
-            getter = "GetProtoObject"
-        else:
-            getter = "GetConstructorObject"
-
-        return ("  JSObject* global = JS_GetGlobalForObject(aCx, aReceiver);\n" +
-                CheckPref(self.descriptor, "global", "*aEnabled", "false") + 
+        return (CheckPref(self.descriptor, "aGlobal", "*aEnabled", "nullptr") + 
                 """
   *aEnabled = true;
-  return !!%s(aCx, global, aReceiver);""" % (getter))
+  return GetConstructorObject(aCx, aGlobal);""")
 
 class CGPrefEnabled(CGAbstractMethod):
     """
     A method for testing whether the preference controlling this
     interface is enabled.  When it's not, the interface should not be
     visible on the global.
     """
     def __init__(self, descriptor):
@@ -1589,17 +1672,17 @@ class CGWrapWithCacheMethod(CGAbstractMe
   JSObject* parent = WrapNativeParent(aCx, aScope, aObject->GetParentObject());
   if (!parent) {
     return NULL;
   }
 
   JSAutoCompartment ac(aCx, parent);
   JSObject* global = JS_GetGlobalForObject(aCx, parent);
 %s
-  JSObject* proto = GetProtoObject(aCx, global, global);
+  JSObject* proto = GetProtoObject(aCx, global);
   if (!proto) {
     return NULL;
   }
 
 %s
 %s
   aCache->SetWrapper(obj);
 
@@ -1631,17 +1714,17 @@ class CGWrapNonWrapperCacheMethod(CGAbst
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
                 Argument(descriptor.nativeType + '*', 'aObject')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
         self.properties = properties
 
     def definition_body(self):
         return """
   JSObject* global = JS_GetGlobalForObject(aCx, aScope);
-  JSObject* proto = GetProtoObject(aCx, global, global);
+  JSObject* proto = GetProtoObject(aCx, global);
   if (!proto) {
     return NULL;
   }
 
 %s
 %s
   return obj;""" % (CreateBindingJSObject(self.descriptor, "global"),
                     InitUnforgeableProperties(self.descriptor, self.properties))
@@ -3615,19 +3698,23 @@ class CGMethodCall(CGThing):
         return self.cgRoot.define()
 
 class CGGetterCall(CGPerSignatureCall):
     """
     A class to generate a native object getter call for a particular IDL
     getter.
     """
     def __init__(self, returnType, nativeMethodName, descriptor, attr):
-        CGPerSignatureCall.__init__(self, returnType, [], [],
-                                    nativeMethodName, False, descriptor,
-                                    attr, getter=True)
+        if attr.isStatic():
+            argsPre = [ "global" ]
+        else:
+            argsPre = []
+        CGPerSignatureCall.__init__(self, returnType, argsPre, [],
+                                    nativeMethodName, attr.isStatic(),
+                                    descriptor, attr, getter=True)
 
 class FakeArgument():
     """
     A class that quacks like an IDLArgument.  This is used to make
     setters look like method calls or for special operations.
     """
     def __init__(self, type, interfaceMember):
         self.type = type
@@ -3644,20 +3731,24 @@ class FakeArgument():
         self.identifier = FakeIdentifier()
 
 class CGSetterCall(CGPerSignatureCall):
     """
     A class to generate a native object setter call for a particular IDL
     setter.
     """
     def __init__(self, argType, nativeMethodName, descriptor, attr):
-        CGPerSignatureCall.__init__(self, None, [],
+        if attr.isStatic():
+            argsPre = [ "global" ]
+        else:
+            argsPre = []
+        CGPerSignatureCall.__init__(self, None, argsPre,
                                     [FakeArgument(argType, attr)],
-                                    nativeMethodName, False, descriptor, attr,
-                                    setter=True)
+                                    nativeMethodName, attr.isStatic(),
+                                    descriptor, attr, setter=True)
     def wrap_return_value(self):
         # We have no return value
         return "\nreturn true;"
     def getArgc(self):
         return "1"
     def getArgvDecl(self):
         # We just get our stuff from our last arg no matter what
         return ""
@@ -3686,31 +3777,70 @@ class CGAbstractBindingMethod(CGAbstract
         else:
             self.unwrapFailureCode = unwrapFailureCode
 
     def definition_body(self):
         # Our descriptor might claim that we're not castable, simply because
         # we're someone's consequential interface.  But for this-unwrapping, we
         # know that we're the real deal.  So fake a descriptor here for
         # consumption by FailureFatalCastableObjectUnwrapper.
-        unwrapThis = CGIndenter(CGGeneric(
+        getThis = CGGeneric("""js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+if (!obj) {
+  return false;
+}
+
+%s* self;""" % self.descriptor.nativeType)
+        unwrapThis = CGGeneric(
             str(CastableObjectUnwrapper(
                         FakeCastableDescriptor(self.descriptor),
-                        "obj", "self", self.unwrapFailureCode))))
-        return CGList([ self.getThis(), unwrapThis,
+                        "obj", "self", self.unwrapFailureCode)))
+        return CGList([ CGIndenter(getThis), CGIndenter(unwrapThis),
                         self.generate_code() ], "\n").define()
 
-    def getThis(self):
-        return CGIndenter(
-            CGGeneric("js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));\n"
-                      "if (!obj) {\n"
-                      "  return false;\n"
-                      "}\n"
-                      "\n"
-                      "%s* self;" % self.descriptor.nativeType))
+    def generate_code(self):
+        assert(False) # Override me
+
+class CGAbstractStaticBindingMethod(CGAbstractStaticMethod):
+    """
+    Common class to generate the JSNatives for all our static methods, getters
+    and setters.  This will generate the function declaration and unwrap the
+    global object.  Subclasses are expected to override the generate_code
+    function to do the rest of the work.  This function should return a
+    CGThing which is already properly indented.
+    """
+    def __init__(self, descriptor, name, args):
+        CGAbstractStaticMethod.__init__(self, descriptor, name, "JSBool", args)
+
+    def definition_body(self):
+        isMainThread = toStringBool(not self.descriptor.workers)
+        unwrap = CGGeneric("""js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+if (!obj) {
+  return false;
+}
+
+if (js::IsWrapper(obj)) {
+  obj = XPCWrapper::Unwrap(cx, obj, false);
+  if (!obj) {
+    return Throw<%s>(cx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
+  }
+}
+
+nsISupports* global;
+xpc_qsSelfRef globalRef;
+{
+  JS::Value val;
+  val.setObjectOrNull(JS_GetGlobalForObject(cx, obj));
+  nsresult rv = xpc_qsUnwrapArg<nsISupports>(cx, val, &global, &globalRef.ptr,
+                                             &val);
+  if (NS_FAILED(rv)) {
+    return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
+  }
+}""" % (isMainThread, isMainThread))
+        return CGList([ CGIndenter(unwrap),
+                        self.generate_code() ], "\n\n").define()
 
     def generate_code(self):
         assert(False) # Override me
 
 def MakeNativeName(name):
     return name[0].upper() + name[1:]
 
 class CGGenericMethod(CGAbstractBindingMethod):
@@ -3747,16 +3877,33 @@ class CGSpecializedMethod(CGAbstractStat
         return CGMethodCall([], nativeName, self.method.isStatic(),
                             self.descriptor, self.method).define()
 
     @staticmethod
     def makeNativeName(descriptor, method):
         name = method.identifier.name
         return MakeNativeName(descriptor.binaryNames.get(name, name))
 
+class CGStaticMethod(CGAbstractStaticBindingMethod):
+    """
+    A class for generating the C++ code for an IDL static method.
+    """
+    def __init__(self, descriptor, method):
+        self.method = method
+        name = method.identifier.name
+        args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
+                Argument('JS::Value*', 'vp')]
+        CGAbstractStaticBindingMethod.__init__(self, descriptor, name, args)
+
+    def generate_code(self):
+        nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
+                                                        self.method)
+        return CGMethodCall([ "global" ], nativeName, True, self.descriptor,
+                            self.method)
+
 class CGGenericGetter(CGAbstractBindingMethod):
     """
     A class for generating the C++ code for an IDL attribute getter.
     """
     def __init__(self, descriptor, lenientThis=False):
         args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
                 Argument('JS::Value*', 'vp')]
         if lenientThis:
@@ -3805,16 +3952,33 @@ class CGSpecializedGetter(CGAbstractStat
         (_, resultOutParam) = getRetvalDeclarationForType(attr.type, descriptor,
                                                           False)
         infallible = ('infallible' in
                       descriptor.getExtendedAttributes(attr, getter=True))
         if resultOutParam or attr.type.nullable() or not infallible:
             nativeName = "Get" + nativeName
         return nativeName
 
+class CGStaticGetter(CGAbstractStaticBindingMethod):
+    """
+    A class for generating the C++ code for an IDL static attribute getter.
+    """
+    def __init__(self, descriptor, attr):
+        self.attr = attr
+        name = 'get_' + attr.identifier.name
+        args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
+                Argument('JS::Value*', 'vp')]
+        CGAbstractStaticBindingMethod.__init__(self, descriptor, name, args)
+
+    def generate_code(self):
+        nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
+                                                        self.attr)
+        return CGIndenter(CGGetterCall(self.attr.type, nativeName,
+                                       self.descriptor, self.attr))
+
 class CGGenericSetter(CGAbstractBindingMethod):
     """
     A class for generating the C++ code for an IDL attribute setter.
     """
     def __init__(self, descriptor, lenientThis=False):
         args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
                 Argument('JS::Value*', 'vp')]
         if lenientThis:
@@ -3863,16 +4027,39 @@ class CGSpecializedSetter(CGAbstractStat
         return CGIndenter(CGSetterCall(self.attr.type, nativeName,
                                        self.descriptor, self.attr)).define()
 
     @staticmethod
     def makeNativeName(descriptor, attr):
         name = attr.identifier.name
         return "Set" + MakeNativeName(descriptor.binaryNames.get(name, name))
 
+class CGStaticSetter(CGAbstractStaticBindingMethod):
+    """
+    A class for generating the C++ code for an IDL static attribute setter.
+    """
+    def __init__(self, descriptor, attr):
+        self.attr = attr
+        name = 'set_' + attr.identifier.name
+        args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
+                Argument('JS::Value*', 'vp')]
+        CGAbstractStaticBindingMethod.__init__(self, descriptor, name, args)
+
+    def generate_code(self):
+        nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
+                                                        self.attr)
+        argv = CGGeneric("""JS::Value* argv = JS_ARGV(cx, vp);
+JS::Value undef = JS::UndefinedValue();
+if (argc == 0) {
+  argv = &undef;
+}""")
+        call = CGSetterCall(self.attr.type, nativeName, self.descriptor,
+                            self.attr)
+        return CGIndenter(CGList([ argv, call ], "\n"))
+
 class CGSpecializedForwardingSetter(CGSpecializedSetter):
     """
     A class for generating the code for a specialized attribute setter with
     PutForwards that the JIT can call with lower overhead.
     """
     def __init__(self, descriptor, attr):
         CGSpecializedSetter.__init__(self, descriptor, attr)
 
@@ -4671,90 +4858,38 @@ class CGClass(CGThing):
             (memberString, itemCount) = defineMembers(self, memberList,
                                                       itemCount, separator)
             result = result + memberString
         return result
 
 class CGResolveOwnProperty(CGAbstractMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
-                Argument('jsid', 'id'), Argument('bool', 'set'),
+                Argument('JSObject*', 'obj'), Argument('jsid', 'id'),
+                Argument('bool', 'set'),
                 Argument('JSPropertyDescriptor*', 'desc')]
         CGAbstractMethod.__init__(self, descriptor, "ResolveOwnProperty", "bool", args)
     def definition_body(self):
-        return """  JSObject* obj = wrapper;
-  if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
-    obj = js::UnwrapObject(obj);
-  }
-  // We rely on getOwnPropertyDescriptor not shadowing prototype properties by named
+        return """  // We rely on getOwnPropertyDescriptor not shadowing prototype properties by named
   // properties. If that changes we'll need to filter here.
   return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, set, desc);
 """
 
 class CGEnumerateOwnProperties(CGAbstractMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
+                Argument('JSObject*', 'obj'),
                 Argument('JS::AutoIdVector&', 'props')]
         CGAbstractMethod.__init__(self, descriptor, "EnumerateOwnProperties", "bool", args)
     def definition_body(self):
-        return """  JSObject* obj = wrapper;
-  if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
-    obj = js::UnwrapObject(obj);
-  }
-  // We rely on getOwnPropertyNames not shadowing prototype properties by named
+        return """  // We rely on getOwnPropertyNames not shadowing prototype properties by named
   // properties. If that changes we'll need to filter here.
   return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);
 """
 
-class CGXrayHelper(CGAbstractMethod):
-    def __init__(self, descriptor, name, args, properties):
-        CGAbstractMethod.__init__(self, descriptor, name, "bool", args)
-        self.properties = properties
-
-    def definition_body(self):
-        prefixArgs = CGGeneric(self.getPrefixArgs())
-        if self.properties.hasNonChromeOnly():
-            regular = "&sNativeProperties"
-        else:
-            regular = "nullptr"
-        regular = CGGeneric(regular)
-        if self.properties.hasChromeOnly():
-            chrome = "&sChromeOnlyNativeProperties"
-        else:
-            chrome = "nullptr"
-        chrome = CGGeneric(chrome)
-
-        return CGIndenter(
-            CGWrapper(CGList([prefixArgs, regular, chrome], ",\n"),
-                      pre=("return Xray%s(" % self.name),
-                      post=");",
-                      reindent=True)).define()
-
-class CGResolveProperty(CGXrayHelper):
-    def __init__(self, descriptor, properties):
-        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
-                Argument('jsid', 'id'), Argument('bool', 'set'),
-                Argument('JSPropertyDescriptor*', 'desc')]
-        CGXrayHelper.__init__(self, descriptor, "ResolveProperty", args,
-                              properties)
-
-    def getPrefixArgs(self):
-        return "cx, wrapper, id, desc"
-
-
-class CGEnumerateProperties(CGXrayHelper):
-    def __init__(self, descriptor, properties):
-        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
-                Argument('JS::AutoIdVector&', 'props')]
-        CGXrayHelper.__init__(self, descriptor, "EnumerateProperties", args,
-                              properties)
-
-    def getPrefixArgs(self):
-        return "wrapper, props"
-
 class CGPrototypeTraitsClass(CGClass):
     def __init__(self, descriptor, indent=''):
         templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
         templateSpecialization = ['prototypes::id::' + descriptor.name]
         enums = [ClassEnum('', ['Depth'],
                            [descriptor.interface.inheritanceDepth()])]
         typedefs = [ClassTypedef('NativeType', descriptor.nativeType)]
         CGClass.__init__(self, 'PrototypeTraits', indent=indent,
@@ -5320,40 +5455,52 @@ def stripTrailingWhitespace(text):
 class CGDescriptor(CGThing):
     def __init__(self, descriptor):
         CGThing.__init__(self)
 
         assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
 
         cgThings = []
         if descriptor.interface.hasInterfacePrototypeObject():
+            # These are set to true if at least one non-static
+            # method/getter/setter exist on the interface.
             (hasMethod, hasGetter, hasLenientGetter,
              hasSetter, hasLenientSetter) = False, False, False, False, False
             for m in descriptor.interface.members:
-                if (m.isMethod() and not m.isStatic() and
+                if (m.isMethod() and
                     (not m.isIdentifierLess() or m == descriptor.operations['Stringifier'])):
-                    cgThings.append(CGSpecializedMethod(descriptor, m))
-                    cgThings.append(CGMemberJITInfo(descriptor, m))
-                    hasMethod = True
+                    if m.isStatic():
+                        cgThings.append(CGStaticMethod(descriptor, m))
+                    else:
+                        cgThings.append(CGSpecializedMethod(descriptor, m))
+                        cgThings.append(CGMemberJITInfo(descriptor, m))
+                        hasMethod = True
                 elif m.isAttr():
-                    cgThings.append(CGSpecializedGetter(descriptor, m))
-                    if m.hasLenientThis():
-                        hasLenientGetter = True
+                    if m.isStatic():
+                        cgThings.append(CGStaticGetter(descriptor, m))
                     else:
-                        hasGetter = True
+                        cgThings.append(CGSpecializedGetter(descriptor, m))
+                        if m.hasLenientThis():
+                            hasLenientGetter = True
+                        else:
+                            hasGetter = True
                     if not m.readonly:
-                        cgThings.append(CGSpecializedSetter(descriptor, m))
-                        if m.hasLenientThis():
-                            hasLenientSetter = True
+                        if m.isStatic():
+                            cgThings.append(CGStaticSetter(descriptor, m))
                         else:
-                            hasSetter = True
+                            cgThings.append(CGSpecializedSetter(descriptor, m))
+                            if m.hasLenientThis():
+                                hasLenientSetter = True
+                            else:
+                                hasSetter = True
                     elif m.getExtendedAttribute("PutForwards"):
                         cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
                         hasSetter = True
-                    cgThings.append(CGMemberJITInfo(descriptor, m))
+                    if not m.isStatic():
+                        cgThings.append(CGMemberJITInfo(descriptor, m))
             if hasMethod: cgThings.append(CGGenericMethod(descriptor))
             if hasGetter: cgThings.append(CGGenericGetter(descriptor))
             if hasLenientGetter: cgThings.append(CGGenericGetter(descriptor,
                                                                  lenientThis=True))
             if hasSetter: cgThings.append(CGGenericSetter(descriptor))
             if hasLenientSetter: cgThings.append(CGGenericSetter(descriptor,
                                                                  lenientThis=True))
 
@@ -5370,54 +5517,51 @@ class CGDescriptor(CGThing):
                 # Always have a finalize hook, regardless of whether the class
                 # wants a custom hook.
                 cgThings.append(CGClassFinalizeHook(descriptor))
 
                 # Only generate a trace hook if the class wants a custom hook.
                 if (descriptor.customTrace):
                     cgThings.append(CGClassTraceHook(descriptor))
 
+        properties = PropertyArrays(descriptor)
+        cgThings.append(CGGeneric(define=str(properties)))
+        cgThings.append(CGNativeProperties(descriptor, properties))
+
+        cgThings.append(CGNativePropertyHooks(descriptor, properties))
+
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGClassConstructHook(descriptor))
             cgThings.append(CGClassHasInstanceHook(descriptor))
-            cgThings.append(CGInterfaceObjectJSClass(descriptor))
+            cgThings.append(CGInterfaceObjectJSClass(descriptor, properties))
+            cgThings.append(CGClassConstructHookHolder(descriptor))
 
         if descriptor.interface.hasInterfacePrototypeObject():
-            cgThings.append(CGPrototypeJSClass(descriptor))
-
-        properties = PropertyArrays(descriptor)
-        cgThings.append(CGGeneric(define=str(properties)))
-        cgThings.append(CGNativeProperties(descriptor, properties))
+            cgThings.append(CGPrototypeJSClass(descriptor, properties))
+
         cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGGetProtoObjectMethod(descriptor))
-        else:
+        if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGGetConstructorObjectMethod(descriptor))
 
         # Set up our Xray callbacks as needed.  Note that we don't need to do
         # it in workers.
-        if (descriptor.interface.hasInterfacePrototypeObject() and
-            not descriptor.workers):
-            if descriptor.concrete and descriptor.proxy:
-                cgThings.append(CGResolveOwnProperty(descriptor))
-                cgThings.append(CGEnumerateOwnProperties(descriptor))
-            cgThings.append(CGResolveProperty(descriptor, properties))
-            cgThings.append(CGEnumerateProperties(descriptor, properties))
+        if not descriptor.workers and descriptor.concrete and descriptor.proxy:
+            cgThings.append(CGResolveOwnProperty(descriptor))
+            cgThings.append(CGEnumerateOwnProperties(descriptor))
 
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
             if (not descriptor.interface.isExternal() and
                 # Workers stuff is never pref-controlled
                 not descriptor.workers and
                 descriptor.interface.getExtendedAttribute("PrefControlled") is not None):
                 cgThings.append(CGPrefEnabled(descriptor))
 
-        if descriptor.interface.hasInterfacePrototypeObject():
-            cgThings.append(CGNativePropertyHooks(descriptor))
-
         if descriptor.concrete:
             if descriptor.proxy:
                 cgThings.append(CGProxyIsProxy(descriptor))
                 cgThings.append(CGProxyUnwrap(descriptor))
                 cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
                 cgThings.append(CGDOMJSProxyHandler(descriptor))
                 cgThings.append(CGIsMethod(descriptor))
             else:
@@ -6017,17 +6161,17 @@ class CGExampleMember(CGThing):
         self.extendedAttrs = extendedAttrs
         self.resultAlreadyAddRefed = isResultAlreadyAddRefed(self.descriptor,
                                                              self.extendedAttrs)
 
     def define(self):
         static = "static " if self.member.isStatic() else ""
         # Mark our getters, which are attrs that have a non-void return type,
         # as const.
-        if self.member.isAttr() and not self.signatures[0][0].isVoid():
+        if not self.member.isStatic() and self.member.isAttr() and not self.signatures[0][0].isVoid():
             const = " const"
         else:
             const = ""
         return "\n".join("%s%s %s(%s)%s;" %
                          (static,
                           self.getReturnType(s[0], False),
                           self.name,
                           self.getArgs(s[0], s[1]),
@@ -6417,32 +6561,33 @@ class GlobalGenRoots():
     call the appropriate define/declare method.
     """
 
     @staticmethod
     def PrototypeList(config):
 
         # Prototype ID enum.
         protos = [d.name for d in config.getDescriptors(hasInterfacePrototypeObject=True)]
-        idEnum = CGNamespacedEnum('id', 'ID', protos, [0])
+        idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + protos,
+                                  [0, '_ID_Start'])
         idEnum = CGList([idEnum])
         idEnum.append(CGGeneric(declare="const unsigned MaxProtoChainLength = " +
                                 str(config.maxProtoChainLength) + ";\n\n"))
 
         # Wrap all of that in our namespaces.
         idEnum = CGNamespace.build(['mozilla', 'dom', 'prototypes'],
                                    CGWrapper(idEnum, pre='\n'))
         idEnum = CGWrapper(idEnum, post='\n')
 
         curr = CGList([idEnum])
 
         # Constructor ID enum.
-        constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True,
-                                                              hasInterfacePrototypeObject=False)]
-        idEnum = CGNamespacedEnum('id', 'ID', constructors, [0])
+        constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True)]
+        idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + constructors,
+                                  ['prototypes::id::_ID_Count', '_ID_Start'])
 
         # Wrap all of that in our namespaces.
         idEnum = CGNamespace.build(['mozilla', 'dom', 'constructors'],
                                    CGWrapper(idEnum, pre='\n'))
         idEnum = CGWrapper(idEnum, post='\n')
 
         curr.append(idEnum)
 
@@ -6546,15 +6691,15 @@ struct PrototypeIDMap;
 
         unions = UnionConversions(config.getDescriptors())
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'], unions)
 
         curr = CGWrapper(curr, post='\n')
 
-        curr = CGHeaders([], [], ["nsDebug.h", "mozilla/dom/UnionTypes.h", "nsDOMQS.h"], [], curr)
+        curr = CGHeaders([], [], ["nsDebug.h", "mozilla/dom/UnionTypes.h", "nsDOMQS.h", "XPCWrapper.h"], [], curr)
 
         # Add include guards.
         curr = CGIncludeGuard('UnionConversions', curr)
 
         # Done.
         return curr
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -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/. */
 
 #ifndef mozilla_dom_DOMJSClass_h
 #define mozilla_dom_DOMJSClass_h
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "mozilla/Assertions.h"
 
 #include "mozilla/dom/PrototypeList.h" // auto-generated
 
 class nsCycleCollectionParticipant;
 
 // We use slot 0 for holding the raw object.  This is safe for both
 // globals and non-globals.
 #define DOM_OBJECT_SLOT 0
@@ -22,31 +23,37 @@ class nsCycleCollectionParticipant;
 // bindings.
 #define DOM_XRAY_EXPANDO_SLOT 1
 
 // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT.
 #define DOM_PROTOTYPE_SLOT JSCLASS_GLOBAL_SLOT_COUNT
 
 // We use these flag bits for the new bindings.
 #define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1
+#define JSCLASS_IS_DOMIFACEANDPROTOJSCLASS JSCLASS_USERBIT2
 
 // NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
 // LSetDOMProperty. Those constants need to be changed accordingly if this value
 // changes.
 #define DOM_PROTO_INSTANCE_CLASS_SLOT 0
 
+MOZ_STATIC_ASSERT(DOM_PROTO_INSTANCE_CLASS_SLOT != DOM_XRAY_EXPANDO_SLOT,
+                  "Interface prototype object use both of these, so they must "
+                  "not be the same slot.");
+
 namespace mozilla {
 namespace dom {
 
 typedef bool
-(* ResolveProperty)(JSContext* cx, JSObject* wrapper, jsid id, bool set,
-                    JSPropertyDescriptor* desc);
+(* ResolveOwnProperty)(JSContext* cx, JSObject* wrapper, JSObject* obj, jsid id,
+                       bool set, JSPropertyDescriptor* desc);
+
 typedef bool
-(* EnumerateProperties)(JSContext* cx, JSObject* wrapper,
-                        JS::AutoIdVector& props);
+(* EnumerateOwnProperties)(JSContext* cx, JSObject* wrapper, JSObject* obj,
+                           JS::AutoIdVector& props);
 
 struct ConstantSpec
 {
   const char* name;
   JS::Value value;
 };
 
 template<typename T>
@@ -59,38 +66,72 @@ struct Prefable {
   T* specs;
 };
 
 struct NativeProperties
 {
   Prefable<JSFunctionSpec>* staticMethods;
   jsid* staticMethodIds;
   JSFunctionSpec* staticMethodsSpecs;
+  Prefable<JSPropertySpec>* staticAttributes;
+  jsid* staticAttributeIds;
+  JSPropertySpec* staticAttributeSpecs;
   Prefable<JSFunctionSpec>* methods;
   jsid* methodIds;
   JSFunctionSpec* methodsSpecs;
   Prefable<JSPropertySpec>* attributes;
   jsid* attributeIds;
   JSPropertySpec* attributeSpecs;
   Prefable<JSPropertySpec>* unforgeableAttributes;
   jsid* unforgeableAttributeIds;
   JSPropertySpec* unforgeableAttributeSpecs;
   Prefable<ConstantSpec>* constants;
   jsid* constantIds;
   ConstantSpec* constantSpecs;
 };
 
+struct NativePropertiesHolder
+{
+  const NativeProperties* regular;
+  const NativeProperties* chromeOnly;
+};
+
+// Helper structure for Xrays for DOM binding objects. The same instance is used
+// for instances, interface objects and interface prototype objects of a
+// specific interface.
 struct NativePropertyHooks
 {
-  ResolveProperty mResolveOwnProperty;
-  ResolveProperty mResolveProperty;
-  EnumerateProperties mEnumerateOwnProperties;
-  EnumerateProperties mEnumerateProperties;
+  // The hook to call for resolving indexed or named properties. May be null if
+  // there can't be any.
+  ResolveOwnProperty mResolveOwnProperty;
+  // The hook to call for enumerating indexed or named properties. May be null
+  // if there can't be any.
+  EnumerateOwnProperties mEnumerateOwnProperties;
+
+  // The property arrays for this interface.
+  NativePropertiesHolder mNativeProperties;
 
-  const NativePropertyHooks *mProtoHooks;
+  // This will be set to the ID of the interface prototype object for the
+  // interface, if it has one. If it doesn't have one it will be set to
+  // prototypes::id::_ID_Count.
+  prototypes::ID mPrototypeID;
+
+  // This will be set to the ID of the interface object for the interface, if it
+  // has one. If it doesn't have one it will be set to
+  // constructors::id::_ID_Count.
+  constructors::ID mConstructorID;
+
+  // The NativePropertyHooks instance for the parent interface.
+  const NativePropertyHooks* mProtoHooks;
+};
+
+enum DOMObjectType {
+  eInstance,
+  eInterface,
+  eInterfacePrototype
 };
 
 struct DOMClass
 {
   // A list of interfaces that this object implements, in order of decreasing
   // derivedness.
   const prototypes::ID mInterfaceChain[prototypes::id::_ID_Count];
 
@@ -132,16 +173,41 @@ struct DOMJSClass
   }
   static const DOMJSClass* FromJSClass(const js::Class* base) {
     return FromJSClass(Jsvalify(base));
   }
 
   JSClass* ToJSClass() { return &mBase; }
 };
 
+// Special JSClass for DOM interface and interface prototype objects.
+struct DOMIfaceAndProtoJSClass
+{
+  // It would be nice to just inherit from JSClass, but that precludes pure
+  // compile-time initialization of the form
+  // |DOMJSInterfaceAndPrototypeClass = {...};|, since C++ only allows brace
+  // initialization for aggregate/POD types.
+  JSClass mBase;
+
+  // Either eInterface or eInterfacePrototype
+  DOMObjectType mType;
+
+  const NativePropertyHooks* mNativeHooks;
+
+  static const DOMIfaceAndProtoJSClass* FromJSClass(const JSClass* base) {
+    MOZ_ASSERT(base->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS);
+    return reinterpret_cast<const DOMIfaceAndProtoJSClass*>(base);
+  }
+  static const DOMIfaceAndProtoJSClass* FromJSClass(const js::Class* base) {
+    return FromJSClass(Jsvalify(base));
+  }
+
+  JSClass* ToJSClass() { return &mBase; }
+};
+
 inline bool
 HasProtoAndIfaceArray(JSObject* global)
 {
   MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL);
   // This can be undefined if we GC while creating the global
   return !js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).isUndefined();
 }
 
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -31,28 +31,35 @@ def parseInt(literal):
             string = string[1:]
     else:
         base = 10
 
     value = int(string, base)
     return value * sign
 
 # Magic for creating enums
-def M_add_class_attribs(attribs):
+def M_add_class_attribs(attribs, start):
     def foo(name, bases, dict_):
         for v, k in enumerate(attribs):
-            dict_[k] = v
+            dict_[k] = start + v
         assert 'length' not in dict_
-        dict_['length'] = len(attribs)
+        dict_['length'] = start + len(attribs)
         return type(name, bases, dict_)
     return foo
 
-def enum(*names):
-    class Foo(object):
-        __metaclass__ = M_add_class_attribs(names)
+def enum(*names, **kw):
+    if len(kw) == 1:
+        base = kw['base'].__class__
+        start = base.length
+    else:
+        assert len(kw) == 0
+        base = object
+        start = 0
+    class Foo(base):
+        __metaclass__ = M_add_class_attribs(names, start)
         def __setattr__(self, name, value):  # this makes it read-only
             raise NotImplementedError
     return Foo()
 
 class WebIDLError(Exception):
     def __init__(self, message, locations, warning=False):
         self.message = message
         self.locations = [str(loc) for loc in locations]
@@ -1923,16 +1930,21 @@ class IDLNullValue(IDLObject):
 class IDLInterfaceMember(IDLObjectWithIdentifier):
 
     Tags = enum(
         'Const',
         'Attr',
         'Method'
     )
 
+    Special = enum(
+        'Static',
+        'Stringifier'
+    )
+
     def __init__(self, location, identifier, tag):
         IDLObjectWithIdentifier.__init__(self, location, None, identifier)
         self.tag = tag
         self._extendedAttrDict = {}
 
     def isMethod(self):
         return self.tag == IDLInterfaceMember.Tags.Method
 
@@ -1986,28 +1998,29 @@ class IDLConst(IDLInterfaceMember):
         assert coercedValue
 
         self.value = coercedValue
 
     def validate(self):
         pass
 
 class IDLAttribute(IDLInterfaceMember):
-    def __init__(self, location, identifier, type, readonly, inherit,
-                 static=False):
+    def __init__(self, location, identifier, type, readonly, inherit=False,
+                 static=False, stringifier=False):
         IDLInterfaceMember.__init__(self, location, identifier,
                                     IDLInterfaceMember.Tags.Attr)
 
         assert isinstance(type, IDLType)
         self.type = type
         self.readonly = readonly
         self.inherit = inherit
         self.static = static
         self.lenientThis = False
         self._unforgeable = False
+        self.stringifier = stringifier
 
         if readonly and inherit:
             raise WebIDLError("An attribute cannot be both 'readonly' and 'inherit'",
                               [self.location])
 
     def isStatic(self):
         return self.static
 
@@ -2260,24 +2273,22 @@ class IDLMethodOverload:
         self.returnType = returnType
         # Clone the list of arguments, just in case
         self.arguments = list(arguments)
         self.location = location
 
 class IDLMethod(IDLInterfaceMember, IDLScope):
 
     Special = enum(
-        'None',
         'Getter',
         'Setter',
         'Creator',
         'Deleter',
         'LegacyCaller',
-        'Stringifier',
-        'Static'
+        base=IDLInterfaceMember.Special
     )
 
     TypeSuffixModifier = enum(
         'None',
         'QMark',
         'Brackets'
     )
 
@@ -3091,26 +3102,42 @@ class Parser(Tokenizer):
 
     def p_AttributeOrOperation(self, p):
         """
             AttributeOrOperation : Attribute
                                  | Operation
         """
         p[0] = p[1]
 
+    def p_AttributeWithQualifier(self, p):
+        """
+            Attribute : Qualifier AttributeRest
+        """
+        static = IDLInterfaceMember.Special.Static in p[1]
+        stringifier = IDLInterfaceMember.Special.Stringifier in p[1]
+        (location, identifier, type, readonly) = p[2]
+        p[0] = IDLAttribute(location, identifier, type, readonly, static=static,
+                            stringifier=stringifier)
+
     def p_Attribute(self, p):
         """
-            Attribute : Inherit ReadOnly ATTRIBUTE Type IDENTIFIER SEMICOLON
-        """
-        location = self.getLocation(p, 3)
-        inherit = p[1]
-        readonly = p[2]
-        t = p[4]
-        identifier = IDLUnresolvedIdentifier(self.getLocation(p, 5), p[5])
-        p[0] = IDLAttribute(location, identifier, t, readonly, inherit)
+            Attribute : Inherit AttributeRest
+        """
+        (location, identifier, type, readonly) = p[2]
+        p[0] = IDLAttribute(location, identifier, type, readonly, inherit=p[1])
+
+    def p_AttributeRest(self, p):
+        """
+            AttributeRest : ReadOnly ATTRIBUTE Type IDENTIFIER SEMICOLON
+        """
+        location = self.getLocation(p, 2)
+        readonly = p[1]
+        t = p[3]
+        identifier = IDLUnresolvedIdentifier(self.getLocation(p, 4), p[4])
+        p[0] = (location, identifier, t, readonly)
 
     def p_ReadOnly(self, p):
         """
             ReadOnly : READONLY
         """
         p[0] = True
 
     def p_ReadOnlyEmpty(self, p):
@@ -3137,27 +3164,31 @@ class Parser(Tokenizer):
         """
         qualifiers = p[1]
 
         # Disallow duplicates in the qualifier set
         if not len(set(qualifiers)) == len(qualifiers):
             raise WebIDLError("Duplicate qualifiers are not allowed",
                               [self.getLocation(p, 1)])
 
-        static = True if IDLMethod.Special.Static in p[1] else False
+        static = IDLInterfaceMember.Special.Static in p[1]
         # If static is there that's all that's allowed.  This is disallowed
         # by the parser, so we can assert here.
         assert not static or len(qualifiers) == 1
 
+        stringifier = IDLInterfaceMember.Special.Stringifier in p[1]
+        # If stringifier is there that's all that's allowed.  This is disallowed
+        # by the parser, so we can assert here.
+        assert not stringifier or len(qualifiers) == 1
+
         getter = True if IDLMethod.Special.Getter in p[1] else False
         setter = True if IDLMethod.Special.Setter in p[1] else False
         creator = True if IDLMethod.Special.Creator in p[1] else False
         deleter = True if IDLMethod.Special.Deleter in p[1] else False
         legacycaller = True if IDLMethod.Special.LegacyCaller in p[1] else False
-        stringifier = True if IDLMethod.Special.Stringifier in p[1] else False
 
         if getter or deleter:
             if setter or creator:
                 raise WebIDLError("getter and deleter are incompatible with setter and creator",
                                   [self.getLocation(p, 1)])
 
         (returnType, identifier, arguments) = p[2]
 
@@ -3255,25 +3286,32 @@ class Parser(Tokenizer):
                  "stringifier" if stringifier else ""), allowDoubleUnderscore=True)
 
         method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments,
                            static=static, getter=getter, setter=setter, creator=creator,
                            deleter=deleter, specialType=specialType,
                            legacycaller=legacycaller, stringifier=stringifier)
         p[0] = method
 
-    def p_QualifiersStatic(self, p):
-        """
-            Qualifiers : STATIC
-        """
-        p[0] = [IDLMethod.Special.Static]
-
-    def p_QualifiersSpecials(self, p):
-        """
-            Qualifiers : Specials
+    def p_QualifierStatic(self, p):
+        """
+            Qualifier : STATIC
+        """
+        p[0] = [IDLInterfaceMember.Special.Static]
+
+    def p_QualifierStringifier(self, p):
+        """
+            Qualifier : STRINGIFIER
+        """
+        p[0] = [IDLInterfaceMember.Special.Stringifier]
+
+    def p_Qualifiers(self, p):
+        """
+            Qualifiers : Qualifier
+                       | Specials
         """
         p[0] = p[1]
 
     def p_Specials(self, p):
         """
             Specials : Special Specials
         """
         p[0] = [p[1]]
@@ -3310,22 +3348,16 @@ class Parser(Tokenizer):
         p[0] = IDLMethod.Special.Deleter
 
     def p_SpecialLegacyCaller(self, p):
         """
             Special : LEGACYCALLER
         """
         p[0] = IDLMethod.Special.LegacyCaller
 
-    def p_SpecialStringifier(self, p):
-        """
-            Special : STRINGIFIER
-        """
-        p[0] = IDLMethod.Special.Stringifier
-
     def p_OperationRest(self, p):
         """
             OperationRest : ReturnType OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON
         """
         p[0] = (p[1], p[2], p[4])
 
     def p_OptionalIdentifier(self, p):
         """
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -423,16 +423,21 @@ public:
   void PassDictContainingDict(const DictContainingDict&);
   void PassDictContainingSequence(const DictContainingSequence&);
 
   // Typedefs
   void ExerciseTypedefInterfaces1(TestInterface&);
   already_AddRefed<TestInterface> ExerciseTypedefInterfaces2(TestInterface*);
   void ExerciseTypedefInterfaces3(TestInterface&);
 
+  // Static methods and attributes
+  static void StaticMethod(nsISupports*, bool);
+  static bool StaticAttribute(nsISupports*);
+  static void SetStaticAttribute(nsISupports*, bool);
+
   // Miscellania
   int32_t AttrWithLenientThis();
   void SetAttrWithLenientThis(int32_t);
   uint32_t UnforgeableAttr();
   uint32_t UnforgeableAttr2();
   void PassRenamedInterface(nsRenamedInterface&);
   TestInterface* PutForwardsAttr();
   TestInterface* PutForwardsAttr2();
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -329,16 +329,20 @@ interface TestInterface {
   void doClamp([Clamp] byte arg);
 
   // Typedefs
   const myLong myLongConstant = 5;
   void exerciseTypedefInterfaces1(AnotherNameForTestInterface arg);
   AnotherNameForTestInterface exerciseTypedefInterfaces2(NullableTestInterface arg);
   void exerciseTypedefInterfaces3(YetAnotherNameForTestInterface arg);
 
+  // Static methods and attributes
+  static attribute boolean staticAttribute;
+  static void staticMethod(boolean arg);
+
   // Miscellania
   [LenientThis] attribute long attrWithLenientThis;
   [Unforgeable] readonly attribute long unforgeableAttr;
   [Unforgeable, ChromeOnly] readonly attribute long unforgeableAttr2;
   void passRenamedInterface(TestRenamedInterface arg);
   [PutForwards=writableByte] readonly attribute TestInterface putForwardsAttr;
   [PutForwards=writableByte, LenientThis] readonly attribute TestInterface putForwardsAttr2;
   [PutForwards=writableByte, ChromeOnly] readonly attribute TestInterface putForwardsAttr3;
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -296,16 +296,20 @@ interface TestExampleInterface {
   void doClamp([Clamp] byte arg);
 
   // Typedefs
   const myLong myLongConstant = 5;
   void exerciseTypedefInterfaces1(AnotherNameForTestInterface arg);
   AnotherNameForTestInterface exerciseTypedefInterfaces2(NullableTestInterface arg);
   void exerciseTypedefInterfaces3(YetAnotherNameForTestInterface arg);
 
+  // Static methods and attributes
+  static attribute boolean staticAttribute;
+  static void staticMethod(boolean arg);
+
   // Miscellania
   [LenientThis] attribute long attrWithLenientThis;
   [Unforgeable] readonly attribute long unforgeableAttr;
   [Unforgeable, ChromeOnly] readonly attribute long unforgeableAttr2;
   void passRenamedInterface(TestRenamedInterface arg);
   [PutForwards=writableByte] readonly attribute TestExampleInterface putForwardsAttr;
   [PutForwards=writableByte, LenientThis] readonly attribute TestExampleInterface putForwardsAttr2;
   [PutForwards=writableByte, ChromeOnly] readonly attribute TestExampleInterface putForwardsAttr3;
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -366,19 +366,20 @@ BrowserElementParent.prototype = {
     if (this._window.document.mozHidden) {
       this._ownerVisibilityChange();
     }
   },
 
   _recvGetName: function(data) {
     return this._frameElement.getAttribute('name');
   },
-  
+
   _recvGetFullscreenAllowed: function(data) {
-    return this._frameElement.hasAttribute('mozallowfullscreen');
+    return this._frameElement.hasAttribute('allowfullscreen') ||
+           this._frameElement.hasAttribute('mozallowfullscreen');
   },
 
   _fireCtxMenuEvent: function(data) {
     let evtName = data.name.substring('browser-element-api:'.length);
     let detail = data.json;
 
     debug('fireCtxMenuEventFromMsg: ' + evtName + ' ' + detail);
     let evt = this._createEvent(evtName, detail);
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -23,16 +23,17 @@
 #include "libcameraservice/CameraHardwareInterface.h"
 #include "camera/CameraParameters.h"
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfo.h"
 #include "nsMemory.h"
 #include "jsapi.h"
 #include "nsThread.h"
 #include <media/MediaProfiles.h>
+#include "mozilla/FileUtils.h"
 #include "nsDirectoryServiceDefs.h" // for NS_GetSpecialDirectory
 #include "nsPrintfCString.h"
 #include "DOMCameraManager.h"
 #include "GonkCameraHwMgr.h"
 #include "DOMCameraCapabilities.h"
 #include "DOMCameraControl.h"
 #include "GonkRecorderProfiles.h"
 #include "GonkCameraControl.h"
@@ -729,30 +730,27 @@ nsGonkCameraControl::StartRecordingImpl(
    */
   nsCOMPtr<nsIFile> filename = aStartRecording->mFolder;
   filename->AppendRelativePath(aStartRecording->mFilename);
 
   nsAutoCString nativeFilename;
   filename->GetNativePath(nativeFilename);
   DOM_CAMERA_LOGI("Video filename is '%s'\n", nativeFilename.get());
 
-  int fd = open(nativeFilename.get(), O_RDWR | O_CREAT, 0644);
+  ScopedClose fd(open(nativeFilename.get(), O_RDWR | O_CREAT, 0644));
   if (fd < 0) {
     DOM_CAMERA_LOGE("Couldn't create file '%s': (%d) %s\n", nativeFilename.get(), errno, strerror(errno));
     return NS_ERROR_FAILURE;
   }
 
-  if (SetupRecording(fd) != NS_OK) {
-    DOM_CAMERA_LOGE("SetupRecording() failed\n");
-    close(fd);
-    return NS_ERROR_FAILURE;
-  }
+  nsresult rv = SetupRecording(fd);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   if (mRecorder->start() != OK) {
     DOM_CAMERA_LOGE("mRecorder->start() failed\n");
-    close(fd);
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsGonkCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
--- a/dom/file/test/test_archivereader.html
+++ b/dom/file/test/test_archivereader.html
@@ -3,18 +3,24 @@
   http://creativecommons.org/publicdomain/zero/1.0/
 -->
 <html>
 <head>
   <title>Archive Reader Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
 
-  <script type="text/javascript;version=1.7">
+<body>
+<p id="display">
+  <input id="fileList" type="file"></input>
+</p>
+
+<script type="text/javascript;version=1.7">
   function createZipFileWithData(fileData) {
     var Cc = SpecialPowers.Cc;
     var Ci = SpecialPowers.Ci;
 
     var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
     var testFile = dirSvc.get("ProfD", Ci.nsIFile);
     testFile.append("fileArchiveReader.zip");
     var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
@@ -43,16 +49,27 @@
     outStream.close();
 
     var fileList = document.getElementById('fileList');
     SpecialPowers.wrap(fileList).value = testFile.path;
 
     return fileList.files[0];
   }
 
+  handleFinished = 0;
+  function markTestDone() {
+    ++handleFinished;
+    if (isFinished()) {
+      SimpleTest.finish();
+    }
+  }
+  function isFinished() {
+    return handleFinished == 5;
+  }
+
   function testSteps()
   {
     var binaryString = '504B03040A00000000002E6BF14000000000000000000000000005001C00746573742F555409000337CA055039CA055075780B' +
                        '000104E803000004E8030000504B03041400000008002D6BF1401780E15015000000580200000A001C00746573742F612E7478' +
                        '74555409000336CA05503ACA055075780B000104E803000004E8030000CB48CDC9C95728CF2FCA49E1CA18658FB2A9C4060050' +
                        '4B03040A00000000002F88EC40662E847010000000100000000A001C00746573742F622E74787455540900035A65FF4F42C505' +
                        '5075780B000104E803000004E803000068656C6C6F20776F726C642C2032210A504B01021E030A00000000002E6BF140000000' +
                        '000000000000000000050018000000000000001000FD4100000000746573742F555405000337CA055075780B000104E8030000' +
@@ -106,116 +123,120 @@
     var rt = new ArchiveReader(textFile);
     isnot(rt, null, "ArchiveReader cannot be null");
 
     // GetFilename
     var handle = rt.getFilenames();
     isnot(handle, null, "ArchiveReader.getFilenames() cannot be null");
     handle.onsuccess = function() {
       ok(false, "ArchiveReader.getFilenames() should return a 'failure' if the input file is not a zip");
+      markTestDone();
     }
     handle.onerror = function() {
       ok(true, "ArchiveReader.getFilenames() should return a 'error' if the input file is a zip file");
       is(this.reader, rt, "ArchiveRequest.reader == ArchiveReader");
+      markTestDone();
     }
 
     // Create - good!
     var r = new ArchiveReader(binaryFile);
     isnot(r, null, "ArchiveReader cannot be null");
 
     // GetFilename
     handle = r.getFilenames();
     isnot(handle, null, "ArchiveReader.getFilenames() cannot be null");
     handle.onsuccess = function() {
       ok(true, "ArchiveReader.getFilenames() should return a 'success'");
       is(this.result instanceof Array, true, "ArchiveReader.getFilenames() should return an array");
       is(this.result.length, 2, "ArchiveReader.getFilenames(): the array contains 2 items");
       is(this.result[0], "test/a.txt", "ArchiveReader.getFilenames(): first file is 'test/a.txt'");
       is(this.result[1], "test/b.txt", "ArchiveReader.getFilenames(): second file is 'test/b.txt'");
       ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
+      markTestDone();
     }
     handle.onerror = function() {
       ok(false, "ArchiveReader.getFilenames() should not return any 'error'");
+      markTestDone();
     }
 
     // GetFile - wrong (no args)
     try {
       r.getFile();
       status = false;
     }
     catch(e) {
       status = true;
     }
     ok(status, "ArchiveReader.getFile() without args fail");
 
     var handle2 = r.getFile("hello world");
     isnot(handle2, null, "ArchiveReader.getFile() cannot be null");
     handle2.onsuccess = function() {
       ok(false, "ArchiveReader.getFile('unknown file') should not return a 'success'");
+      markTestDone();
     }
     handle2.onerror = function() {
       ok(true, "ArchiveReader.getFile('unknown file') should return an 'error'");
       ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
+      markTestDone();
     }
 
     var handle3 = r.getFile("test/b.txt");
     isnot(handle3, null, "ArchiveReader.getFile() cannot be null");
     handle3.onsuccess = function() {
       ok(true, "ArchiveReader.getFile('test/b.txt') should return a 'success'");
       ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
       is(this.result.name, "test/b.txt", "ArchiveReader.getFile('test/b.txt') the name MUST be 'test/b.txt'");
       is(this.result.type, "text/plain", "ArchiveReader.getFile('test/b.txt') the type MUST be 'text/plain'");
 
       var fr = new FileReader();
       fr.readAsText(this.result);
       fr.onerror = function() {
         ok(false, "ArchiveReader + FileReader should work!");
+        markTestDone();
       }
       fr.onload = function(event) {
         is(event.target.result, "hello world, 2!\n", "ArchiveReader + FileReader are working together.");
+        markTestDone();
       }
     }
 
     handle3.onerror = function() {
       ok(false, "ArchiveReader.getFile('test/b.txt') should not return an 'error'");
+      markTestDone();
     }
 
     var handle4 = r.getFile("test/a.txt");
     isnot(handle4, null, "ArchiveReader.getFile() cannot be null");
     handle4.onsuccess = function() {
       ok(true, "ArchiveReader.getFile('test/a.txt') should return a 'success'");
       ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
       is(this.result.name, "test/a.txt", "ArchiveReader.getFile('test/a.txt') the name MUST be 'test/a.txt'");
       is(this.result.type, "text/plain", "ArchiveReader.getFile('test/a.txt') the type MUST be 'text/plain'");
 
       var fr = new FileReader();
       fr.readAsText(this.result);
       fr.onerror = function() {
         ok(false, "ArchiveReader + FileReader should work!");
+        markTestDone();
       }
       fr.onload = function(event) {
         is(event.target.result.length, 600, "ArchiveReader + FileReader are working with a compress data");
         var p = event.target.result.trim().split('\n');
         is(p.length, 50, "ArchiveReader + FileReader are working with a compress data");
 
         for (var i = 0; i < p.length; ++i)
           is(p[i], "hello world", "ArchiveReader + FileReader are working with a compress data");
+        markTestDone();
       }
     }
     handle4.onerror = function() {
       ok(false, "ArchiveReader.getFile('test/a.txt') should not return an 'error'");
+      markTestDone();
     }
+  }
 
-    finishTest();
-    yield;
-  }
+  SimpleTest.waitForExplicitFinish();
+  testSteps();
   </script>
-  <script type="text/javascript;version=1.7" src="helpers.js"></script>
-
-</head>
-
-<body onload="runTest();">
-<p id="display">
-  <input id="fileList" type="file"></input>
-</p>
 </body>
 
 </html>
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -494,16 +494,17 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDB
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mOwningObject)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 DOMCI_DATA(IDBFactory, IDBFactory)
 
 nsresult
 IDBFactory::OpenCommon(const nsAString& aName,
                        int64_t aVersion,
+                       const nsACString& aASCIIOrigin,
                        bool aDeleting,
                        JSContext* aCallingCx,
                        IDBOpenDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mWindow || mOwningObject, "Must have one of these!");
 
   nsCOMPtr<nsPIDOMWindow> window;
@@ -524,36 +525,36 @@ IDBFactory::OpenCommon(const nsAString& 
   nsRefPtr<IDBOpenDBRequest> request =
     IDBOpenDBRequest::Create(this, window, scriptOwner, aCallingCx);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsresult rv;
 
   if (IndexedDatabaseManager::IsMainProcess()) {
     nsRefPtr<OpenDatabaseHelper> openHelper =
-      new OpenDatabaseHelper(request, aName, mASCIIOrigin, aVersion, aDeleting,
+      new OpenDatabaseHelper(request, aName, aASCIIOrigin, aVersion, aDeleting,
                              mContentParent, privilege);
 
     rv = openHelper->Init();
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     nsRefPtr<CheckPermissionsHelper> permissionHelper =
       new CheckPermissionsHelper(openHelper, window, aDeleting);
 
     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     NS_ASSERTION(mgr, "This should never be null!");
 
     rv =
-      mgr->WaitForOpenAllowed(OriginOrPatternString::FromOrigin(mASCIIOrigin),
+      mgr->WaitForOpenAllowed(OriginOrPatternString::FromOrigin(aASCIIOrigin),
                               openHelper->Id(), permissionHelper);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
   else if (aDeleting) {
     nsCOMPtr<nsIAtom> databaseId =
-      IndexedDatabaseManager::GetDatabaseId(mASCIIOrigin, aName);
+      IndexedDatabaseManager::GetDatabaseId(aASCIIOrigin, aName);
     NS_ENSURE_TRUE(databaseId, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     IndexedDBDeleteDatabaseRequestChild* actor =
       new IndexedDBDeleteDatabaseRequestChild(this, request, databaseId);
 
     mActorChild->SendPIndexedDBDeleteDatabaseRequestConstructor(
                                                                actor,
                                                                nsString(aName));
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -87,20 +87,32 @@ public:
   static nsresult
   SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
                       uint64_t aVersion,
                       ObjectStoreInfoArray& aObjectStores);
 
   nsresult
   OpenCommon(const nsAString& aName,
              int64_t aVersion,
+             const nsACString& aASCIIOrigin,
              bool aDeleting,
              JSContext* aCallingCx,
              IDBOpenDBRequest** _retval);
 
+  nsresult
+  OpenCommon(const nsAString& aName,
+             int64_t aVersion,
+             bool aDeleting,
+             JSContext* aCallingCx,
+             IDBOpenDBRequest** _retval)
+  {
+    return OpenCommon(aName, aVersion, mASCIIOrigin, aDeleting, aCallingCx,
+                      _retval);
+  }
+
   void
   SetActor(IndexedDBChild* aActorChild)
   {
     NS_ASSERTION(!aActorChild || !mActorChild, "Shouldn't have more than one!");
     mActorChild = aActorChild;
   }
 
   void
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -76,16 +76,17 @@ MOCHITEST_FILES = \
   test_multientry.html \
   test_names_sorted.html \
   test_objectCursors.html \
   test_objectStore_inline_autoincrement_key_added_on_put.html \
   test_objectStore_remove_values.html \
   test_object_identity.html \
   test_odd_result_order.html \
   test_open_empty_db.html \
+  test_open_for_principal.html \
   test_open_objectStore.html \
   test_optionalArguments.html \
   test_overlapping_transactions.html \
   test_put_get_values.html \
   test_put_get_values_autoIncrement.html \
   test_readonly_transactions.html \
   test_remove_index.html \
   test_remove_objectStore.html \
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_open_for_principal.html
@@ -0,0 +1,31 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Property Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript;version=1.7">
+  function testSteps()
+  {
+    is("open" in indexedDB, true, "open() defined");
+    is("openForPrincipal" in indexedDB, false, "openForPrincipal() not defined");
+
+    is("deleteDatabase" in indexedDB, true, "deleteDatabase() defined");
+    is("deleteForPrincipal" in indexedDB, false, "deleteForPrincipal() not defined");
+
+    finishTest();
+    yield;
+  }
+  </script>
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+
+</head>
+
+<body onload="runTest();"></body>
+
+</html>
--- a/dom/indexedDB/test/unit/Makefile.in
+++ b/dom/indexedDB/test/unit/Makefile.in
@@ -40,16 +40,17 @@ MOCHITEST_FILES = \
   test_multientry.js \
   test_names_sorted.js \
   test_object_identity.js \
   test_objectCursors.js \
   test_objectStore_inline_autoincrement_key_added_on_put.js \
   test_objectStore_remove_values.js \
   test_odd_result_order.js \
   test_open_empty_db.js \
+  test_open_for_principal.js \
   test_open_objectStore.js \
   test_optionalArguments.js \
   test_overlapping_transactions.js \
   test_put_get_values.js \
   test_put_get_values_autoIncrement.js \
   test_remove_index.js \
   test_remove_objectStore.js \
   test_request_readyState.js \
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_open_for_principal.js
@@ -0,0 +1,90 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function testSteps()
+{
+  const name = this.window ? window.location.pathname : "Splendid Test";
+
+  const objectStoreName = "Foo";
+
+  const data = { key: 1, value: "bar" };
+
+  let request = indexedDB.open(name, 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  let event = yield;
+
+  is(event.type, "upgradeneeded", "Got correct event type");
+
+  let db = event.target.result;
+  db.onerror = errorHandler;
+
+  let objectStore = db.createObjectStore(objectStoreName, { });
+
+  event = yield;
+
+  is(event.type, "success", "Got correct event type");
+
+  objectStore = db.transaction([objectStoreName], "readwrite")
+                  .objectStore(objectStoreName);
+
+  request = objectStore.get(data.key);
+  request.onsuccess = grabEventAndContinueHandler;
+  event = yield;
+
+  is(event.target.result, null, "Got no data");
+
+  request = objectStore.add(data.value, data.key);
+  request.onsuccess = grabEventAndContinueHandler;
+  event = yield;
+
+  is(event.target.result, data.key, "Got correct key");
+
+  let uri = Components.classes["@mozilla.org/network/io-service;1"]
+                      .getService(Components.interfaces.nsIIOService)
+                      .newURI("http://appdata.example.com", null, null);
+  let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+                     .getService(Components.interfaces.nsIScriptSecurityManager)
+                     .getNoAppCodebasePrincipal(uri);
+
+  request = indexedDB.openForPrincipal(principal, name, 1);
+  request.onerror = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  request.onsuccess = grabEventAndContinueHandler;
+  let event = yield;
+
+  is(event.type, "upgradeneeded", "Got correct event type");
+
+  db = event.target.result;
+  db.onerror = errorHandler;
+
+  objectStore = db.createObjectStore(objectStoreName, { });
+
+  event = yield;
+
+  is(event.type, "success", "Got correct event type");
+
+  objectStore = db.transaction([objectStoreName])
+                  .objectStore(objectStoreName);
+
+  request = objectStore.get(data.key);
+  request.onsuccess = grabEventAndContinueHandler;
+  event = yield;
+
+  is(event.target.result, null, "Got no data");
+
+  db.close();
+
+  request = indexedDB.deleteForPrincipal(principal, name);
+  request.onerror = errorHandler;
+  request.onsuccess = grabEventAndContinueHandler
+  event = yield;
+
+  finishTest();
+  yield;
+}
--- a/dom/indexedDB/test/unit/xpcshell.ini
+++ b/dom/indexedDB/test/unit/xpcshell.ini
@@ -33,16 +33,17 @@ tail =
 [test_multientry.js]
 [test_names_sorted.js]
 [test_object_identity.js]
 [test_objectCursors.js]
 [test_objectStore_inline_autoincrement_key_added_on_put.js]
 [test_objectStore_remove_values.js]
 [test_odd_result_order.js]
 [test_open_empty_db.js]
+[test_open_for_principal.js]
 [test_open_objectStore.js]
 [test_optionalArguments.js]
 [test_overlapping_transactions.js]
 [test_put_get_values.js]
 [test_put_get_values_autoIncrement.js]
 [test_remove_index.js]
 [test_remove_objectStore.js]
 [test_request_readyState.js]
--- a/dom/interfaces/base/nsIContentPrefService.idl
+++ b/dom/interfaces/base/nsIContentPrefService.idl
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIVariant;
 interface nsIPropertyBag2;
 interface nsIContentURIGrouper;
+interface nsILoadContext;
 interface mozIStorageConnection;
 
 [scriptable, uuid(746c7a02-f6c1-4869-b434-7c8b86e60e61)]
 interface nsIContentPrefObserver : nsISupports
 {
   /**
    * Called when a content pref is set to a different value.
    * 
@@ -33,17 +34,17 @@ interface nsIContentPrefObserver : nsISu
 };
 
 [scriptable, function, uuid(c1b3d6df-5373-4606-8494-8bcf14a7fc62)]
 interface nsIContentPrefCallback : nsISupports
 {
   void onResult(in nsIVariant aResult);
 };
 
-[scriptable, uuid(0014e2b4-1bab-4946-9211-7d28fc8df4d7)]
+[scriptable, uuid(e3f772f3-023f-4b32-b074-36cf0fd5d414)]
 interface nsIContentPrefService : nsISupports
 {
   /**
    * Get a pref.
    *
    * Besides the regular string, integer, boolean, etc. values, this method
    * may return null (nsIDataType::VTYPE_EMPTY), which means the pref is set
    * to NULL in the database, as well as undefined (nsIDataType::VTYPE_VOID),
@@ -52,119 +53,166 @@ interface nsIContentPrefService : nsISup
    * This method can be called from content processes in electrolysis builds.
    * We have a whitelist of values that can be read in such a way.
    *
    * @param    aGroup      the group for which to get the pref, as an nsIURI
    *                       from which the hostname will be used, a string
    *                       (typically in the format of a hostname), or null 
    *                       to get the global pref (applies to all sites)
    * @param    aName       the name of the pref to get
+   * @param    aPrivacyContext
+   *                       a context from which to determine the privacy status
+   *                       of the pref (ie. whether to search in memory or in
+   *                       permanent storage for it), obtained from a relevant
+   *                       window or channel.
    * @param    aCallback   an optional nsIContentPrefCallback to receive the
    *                       result. If desired, JavaScript callers can instead
    *                       provide a function to call upon completion
    *
    * @returns  the value of the pref
    * @throws   NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null
    * @throws   NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string
    */
   nsIVariant getPref(in nsIVariant aGroup, in AString aName,
+                     in nsILoadContext aPrivacyContext,
                      [optional] in nsIContentPrefCallback aCallback);
 
   /**
    * Set a pref.
    *
    * This method can be called from content processes in electrolysis builds.
    * We have a whitelist of values that can be set in such a way.
    *
    * @param    aGroup      the group for which to set the pref, as an nsIURI
    *                       from which the hostname will be used, a string
    *                       (typically in the format of a hostname), or null
    *                       to set the global pref (applies to all sites)
    * @param    aName       the name of the pref to set
    * @param    aValue      the new value of the pref
+   * @param    aPrivacyContext
+   *                       a context from which to determine the privacy status
+   *                       of the pref (ie. whether to store it in memory or in
+   *                       permanent storage), obtained from a relevant
+   *                       window or channel.
    * @throws   NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null
    * @throws   NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string
    */
-  void setPref(in nsIVariant aGroup, in AString aName, in nsIVariant aValue);
+  void setPref(in nsIVariant aGroup, in AString aName, in nsIVariant aValue, in nsILoadContext aPrivacyContext);
   
   /**
    * Check whether or not a pref exists.
    *
    * @param    aGroup      the group for which to check for the pref, as an nsIURI
    *                       from which the hostname will be used, a string
    *                       (typically in the format of a hostname), or null
    *                       to check for the global pref (applies to all sites)
    * @param    aName       the name of the pref to check for
+   * @param    aPrivacyContext
+   *                       a context from which to determine the privacy status
+   *                       of the pref (ie. whether to search in memory or in
+   *                       permanent storage for it), obtained from a relevant
+   *                       window or channel.
    * @throws   NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null
    * @throws   NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string
    */
-  boolean hasPref(in nsIVariant aGroup, in AString aName);
+  boolean hasPref(in nsIVariant aGroup, in AString aName, in nsILoadContext aContext);
 
   /**
    * Check whether or not the value of a pref (or its non-existance) is cached.
    *
    * @param    aGroup      the group for which to check for the pref, as an nsIURI
    *                       from which the hostname will be used, a string
    *                       (typically in the format of a hostname), or null
    *                       to check for the global pref (applies to all sites)
    * @param    aName       the name of the pref to check for
+   * @param    aPrivacyContext
+   *                       a context from which to determine the privacy status
+   *                       of the pref (ie. whether to search in memory or in
+   *                       permanent storage for it), obtained from a relevant
+   *                       window or channel.
    * @throws   NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null
    * @throws   NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string
    */
-  boolean hasCachedPref(in nsIVariant aGroup, in AString aName);
+  boolean hasCachedPref(in nsIVariant aGroup, in AString aName, in nsILoadContext aContext);
 
   /**
    * Remove a pref.
    *
    * @param    aGroup      the group for which to remove the pref, as an nsIURI
    *                       from which the hostname will be used, a string
    *                       (typically in the format of a hostname), or null
    *                       to remove the global pref (applies to all sites) 
    * @param    aName       the name of the pref to remove
+   * @param    aPrivacyContext
+   *                       a context from which to determine the privacy status
+   *                       of the pref (ie. whether to search in memory or in
+   *                       permanent storage for it), obtained from a relevant
+   *                       window or channel.
    * @throws   NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null
    * @throws   NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string
    */
-  void removePref(in nsIVariant aGroup, in AString aName);
+  void removePref(in nsIVariant aGroup, in AString aName, in nsILoadContext aContext);
 
   /**
    * Remove all grouped prefs.  Useful for removing references to the sites
    * the user has visited when the user clears their private data.
+   *
+   * @param    aPrivacyContext
+   *                       a context from which to determine the privacy status
+   *                       of the pref (ie. whether to remove prefs in memory or
+   *                       in permanent storage), obtained from a relevant
+   *                       window or channel.
    */
-  void removeGroupedPrefs();
+  void removeGroupedPrefs(in nsILoadContext aContext);
 
   /**
    * Remove all prefs with the given name.
    *
    * @param    aName        the setting name for which to remove prefs
+   * @param    aPrivacyContext
+   *                        a context from which to determine the privacy status
+   *                        of the prefs (ie. whether to remove prefs in memory or
+   *                        in permanent storage), obtained from a relevant
+   *                        window or channel.
    * @throws   NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string
    */
-  void removePrefsByName(in AString aName);
+  void removePrefsByName(in AString aName, in nsILoadContext aContext);
 
   /**
    * Get the prefs that apply to the given site.
    *
    * @param    aGroup      the group for which to retrieve prefs, as an nsIURI
    *                       from which the hostname will be used, a string
    *                       (typically in the format of a hostname), or null
    *                       to get the global prefs (apply to all sites) 
+   * @param    aPrivacyContext
+   *                       a context from which to determine the privacy status
+   *                       of the pref (ie. whether to search for prefs in memory
+   *                       or in permanent storage), obtained from a relevant
+   *                       window or channel.
    * 
    * @returns  a property bag of prefs
    * @throws   NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null
    */
-  nsIPropertyBag2 getPrefs(in nsIVariant aGroup);
+  nsIPropertyBag2 getPrefs(in nsIVariant aGroup, in nsILoadContext aContext);
 
   /**
    * Get the prefs with the given name.
    *
    * @param    aName        the setting name for which to retrieve prefs
+   * @param    aPrivacyContext
+   *                        a context from which to determine the privacy status
+   *                        of the pref (ie. whether to search for prefs in memory
+   *                        or in permanent storage), obtained from a relevant
+   *                        window or channel.
    * 
    * @returns  a property bag of prefs
    * @throws   NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string
    */
-  nsIPropertyBag2 getPrefsByName(in AString aName);
+  nsIPropertyBag2 getPrefsByName(in AString aName, in nsILoadContext aContext);
   
   /**
    * Add an observer.
    * 
    * @param    aName       the setting to observe, or null to add
    *                       a generic observer that observes all settings
    * @param    aObserver   the observer to add
    */
--- a/dom/interfaces/core/nsIDOMDocument.idl
+++ b/dom/interfaces/core/nsIDOMDocument.idl
@@ -348,17 +348,17 @@ interface nsIDOMDocument : nsIDOMNode
    *
    * @see <https://wiki.mozilla.org/index.php?title=Gecko:FullScreenAPI>
    */
   readonly attribute boolean mozFullScreen;  
 
   /**
    * Denotes whether the full-screen-api.enabled is true, no windowed
    * plugins are present, and all ancestor documents have the
-   * mozallowfullscreen attribute set.
+   * allowfullscreen attribute set.
    *
    * @see <https://wiki.mozilla.org/index.php?title=Gecko:FullScreenAPI>
    */
   readonly attribute boolean mozFullScreenEnabled;
 
   /**
    * The element to which the mouse pointer is locked, if any, as per the
    * DOM pointer lock api.
--- a/dom/interfaces/html/nsIDOMHTMLIFrameElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLIFrameElement.idl
@@ -11,17 +11,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(52f6244b-b1f5-4f4c-8ff3-7e146316f411)]
+[scriptable, uuid(a7bd1e34-3969-47ae-8c1d-2970132ba925)]
 interface nsIDOMHTMLIFrameElement : nsIDOMHTMLElement
 {
            attribute DOMString        align;
            attribute DOMString        frameBorder;
            attribute DOMString        height;
            attribute DOMString        longDesc;
            attribute DOMString        marginHeight;
            attribute DOMString        marginWidth;
@@ -30,13 +30,13 @@ interface nsIDOMHTMLIFrameElement : nsID
            attribute DOMString        src;
            attribute DOMString        width;
   // Introduced in DOM Level 2:
   readonly attribute nsIDOMDocument   contentDocument;
   readonly attribute nsIDOMWindow     contentWindow;
 
            attribute DOMString        sandbox;
   // Mozilla extensions
-  // iframe elements require the mozAllowFullScreen attribute to be present
+  // iframe elements require the allowfullscreen attribute to be present
   // if they're to allow content in the sub document to go into DOM full-screen
   // mode. See https://wiki.mozilla.org/index.php?title=Gecko:FullScreenAPI
-           attribute boolean          mozAllowFullScreen;
+           attribute boolean          allowfullscreen;
 };
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -15,17 +15,16 @@
 #include "ContentChild.h"
 #include "CrashReporterChild.h"
 #include "TabChild.h"
 #if defined(MOZ_SYDNEYAUDIO)
 #include "AudioChild.h"
 #endif
 
 #include "mozilla/Attributes.h"
-#include "mozilla/MemoryInfoDumper.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 #include "mozilla/dom/StorageChild.h"
 #include "mozilla/Hal.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
 #include "mozilla/jsipc/PContextWrapperChild.h"
@@ -34,16 +33,17 @@
 #include "mozilla/layers/PCompositorChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/Preferences.h"
 
 #if defined(MOZ_SYDNEYAUDIO)
 #include "nsAudioStream.h"
 #endif
 #include "nsIMemoryReporter.h"
+#include "nsIMemoryInfoDumper.h"
 #include "nsIObserverService.h"
 #include "nsTObserverArray.h"
 #include "nsIObserver.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXULAppAPI.h"
 #include "nsWeakReference.h"
 #include "nsIScriptError.h"
@@ -443,26 +443,30 @@ ContentChild::DeallocPMemoryReportReques
     return true;
 }
 
 bool
 ContentChild::RecvDumpMemoryReportsToFile(const nsString& aIdentifier,
                                           const bool& aMinimizeMemoryUsage,
                                           const bool& aDumpChildProcesses)
 {
-    MemoryInfoDumper::DumpMemoryReportsToFile(
+    nsCOMPtr<nsIMemoryInfoDumper> dumper = do_GetService("@mozilla.org/memory-info-dumper;1");
+
+    dumper->DumpMemoryReportsToFile(
         aIdentifier, aMinimizeMemoryUsage, aDumpChildProcesses);
     return true;
 }
 
 bool
 ContentChild::RecvDumpGCAndCCLogsToFile(const nsString& aIdentifier,
                                         const bool& aDumpChildProcesses)
 {
-    MemoryInfoDumper::DumpGCAndCCLogsToFile(
+    nsCOMPtr<nsIMemoryInfoDumper> dumper = do_GetService("@mozilla.org/memory-info-dumper;1");
+
+    dumper->DumpGCAndCCLogsToFile(
         aIdentifier, aDumpChildProcesses);
     return true;
 }
 
 PCompositorChild*
 ContentChild::AllocPCompositor(mozilla::ipc::Transport* aTransport,
                                base::ProcessId aOtherProcess)
 {
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -152,17 +152,17 @@ parent:
      *  if cancel is PR_TRUE,
      *    widget should return empty string for composition
      *  if cancel is PR_FALSE,
      *    widget should return the current composition text
      */
     sync EndIMEComposition(bool cancel) returns (nsString composition);
 
     sync GetInputContext() returns (int32_t IMEEnabled, int32_t IMEOpen,
-                                    int64_t NativeIMEContext);
+                                    intptr_t NativeIMEContext);
 
     SetInputContext(int32_t IMEEnabled,
                     int32_t IMEOpen,
                     nsString type,
                     nsString inputmode,
                     nsString actionHint,
                     int32_t cause,
                     int32_t focusChange);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -739,30 +739,30 @@ TabParent::RecvEndIMEComposition(const b
   *aComposition = mIMECompositionText;
   mIMECompositionText.Truncate(0);  
   return true;
 }
 
 bool
 TabParent::RecvGetInputContext(int32_t* aIMEEnabled,
                                int32_t* aIMEOpen,
-                               int64_t* aNativeIMEContext)
+                               intptr_t* aNativeIMEContext)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     *aIMEEnabled = IMEState::DISABLED;
     *aIMEOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
     *aNativeIMEContext = 0;
     return true;
   }
 
   InputContext context = widget->GetInputContext();
   *aIMEEnabled = static_cast<int32_t>(context.mIMEState.mEnabled);
   *aIMEOpen = static_cast<int32_t>(context.mIMEState.mOpen);
-  *aNativeIMEContext = reinterpret_cast<int64_t>(context.mNativeIMEContext);
+  *aNativeIMEContext = reinterpret_cast<intptr_t>(context.mNativeIMEContext);
   return true;
 }
 
 bool
 TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
                                const int32_t& aIMEOpen,
                                const nsString& aType,
                                const nsString& aInputmode,
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -119,17 +119,17 @@ public:
     virtual bool RecvNotifyIMESelection(const uint32_t& aSeqno,
                                         const uint32_t& aAnchor,
                                         const uint32_t& aFocus);
     virtual bool RecvNotifyIMETextHint(const nsString& aText);
     virtual bool RecvEndIMEComposition(const bool& aCancel,
                                        nsString* aComposition);
     virtual bool RecvGetInputContext(int32_t* aIMEEnabled,
                                      int32_t* aIMEOpen,
-                                     int64_t* aNativeIMEContext);
+                                     intptr_t* aNativeIMEContext);
     virtual bool RecvSetInputContext(const int32_t& aIMEEnabled,
                                      const int32_t& aIMEOpen,
                                      const nsString& aType,
                                      const nsString& aInputmode,
                                      const nsString& aActionHint,
                                      const int32_t& aCause,
                                      const int32_t& aFocusChange);
     virtual bool RecvSetCursor(const uint32_t& aValue);
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -67,17 +67,17 @@ nsIJSONEncodeDeprecatedWarning=nsIJSON.e
 nsIDOMWindowInternalWarning=Use of nsIDOMWindowInternal is deprecated. Use nsIDOMWindow instead.
 InputEncodingWarning=Use of inputEncoding is deprecated.
 # LOCALIZATION NOTE: Do not translate "MozBeforePaint" and "mozRequestAnimationFrame"
 MozBeforePaintWarning=MozBeforePaint events are no longer supported.  mozRequestAnimationFrame must be passed a non-null callback argument.
 FullScreenDeniedBlocked=Request for full-screen was denied because this domain has been blocked from full-screen by user.
 FullScreenDeniedDisabled=Request for full-screen was denied because full-screen API is disabled by user preference.
 FullScreenDeniedFocusedPlugin=Request for full-screen was denied because a windowed plugin is focused.
 FullScreenDeniedHidden=Request for full-screen was denied because the document is no longer visible.
-FullScreenDeniedIframeDisallowed=Request for full-screen was denied because at least one of the document's containing iframes does not have a "mozallowfullscreen" attribute.
+FullScreenDeniedIframeDisallowed=Request for full-screen was denied because at least one of the document's containing iframes does not have an "allowfullscreen" attribute.
 FullScreenDeniedNotInputDriven=Request for full-screen was denied because Element.mozRequestFullScreen() was not called from inside a short running user-generated event handler.
 FullScreenDeniedNotInDocument=Request for full-screen was denied because requesting element is no longer in its document.
 FullScreenDeniedMovedDocument=Request for full-screen was denied because requesting element has moved document.
 FullScreenDeniedLostWindow=Request for full-screen was denied because we no longer have a window.
 FullScreenDeniedSubDocFullScreen=Request for full-screen was denied because a subdocument of the document requesting full-screen is already full-screen.
 FullScreenDeniedNotDescendant=Request for full-screen was denied because requesting element is not a descendant of the current full-screen element.
 FullScreenDeniedNotFocusedTab=Request for full-screen was denied because requesting element is not in the currently focused tab.
 RemovedFullScreenElement=Exited full-screen because full-screen element was removed from document.
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -650,16 +650,30 @@ static JSContext *
 GetJSContextFromNPP(NPP npp)
 {
   nsIDocument *doc = GetDocumentFromNPP(npp);
   NS_ENSURE_TRUE(doc, nullptr);
 
   return GetJSContextFromDoc(doc);
 }
 
+static nsresult
+GetPrivacyFromNPP(NPP npp, bool* aPrivate)
+{
+  nsCOMPtr<nsIDocument> doc = GetDocumentFromNPP(npp);
+  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> domwindow = doc->GetWindow();
+  NS_ENSURE_TRUE(domwindow, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsIDocShell> docShell = domwindow->GetDocShell();
+  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
+  *aPrivate = loadContext && loadContext->UsePrivateBrowsing();
+  return NS_OK;
+}
+
 static NPIdentifier
 doGetIdentifier(JSContext *cx, const NPUTF8* name)
 {
   NS_ConvertUTF8toUTF16 utf16name(name);
 
   JSString *str = ::JS_InternUCStringN(cx, (jschar *)utf16name.get(),
                                        utf16name.Length());
 
@@ -2025,26 +2039,22 @@ NPError NP_CALLBACK
     *(NPBool*)result = true;
 #else
     *(NPBool*)result = false;
 #endif
     return NPERR_NO_ERROR;
   }
 
   case NPNVprivateModeBool: {
-    nsCOMPtr<nsIDocument> doc = GetDocumentFromNPP(npp);
-    NS_ENSURE_TRUE(doc, NPERR_GENERIC_ERROR);
-    nsCOMPtr<nsPIDOMWindow> domwindow = doc->GetWindow();
-    if (domwindow) {
-      nsCOMPtr<nsIDocShell> docShell = domwindow->GetDocShell();
-      nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
-      *(NPBool*)result = (NPBool)(loadContext && loadContext->UsePrivateBrowsing());
-      return NPERR_NO_ERROR;
-    }
-    return NPERR_GENERIC_ERROR;
+    bool privacy;
+    nsresult rv = GetPrivacyFromNPP(npp, &privacy);
+    if (NS_FAILED(rv))
+      return NPERR_GENERIC_ERROR;
+    *(NPBool*)result = (NPBool)privacy;
+    return NPERR_NO_ERROR;
   }
 
   case NPNVdocumentOrigin: {
     nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata;
     if (!inst) {
       return NPERR_GENERIC_ERROR;
     }
 
@@ -2724,22 +2734,25 @@ NPError NP_CALLBACK
       !proto.LowerCaseEqualsLiteral("https"))
     return NPERR_GENERIC_ERROR;
 
   nsCOMPtr<nsIHttpAuthManager> authManager =
     do_GetService("@mozilla.org/network/http-auth-manager;1");
   if (!authManager)
     return NPERR_GENERIC_ERROR;
 
+  bool authPrivate = false;
+  GetPrivacyFromNPP(instance, &authPrivate);
+
   nsAutoString unused, uname16, pwd16;
   if (NS_FAILED(authManager->GetAuthIdentity(proto, nsDependentCString(host),
                                              port, nsDependentCString(scheme),
                                              nsDependentCString(realm),
                                              EmptyCString(), unused, uname16,
-                                             pwd16))) {
+                                             pwd16, authPrivate))) {
     return NPERR_GENERIC_ERROR;
   }
 
   NS_ConvertUTF16toUTF8 uname8(uname16);
   NS_ConvertUTF16toUTF8 pwd8(pwd16);
 
   *username = ToNewCString(uname8);
   *ulen = *username ? uname8.Length() : 0;
--- a/dom/src/events/nsJSEventListener.cpp
+++ b/dom/src/events/nsJSEventListener.cpp
@@ -18,16 +18,17 @@
 #include "nsVariant.h"
 #include "nsIDOMBeforeUnloadEvent.h"
 #include "nsGkAtoms.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIJSContextStack.h"
 #include "xpcpublic.h"
 #include "nsJSEnvironment.h"
 #include "nsDOMJSUtils.h"
+#include "mozilla/Likely.h"
 #ifdef DEBUG
 
 #include "nspr.h" // PR_fprintf
 
 class EventListenerCounter
 {
 public:
   ~EventListenerCounter() {
@@ -66,17 +67,17 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSEvent
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSEventListener)
   if (tmp->mContext) {
     NS_DROP_JS_OBJECTS(tmp, nsJSEventListener);
     tmp->mScopeObject = nullptr;
     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSEventListener)
-  if (NS_UNLIKELY(cb.WantDebugInfo()) && tmp->mEventName) {
+  if (MOZ_UNLIKELY(cb.WantDebugInfo()) && tmp->mEventName) {
     nsAutoCString name;
     name.AppendLiteral("nsJSEventListener handlerName=");
     name.Append(
       NS_ConvertUTF16toUTF8(nsDependentAtomString(tmp->mEventName)).get());
     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name.get());
   } else {
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSEventListener, tmp->mRefCnt.get())
   }
--- a/dom/tests/browser/Makefile.in
+++ b/dom/tests/browser/Makefile.in
@@ -15,16 +15,17 @@ MOCHITEST_BROWSER_FILES := \
   browser_focus_steal_from_chrome_during_mousedown.js \
   browser_autofocus_background.js \
   browser_ConsoleAPITests.js \
   test-console-api.html \
   browser_ConsoleStorageAPITests.js \
   browser_ConsoleStoragePBTest.js \
   browser_autofocus_preference.js \
   browser_bug396843.js \
+  browser_xhr_sandbox.js \
   $(NULL)
 
 ifeq (Linux,$(OS_ARCH))
 MOCHITEST_BROWSER_FILES += \
   browser_webapps_permissions.js \
   test-webapp.webapp \
   test-webapp-reinstall.webapp \
   test-webapp-original.webapp \
new file mode 100644
--- /dev/null
+++ b/dom/tests/browser/browser_xhr_sandbox.js
@@ -0,0 +1,49 @@
+// This code is evaluated in a sandbox courtesy of toSource();
+let sandboxCode = (function() {
+  let req = new XMLHttpRequest();
+  req.open("GET", "http://mochi.test:8888/browser/dom/tests/browser/", true);
+  req.onreadystatechange = function() {
+    if (req.readyState === 4) {
+      // If we get past the problem above, we end up with a req.status of zero
+      // (ie, blocked due to CORS) even though we are fetching from the same
+      // origin as the window itself.
+      let result;
+      if (req.status != 200) {
+        result = "ERROR: got request status of " + req.status;
+      } else if (req.responseText.length == 0) {
+        result = "ERROR: got zero byte response text";
+      } else {
+        result = "ok";
+      }
+      postMessage({result: result}, "*");
+    }
+  };
+  req.send(null);
+}).toSource() + "();";
+
+function test() {
+  waitForExplicitFinish();
+  let appShell = Cc["@mozilla.org/appshell/appShellService;1"]
+                  .getService(Ci.nsIAppShellService);
+  let doc = appShell.hiddenDOMWindow.document;
+  let frame = doc.createElement("iframe");
+  frame.setAttribute("type", "content");
+  frame.setAttribute("src", "http://mochi.test:8888/browser/dom/tests/browser/browser_xhr_sandbox.js");
+
+  frame.addEventListener("load", function () {
+    let workerWindow = frame.contentWindow;
+    workerWindow.addEventListener("message", function(evt) {
+      is(evt.data.result, "ok", "check the sandbox code was happy");
+      finish();
+    }, true);
+    let sandbox = new Cu.Sandbox(workerWindow);
+    // inject some functions from the window into the sandbox.
+    // postMessage so the async code in the sandbox can report a result.
+    sandbox.importFunction(workerWindow.postMessage, "postMessage");
+    sandbox.importFunction(workerWindow.XMLHttpRequest, "XMLHttpRequest");
+    Cu.evalInSandbox(sandboxCode, sandbox, "1.8");
+  }, true);
+
+  let container = doc.body ? doc.body : doc.documentElement;
+  container.appendChild(frame);
+}
--- a/dom/tests/mochitest/chrome/Makefile.in
+++ b/dom/tests/mochitest/chrome/Makefile.in
@@ -47,16 +47,18 @@ MOCHITEST_CHROME_FILES = \
 		test_sandbox_postMessage.html \
 		test_sandbox_bindings.xul \
 		test_selectAtPoint.html \
 		selectAtPoint.html \
 		test_bug799299.xul \
 		file_bug799299.xul \
 		test_bug800817.xul \
 		file_bug800817.xul \
+		test_subscript_bindings.xul \
+		file_subscript_bindings.js \
 		$(NULL)
 
 ifeq (WINNT,$(OS_ARCH))
 MOCHITEST_CHROME_FILES += \
 		test_sizemode_attribute.xul \
 		sizemode_attribute.xul \
 		$(NULL)
 endif
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/file_subscript_bindings.js
@@ -0,0 +1,1 @@
+new window.XMLHttpRequest();
--- a/dom/tests/mochitest/chrome/test_sandbox_bindings.xul
+++ b/dom/tests/mochitest/chrome/test_sandbox_bindings.xul
@@ -16,44 +16,108 @@ https://bugzilla.mozilla.org/show_bug.cg
      target="_blank">Mozilla Bug 741267</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
 
   /** Test for Bug 741267 **/
+    function isXrayWrapper(x) {
+      return XPCNativeWrapper.unwrap(x) != x;
+    }
+
     function doTest() {
       var win = $("t").contentWindow;
       var sandbox = Components.utils.Sandbox(win, { sandboxPrototype: win });
       try {
-        var nl = Components.utils.evalInSandbox("NodeList", sandbox);
-        is(nl, String(NodeList), "'NodeList' in a sandbox should return the NodeList interface prototype object");
+        var css = Components.utils.evalInSandbox("CSSStyleDeclaration", sandbox);
+        is(css.prototype, "[object CSSStyleDeclarationPrototype]", "'CSSStyleDeclaration.prototype' in a sandbox should return the CSSStyleDeclaration interface prototype object");
       } catch (e) {
-        ok(false, "'NodeList' shouldn't throw in a sandbox");
+        ok(false, "'CSSStyleDeclaration' shouldn't throw in a sandbox");
       }
       try {
         var et = Components.utils.evalInSandbox("EventTarget", sandbox);
-        ok(et, "'EventTarget' in a sandbox should return the EventTarget interface prototype object");
+        ok(et, "'EventTarget' in a sandbox should return the EventTarget interface object");
+        ok(isXrayWrapper(et), "Getting an interface object on an Xray wrapper should return an Xray wrapper");
       } catch (e) {
         ok(false, "'EventTarget' shouldn't throw in a sandbox");
       }
       try {
+        var xhr = Components.utils.evalInSandbox("XMLHttpRequest.prototype", sandbox);
+        ok(xhr, "'XMLHttpRequest.prototype' in a sandbox should return the XMLHttpRequest interface prototype object");
+        ok(isXrayWrapper(xhr), "Getting an interface prototype object on an Xray wrapper should return an Xray wrapper");
+        ok(isXrayWrapper(xhr.constructor), "Getting the constructor property on an Xray wrapper of an interface prototype object should return an Xray wrapper");
+      } catch (e) {
+        ok(false, "'XMLHttpRequest.prototype' shouldn't throw in a sandbox");
+      }
+      try {
+        var xhr = Components.utils.evalInSandbox("XMLHttpRequest", sandbox);
+        xhr.prototype = false;
+      } catch (e) {
+        ok(true, "'XMLHttpRequest.prototype' should be readonly");
+      }
+      try {
+        var xhr = Components.utils.evalInSandbox("XMLHttpRequest", sandbox);
+        delete xhr.prototype;
+      } catch (e) {
+        ok(true, "'XMLHttpRequest.prototype' should be permanent");
+      }
+      try {
+        var xhr = Components.utils.evalInSandbox("XMLHttpRequest.prototype", sandbox);
+        xhr.constructor = "ok";
+      } catch (e) {
+        is(xhr.constructor, "ok", "'XMLHttpRequest.prototype.constructor' should be writeable");
+      }
+      try {
+        var xhr = Components.utils.evalInSandbox("XMLHttpRequest.prototype", sandbox);
+        delete xhr.constructor;
+      } catch (e) {
+        is(xhr.constructor, undefined, "'XMLHttpRequest.prototype.constructor' should be permanent");
+      }
+      try {
+        var xhr = Components.utils.evalInSandbox("XMLHttpRequest", sandbox);
+        is(xhr, "[object XrayWrapper " + XMLHttpRequest + "]", "'XMLHttpRequest' in a sandbox should return the XMLHttpRequest interface object");
+        ok(isXrayWrapper(xhr.prototype), "Getting the prototype property on an Xray wrapper of an interface object should return an Xray wrapper");
+      } catch (e) {
+        ok(false, "'XMLHttpRequest' shouldn't throw in a sandbox");
+      }
+      try {
         var xhr = Components.utils.evalInSandbox("XMLHttpRequest()", sandbox);
-        is(xhr, "[object XMLHttpRequest]", "'XMLHttpRequest()' in a sandbox should create an XMLHttpRequest object");
+        is("" + xhr, "" + XMLHttpRequest(), "'XMLHttpRequest()' in a sandbox should create an XMLHttpRequest object");
+      } catch (e) {
+        ok(false, "'XMLHttpRequest()' shouldn't throw in a sandbox");
+      }
+      try {
+        var xhr = Components.utils.evalInSandbox("XMLHttpRequest.prototype.toString = function () { return 'Failed'; }; XMLHttpRequest();", sandbox);
+        is(xhr.toString(), "[object XrayWrapper " + XMLHttpRequest() + "]", "XMLHttpRequest.prototype.toString in the sandbox should not override the native toString behaviour");
+      } catch (e) {
+        ok(false, "'new XMLHttpRequest()' shouldn't throw in a sandbox");
+      }
+      try {
+        Components.utils.evalInSandbox("document.defaultView.XMLHttpRequest = function() {};", sandbox);
+        var win = Components.utils.evalInSandbox("document.defaultView", sandbox);
+        var xhr = win.XMLHttpRequest();
+        is("" + xhr, "" + XMLHttpRequest(), "'XMLHttpRequest()' in a sandbox should create an XMLHttpRequest object");
       } catch (e) {
         ok(false, "'XMLHttpRequest()' shouldn't throw in a sandbox");
       }
       try {
         var canvas = Components.utils.evalInSandbox("document.createElement('canvas').getContext('2d')", sandbox);
         is(canvas.DRAWWINDOW_DRAW_CARET, CanvasRenderingContext2D.DRAWWINDOW_DRAW_CARET, "Constants should be defined on DOM objects in a sandbox");
       } catch (e) {
         ok(false, "'document.createElement('canvas').getContext('2D')' shouldn't throw in a sandbox");
       }
       try {
+        var classList = Components.utils.evalInSandbox("document.body.className = 'a b'; document.body.classList", sandbox);
+        is(classList.toString(), "a b", "Stringifier should be called");
+      } catch (e) {
+        ok(false, "'document.createElement('canvas').getContext('2D')' shouldn't throw in a sandbox");
+      }
+      try {
         var ctx = Components.utils.evalInSandbox("var ctx = document.createElement('canvas').getContext('2d'); ctx.foopy = 5; ctx", sandbox);
         ok(!("foopy" in ctx), "We should have an Xray here");
         var data = ctx.createImageData(1, 1);
         for (var i = 0; i < data.data.length; ++i) {
           // Watch out for premultiplied bits... just set all the alphas to 255
           if (i % 4 == 3) {
             data.data[i] = 255;
           } else {
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/test_subscript_bindings.xul
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=741267
+-->
+<window title="Mozilla Bug 741267"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <iframe id="t"></iframe>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=741267"
+     target="_blank">Mozilla Bug 741267</a>
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+
+  /** Test for Bug 741267 **/
+    function doTest() {
+      // Resolve XMLHttpRequest on the chrome global
+      new XMLHttpRequest();
+
+      var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
+      var context = { window: $("t").contentWindow };
+      var thrown = false;
+      try {
+        loader.loadSubScript(/.*\//.exec(window.location.href)[0] + "file_subscript_bindings.js", context);
+      } catch (e) {
+        thrown = true;
+      }
+      ok(!thrown, "'new window.XMLHttpRequest()' in a subscript shouldn't throw");
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  ]]>
+  </script>
+</window>
--- a/dom/tests/mochitest/pointerlock/file_allowPointerLockSandboxFlag.html
+++ b/dom/tests/mochitest/pointerlock/file_allowPointerLockSandboxFlag.html
@@ -13,17 +13,17 @@
     <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=784402">
       Mozilla Bug 784402</a>
     <p id="display"></p>
 
-    <iframe src ="iframe_differentDOM.html" mozallowfullscreen="true" id="iframe"
+    <iframe src ="iframe_differentDOM.html" allowfullscreen="true" id="iframe"
       onload="startTest()"
       sandbox="allow-scripts allow-same-origin allow-pointer-lock">
     </iframe>
 
     <pre id="test">
       <script type="application/javascript">
         /*
          * Test for Bug 784402
--- a/dom/tests/mochitest/pointerlock/test_pointerlock-api.html
+++ b/dom/tests/mochitest/pointerlock/test_pointerlock-api.html
@@ -15,36 +15,36 @@ https://bugzilla.mozilla.org/show_bug.cg
     </a>
     <div id="content">
     </div>
     <pre id="test">
       <script type="application/javascript">
         /**
          * Pointer Lock tests for bug 633602.  These depend on the fullscreen api
          * which doesn't work when run in the mochitests' iframe, since the
-         * mochitests' iframe doesn't have a mozallowfullscreen attribute.  To get
+         * mochitests' iframe doesn't have an allowfullscreen attribute.  To get
          * around this, all tests are run in a child window, which can go fullscreen.
          * This method is borrowed from content/html/content/test/test_fullscreen-api.html.
          **/
 
         SimpleTest.waitForExplicitFinish();
 
         // Ensure the full-screen api is enabled, and will be disabled on test exit.
         SpecialPowers.setBoolPref("full-screen-api.enabled", true);
 
         // Disable the requirement for trusted contexts only, so the tests are easier to write.
         SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
 
         // Grant "fullscreen" permission on the test domain. This means fullscreen will be
         // automatically approved, so pointer lock in the tests will be too.
         SpecialPowers.setFullscreenAllowed(document);
-        
+
         // Run the tests which go full-screen in new window, as Mochitests
         // normally run in an iframe, which by default will not have the
-        // mozallowfullscreen attribute set, so full-screen won't work.
+        // allowfullscreen attribute set, so full-screen won't work.
         var gTestFiles = [
           "file_approval.html",
           "file_screenClientXYConst.html",
           "file_childIframe.html",
           "file_doubleLock.html",
           "file_escapeKey.html",
           "file_infiniteMovement.html",
           "file_locksvgelement.html",
@@ -67,21 +67,21 @@ https://bugzilla.mozilla.org/show_bug.cg
         // TODO: if ever we remove these checks for XP and Lion, we should do the same
         // in content/html/content/test/test_fullscreen-api.html, which uses the same pattern.
         const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
         const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
         const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
 
         function finish() {
           SpecialPowers.clearUserPref("full-screen-api.enabled");
-          SpecialPowers.clearUserPref("full-screen-api.allow-trusted-requests-only");        
+          SpecialPowers.clearUserPref("full-screen-api.allow-trusted-requests-only");
           SpecialPowers.removeFullscreenAllowed(document)
           SimpleTest.finish();
         }
-        
+
         function nextTest() {
           if (isWinXP) {
             todo(false, "Can't reliably run full-screen tests on Windows XP due to bug 704010");
             finish();
             return;
           }
           if (isOSXLion || isOSXMtnLion) {
             todo(false, "Can't reliably run full-screen tests on OS X Lion or Mountain Lion, see bug 744125");
new file mode 100644
--- /dev/null
+++ b/dom/webidl/AudioParam.webidl
@@ -0,0 +1,43 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[PrefControlled]
+interface AudioParam {
+
+    attribute float value;
+    // readonly attribute float computedValue;
+    readonly attribute float minValue;
+    readonly attribute float maxValue;
+    readonly attribute float defaultValue;
+
+    // Parameter automation. 
+    [Throws]
+    void setValueAtTime(float value, float startTime);
+    [Throws]
+    void linearRampToValueAtTime(float value, float endTime);
+    [Throws]
+    void exponentialRampToValueAtTime(float value, float endTime);
+
+    // Exponentially approach the target value with a rate having the given time constant. 
+    [Throws]
+    void setTargetAtTime(float target, float startTime, float timeConstant);
+
+    // Sets an array of arbitrary parameter values starting at time for the given duration. 
+    // The number of values will be scaled to fit into the desired duration. 
+    // [Throws]
+    // void setValueCurveAtTime(Float32Array values, float startTime, float duration);
+
+    // Cancels all scheduled parameter changes with times greater than or equal to startTime. 
+    // void cancelScheduledValues(float startTime);
+
+};
+
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -9,16 +9,17 @@ generated_webidl_files = \
   $(NULL)
 
 webidl_files = \
   AudioBuffer.webidl \
   AudioBufferSourceNode.webidl \
   AudioContext.webidl \
   AudioDestinationNode.webidl \
   AudioNode.webidl \
+  AudioParam.webidl \
   AudioSourceNode.webidl \
   Blob.webidl \
   CanvasRenderingContext2D.webidl \
   ClientRectList.webidl \
   CSSStyleDeclaration.webidl \
   DOMImplementation.webidl \
   DOMTokenList.webidl \
   DOMSettableTokenList.webidl \
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -230,31 +230,57 @@ var WifiManager = (function() {
   function reconnectCommand(callback) {
     doBooleanCommand("RECONNECT", "OK", callback);
   }
 
   function reassociateCommand(callback) {
     doBooleanCommand("REASSOCIATE", "OK", callback);
   }
 
+  // A note about background scanning:
+  // Normally, background scanning shouldn't be necessary as wpa_supplicant
+  // has the capability to automatically schedule its own scans at appropriate
+  // intervals. However, with some drivers, this appears to get stuck after
+  // three scans, so we enable the driver's background scanning to work around
+  // that when we're not connected to any network. This ensures that we'll
+  // automatically reconnect to networks if one falls out of range.
+  var reEnableBackgroundScan = false;
+  var backgroundScanEnabled = false;
+  function setBackgroundScan(enable, callback) {
+    var doEnable = (enable === "ON");
+    if (doEnable === backgroundScanEnabled) {
+      callback(false, true);
+      return;
+    }
+
+    backgroundScanEnabled = doEnable;
+    doBooleanCommand("SET pno " + (backgroundScanEnabled ? "1" : "0"), "OK",
+                     function(ok) {
+                       callback(true, ok);
+                     });
+  }
+
   var scanModeActive = false;
 
   function doSetScanModeCommand(setActive, callback) {
     doBooleanCommand(setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE", "OK", callback);
   }
 
   function scanCommand(forceActive, callback) {
     if (forceActive && !scanModeActive) {
       // Note: we ignore errors from doSetScanMode.
       doSetScanModeCommand(true, function(ignore) {
-        doBooleanCommand("SCAN", "OK", function(ok) {
-          doSetScanModeCommand(false, function(ignore) {
-            // The result of scanCommand is the result of the actual SCAN
-            // request.
-            callback(ok);
+        setBackgroundScan("OFF", function(turned, ignore) {
+          reEnableBackgroundScan = turned;
+          doBooleanCommand("SCAN", "OK", function(ok) {
+            doSetScanModeCommand(false, function(ignore) {
+              // The result of scanCommand is the result of the actual SCAN
+              // request.
+              callback(ok);
+            });
           });
         });
       });
       return;
     }
     doBooleanCommand("SCAN", "OK", callback);
   }
 
@@ -570,16 +596,26 @@ var WifiManager = (function() {
     // do anything, so just ignore them.
     if (manager.state === "COMPLETED" &&
         fields.state !== "DISCONNECTED" &&
         fields.state !== "INTERFACE_DISABLED" &&
         fields.state !== "INACTIVE" &&
         fields.state !== "SCANNING") {
       return false;
     }
+
+    // Stop background scanning if we're trying to connect to a network.
+    if (backgroundScanEnabled &&
+        (fields.state === "ASSOCIATING" ||
+         fields.state === "ASSOCIATED" ||
+         fields.state === "FOUR_WAY_HANDSHAKE" ||
+         fields.state === "GROUP_HANDSHAKE" ||
+         fields.state === "COMPLETED")) {
+      setBackgroundScan("OFF", function() {});
+    }
     fields.prevState = manager.state;
     manager.state = fields.state;
 
     // Detect wpa_supplicant's loop iterations.
     manager.supplicantLoopDetection(fields.prevState, fields.state);
     notify("statechange", fields);
     return true;
   }
@@ -623,18 +659,34 @@ var WifiManager = (function() {
       manager.connectionInfo.ssid = ssid;
       manager.connectionInfo.id = id;
     }
 
     if (ip_address)
       dhcpInfo = { ip_address: ip_address };
 
     notifyStateChange({ state: state, fromStatus: true });
-    if (state === "COMPLETED")
-      onconnected();
+
+    // If we parse the status and the supplicant has already entered the
+    // COMPLETED state, then we need to set up DHCP right away. Otherwise, if
+    // we're not actively connecting to a network, we need to turn on
+    // background scanning.
+    switch (state) {
+      case "COMPLETED":
+        onconnected();
+        break;
+
+      case "DISCONNECTED":
+      case "INACTIVE":
+      case "SCANNING":
+        setBackgroundScan("ON", function(){});
+
+      default:
+        break;
+    }
   }
 
   // try to connect to the supplicant
   var connectTries = 0;
   var retryTimer = null;
   function connectCallback(ok) {
     if (ok === 0) {
       // Tell the event worker to start waiting for events.
@@ -806,16 +858,20 @@ var WifiManager = (function() {
       // Don't call onconnected if we ignored this state change (since we were
       // already connected).
       if (notifyStateChange({ state: "CONNECTED", BSSID: bssid, id: id }))
         onconnected();
       return true;
     }
     if (eventData.indexOf("CTRL-EVENT-SCAN-RESULTS") === 0) {
       debug("Notifying of scan results available");
+      if (reEnableBackgroundScan) {
+        reEnableBackgroundScan = false;
+        setBackgroundScan("ON", function() {});
+      }
       notify("scanresultsavailable");
       return true;
     }
     if (eventData.indexOf("WPS-TIMEOUT") === 0) {
       notifyStateChange({ state: "WPS_TIMEOUT", BSSID: null, id: -1 });
       return true;
     }
     if (eventData.indexOf("WPS-FAIL") === 0) {
@@ -1156,16 +1212,17 @@ var WifiManager = (function() {
   manager.disableNetwork = function(netId, callback) {
     disableNetworkCommand(netId, callback);
   }
   manager.getMacAddress = getMacAddressCommand;
   manager.getScanResults = scanResultsCommand;
   manager.setScanMode = function(mode, callback) {
     setScanModeCommand(mode === "active", callback);
   }
+  manager.setBackgroundScan = setBackgroundScan;
   manager.scan = scanCommand;
   manager.wpsPbc = wpsPbcCommand;
   manager.wpsPin = wpsPinCommand;
   manager.wpsCancel = wpsCancelCommand;
   manager.setPowerMode = setPowerModeCommand;
   manager.setSuspendOptimizations = setSuspendOptimizationsCommand;
   manager.getRssiApprox = getRssiApproxCommand;
   manager.getLinkSpeed = getLinkSpeedCommand;
@@ -1640,16 +1697,18 @@ function WifiWorker() {
           // We've disconnected from a network because of a call to forgetNetwork.
           // Reconnect to the next available network (if any).
           if (self._reconnectOnDisconnect) {
             self._reconnectOnDisconnect = false;
             WifiManager.reconnect(function(){});
           }
         });
 
+        WifiManager.setBackgroundScan("ON", function(){});
+
         WifiNetworkInterface.state =
           Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED;
         WifiNetworkInterface.ip = null;
         WifiNetworkInterface.netmask = null;
         WifiNetworkInterface.broadcast = null;
         WifiNetworkInterface.gateway = null;
         WifiNetworkInterface.dns1 = null;
         WifiNetworkInterface.dns2 = null;
--- a/dom/workers/DOMBindingInlines.h
+++ b/dom/workers/DOMBindingInlines.h
@@ -34,17 +34,17 @@ struct WrapPrototypeTraits
       using namespace mozilla::dom;                                            \
       return _class##Binding_workers::Class.ToJSClass();                       \
     }                                                                          \
                                                                                \
     static inline JSObject*                                                    \
     GetProtoObject(JSContext* aCx, JSObject* aGlobal)                          \
     {                                                                          \
       using namespace mozilla::dom;                                            \
-      return _class##Binding_workers::GetProtoObject(aCx, aGlobal, aGlobal);   \
+      return _class##Binding_workers::GetProtoObject(aCx, aGlobal);            \
     }                                                                          \
   };
 
 SPECIALIZE_PROTO_TRAITS(FileReaderSync)
 SPECIALIZE_PROTO_TRAITS(XMLHttpRequest)
 SPECIALIZE_PROTO_TRAITS(XMLHttpRequestUpload)
 
 #undef SPECIALIZE_PROTO_TRAITS
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -543,17 +543,17 @@ ResolveWorkerClasses(JSContext* aCx, JSH
 
   if (shouldResolve) {
     // Don't do anything if workers are disabled.
     if (!isChrome && !Preferences::GetBool(PREF_WORKERS_ENABLED)) {
       aObjp.set(nullptr);
       return true;
     }
 
-    JSObject* eventTarget = EventTargetBinding_workers::GetProtoObject(aCx, aObj, aObj);
+    JSObject* eventTarget = EventTargetBinding_workers::GetProtoObject(aCx, aObj);
     if (!eventTarget) {
       return false;
     }
 
     JSObject* worker = worker::InitClass(aCx, aObj, eventTarget, true);
     if (!worker) {
       return false;
     }
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -20,35 +20,16 @@
 #define FUNCTION_FLAGS \
   JSPROP_ENUMERATE
 
 USING_WORKERS_NAMESPACE
 
 using namespace mozilla::dom;
 using mozilla::ErrorResult;
 
-// These are temporary until these classes are moved to be codegenerated.
-bool
-WorkerResolveProperty(JSContext* cx, JSObject* wrapper, jsid id, bool set,
-                      JSPropertyDescriptor* desc)
-{
-  return true;
-}
-bool
-WorkerEnumerateProperties(JSContext* cx, JSObject* wrapper,
-                          JS::AutoIdVector& props)
-{
-  return true;
-}
-NativePropertyHooks mozilla::dom::workers::sNativePropertyHooks =
-  { WorkerResolveProperty, WorkerResolveProperty,
-    WorkerEnumerateProperties, WorkerEnumerateProperties,
-    NULL };
-
-
 namespace {
 
 class Worker
 {
   static DOMJSClass sClass;
   static JSPropertySpec sProperties[];
   static JSFunctionSpec sFunctions[];
 
@@ -294,32 +275,30 @@ private:
 
     return worker->PostMessage(aCx, message, transferable);
   }
 };
 
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
 
-// When this DOMJSClass is removed and it's the last consumer of
-// sNativePropertyHooks then sNativePropertyHooks should be removed too.
 DOMJSClass Worker::sClass = {
   {
     "Worker",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2) |
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
     NULL, NULL, NULL, NULL, Trace
   },
   {
     { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
       prototypes::id::_ID_Count },
     false,
-    &sNativePropertyHooks
+    &sWorkerNativePropertyHooks
   }
 };
 
 JSPropertySpec Worker::sProperties[] = {
   { sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
@@ -420,31 +399,29 @@ private:
       worker->_trace(aTrc);
     }
   }
 };
 
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
 
-// When this DOMJSClass is removed and it's the last consumer of
-// sNativePropertyHooks then sNativePropertyHooks should be removed too.
 DOMJSClass ChromeWorker::sClass = {
   { "ChromeWorker",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2) |
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
     NULL, NULL, NULL, NULL, Trace,
   },
   {
     { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
       prototypes::id::_ID_Count },
     false,
-    &sNativePropertyHooks
+    &sWorkerNativePropertyHooks
   }
 };
 
 WorkerPrivate*
 Worker::GetInstancePrivate(JSContext* aCx, JSObject* aObj,
                            const char* aFunctionName)
 {
   JSClass* classPtr = JS_GetClass(aObj);
--- a/dom/workers/Worker.h
+++ b/dom/workers/Worker.h
@@ -8,18 +8,16 @@
 
 #include "Workers.h"
 
 #include "jspubtd.h"
 #include "mozilla/dom/DOMJSClass.h"
 
 BEGIN_WORKERS_NAMESPACE
 
-extern mozilla::dom::NativePropertyHooks sNativePropertyHooks;
-
 namespace worker {
 
 JSObject*
 InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
           bool aMainRuntime);
 
 } // namespace worker
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -39,16 +39,17 @@
 #include "nsGUIEvent.h"
 #include "nsJSEnvironment.h"
 #include "nsJSUtils.h"
 #include "nsNetUtil.h"
 #include "nsSandboxFlags.h"
 #include "nsThreadUtils.h"
 #include "xpcpublic.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Likely.h"
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 #include "Events.h"
 #include "Exceptions.h"
 #include "File.h"
@@ -3673,17 +3674,17 @@ WorkerPrivate::SetTimeout(JSContext* aCx
   if (currentStatus >= Closing) {
     return false;
   }
 
   nsAutoPtr<TimeoutInfo> newInfo(new TimeoutInfo());
   newInfo->mIsInterval = aIsInterval;
   newInfo->mId = timerId;
 
-  if (NS_UNLIKELY(timerId == UINT32_MAX)) {
+  if (MOZ_UNLIKELY(timerId == UINT32_MAX)) {
     NS_WARNING("Timeout ids overflowed!");
     mNextTimeoutId = 1;
   }
 
   JS::Value* argv = JS_ARGV(aCx, aVp);
 
   // Take care of the main argument.
   if (argv[0].isObject()) {
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -814,17 +814,17 @@ private:
 
   static void
   Trace(JSTracer* aTrc, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
     DedicatedWorkerGlobalScope* scope =
       UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj, eRegularDOMObject);
     if (scope) {
-      mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
+      TraceProtoAndIfaceCache(aTrc, aObj);
       scope->_trace(aTrc);
     }
   }
 
   static JSBool
   PostMessage(JSContext* aCx, unsigned aArgc, jsval* aVp)
   {
     JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
@@ -847,34 +847,32 @@ private:
 
     return scope->mWorker->PostMessageToParent(aCx, message, transferable);
   }
 };
 
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
 
-// When this DOMJSClass is removed and it's the last consumer of
-// sNativePropertyHooks then sNativePropertyHooks should be removed too.
 DOMJSClass DedicatedWorkerGlobalScope::sClass = {
   {
     // We don't have to worry about Xray expando slots here because we'll never
     // have an Xray wrapper to a worker global scope.
     "DedicatedWorkerGlobalScope",
     JSCLASS_DOM_GLOBAL | JSCLASS_IS_DOMJSCLASS | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(3) | JSCLASS_NEW_RESOLVE,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, reinterpret_cast<JSResolveOp>(Resolve), JS_ConvertStub,
     Finalize, NULL, NULL, NULL, NULL, Trace
   },
   {
     { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
       prototypes::id::_ID_Count },
     false,
-    &sNativePropertyHooks
+    &sWorkerNativePropertyHooks
   }
 };
 
 JSPropertySpec DedicatedWorkerGlobalScope::sProperties[] = {
   { sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }
 };
@@ -935,17 +933,17 @@ CreateDedicatedWorkerGlobalScope(JSConte
 
   // Proto chain should be:
   //   global -> DedicatedWorkerGlobalScope
   //          -> WorkerGlobalScope
   //          -> EventTarget
   //          -> Object
 
   JSObject* eventTargetProto =
-    EventTargetBinding_workers::GetProtoObject(aCx, global, global);
+    EventTargetBinding_workers::GetProtoObject(aCx, global);
   if (!eventTargetProto) {
     return NULL;
   }
 
   JSObject* scopeProto =
     WorkerGlobalScope::InitClass(aCx, global, eventTargetProto);
   if (!scopeProto) {
     return NULL;
@@ -982,24 +980,20 @@ CreateDedicatedWorkerGlobalScope(JSConte
       !file::InitClasses(aCx, global) ||
       !exceptions::InitClasses(aCx, global) ||
       !location::InitClass(aCx, global) ||
       !imagedata::InitClass(aCx, global) ||
       !navigator::InitClass(aCx, global)) {
     return NULL;
   }
 
-  // Init other paris-bindings.  Use GetProtoObject so the proto will
-  // be correctly cached in the proto cache.  Otherwise we'll end up
-  // double-calling CreateInterfaceObjects when we actually create an
-  // object which has these protos, which breaks things like
-  // instanceof.
-  if (!FileReaderSyncBinding_workers::GetProtoObject(aCx, global, global) ||
-      !XMLHttpRequestBinding_workers::GetProtoObject(aCx, global, global) ||
-      !XMLHttpRequestUploadBinding_workers::GetProtoObject(aCx, global, global)) {
+  // Init other paris-bindings.
+  if (!FileReaderSyncBinding_workers::GetConstructorObject(aCx, global) ||
+      !XMLHttpRequestBinding_workers::GetConstructorObject(aCx, global) ||
+      !XMLHttpRequestUploadBinding_workers::GetConstructorObject(aCx, global)) {
     return NULL;
   }
 
   if (!JS_DefineProfilingFunctions(aCx, global)) {
     return NULL;
   }
 
   return global;
--- a/editor/composer/src/nsEditorSpellCheck.cpp
+++ b/editor/composer/src/nsEditorSpellCheck.cpp
@@ -20,16 +20,17 @@
 #include "nsIContent.h"                 // for nsIContent
 #include "nsIContentPrefService.h"      // for nsIContentPrefService, etc
 #include "nsIDOMDocument.h"             // for nsIDOMDocument
 #include "nsIDOMElement.h"              // for nsIDOMElement
 #include "nsIDOMRange.h"                // for nsIDOMRange
 #include "nsIDocument.h"                // for nsIDocument
 #include "nsIEditor.h"                  // for nsIEditor
 #include "nsIHTMLEditor.h"              // for nsIHTMLEditor
+#include "nsILoadContext.h"
 #include "nsISelection.h"               // for nsISelection
 #include "nsISpellChecker.h"            // for nsISpellChecker, etc
 #include "nsISupportsBase.h"            // for nsISupports
 #include "nsISupportsUtils.h"           // for NS_ADDREF
 #include "nsITextServicesDocument.h"    // for nsITextServicesDocument
 #include "nsITextServicesFilter.h"      // for nsITextServicesFilter
 #include "nsIURI.h"                     // for nsIURI
 #include "nsIVariant.h"                 // for nsIWritableVariant, etc
@@ -103,16 +104,31 @@ LastDictionary::GetDocumentURI(nsIEditor
   nsCOMPtr<nsIURI> docUri = doc->GetDocumentURI();
   NS_ENSURE_TRUE(docUri, NS_ERROR_FAILURE);
 
   *aURI = docUri;
   NS_ADDREF(*aURI);
   return NS_OK;
 }
 
+static already_AddRefed<nsILoadContext>
+GetLoadContext(nsIEditor* aEditor)
+{
+  nsCOMPtr<nsIDOMDocument> domDoc;
+  aEditor->GetDocument(getter_AddRefs(domDoc));
+  NS_ENSURE_TRUE(domDoc, nullptr);
+
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
+  NS_ENSURE_TRUE(doc, nullptr);
+
+  nsCOMPtr<nsISupports> container = doc->GetContainer();
+  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(container);
+  return loadContext.forget();
+}
+
 NS_IMETHODIMP
 LastDictionary::FetchLastDictionary(nsIEditor* aEditor, nsAString& aDictionary)
 {
   NS_ENSURE_ARG_POINTER(aEditor);
 
   nsresult rv;
 
   nsCOMPtr<nsIURI> docUri;
@@ -122,20 +138,21 @@ LastDictionary::FetchLastDictionary(nsIE
   nsCOMPtr<nsIContentPrefService> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_AVAILABLE);
 
   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
   NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
   uri->SetAsISupports(docUri);
 
+  nsCOMPtr<nsILoadContext> loadContext = GetLoadContext(aEditor);
   bool hasPref;
-  if (NS_SUCCEEDED(contentPrefService->HasPref(uri, CPS_PREF_NAME, &hasPref)) && hasPref) {
+  if (NS_SUCCEEDED(contentPrefService->HasPref(uri, CPS_PREF_NAME, loadContext, &hasPref)) && hasPref) {
     nsCOMPtr<nsIVariant> pref;
-    contentPrefService->GetPref(uri, CPS_PREF_NAME, nullptr, getter_AddRefs(pref));
+    contentPrefService->GetPref(uri, CPS_PREF_NAME, loadContext, nullptr, getter_AddRefs(pref));
     pref->GetAsAString(aDictionary);
   } else {
     aDictionary.Truncate();
   }
 
   return NS_OK;
 }
 
@@ -157,17 +174,18 @@ LastDictionary::StoreCurrentDictionary(n
   nsCOMPtr<nsIWritableVariant> prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID);
   NS_ENSURE_TRUE(prefValue, NS_ERROR_OUT_OF_MEMORY);
   prefValue->SetAsAString(aDictionary);
 
   nsCOMPtr<nsIContentPrefService> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_INITIALIZED);
 
-  return contentPrefService->SetPref(uri, CPS_PREF_NAME, prefValue);
+  nsCOMPtr<nsILoadContext> loadContext = GetLoadContext(aEditor);
+  return contentPrefService->SetPref(uri, CPS_PREF_NAME, prefValue, loadContext);
 }
 
 NS_IMETHODIMP
 LastDictionary::ClearCurrentDictionary(nsIEditor* aEditor)
 {
   NS_ENSURE_ARG_POINTER(aEditor);
 
   nsresult rv;
@@ -179,17 +197,18 @@ LastDictionary::ClearCurrentDictionary(n
   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
   NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
   uri->SetAsISupports(docUri);
 
   nsCOMPtr<nsIContentPrefService> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_INITIALIZED);
 
-  return contentPrefService->RemovePref(uri, CPS_PREF_NAME);
+  nsCOMPtr<nsILoadContext> loadContext = GetLoadContext(aEditor);
+  return contentPrefService->RemovePref(uri, CPS_PREF_NAME, loadContext);
 }
 
 LastDictionary* nsEditorSpellCheck::gDictionaryStore = nullptr;
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEditorSpellCheck)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEditorSpellCheck)
 
 NS_INTERFACE_MAP_BEGIN(nsEditorSpellCheck)
--- a/editor/txmgr/tests/TestTXMgr.cpp
+++ b/editor/txmgr/tests/TestTXMgr.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TestHarness.h"
 
 #include "nsITransactionManager.h"
 #include "nsComponentManagerUtils.h"
+#include "mozilla/Likely.h"
 
 static int32_t sConstructorCount     = 0;
 static int32_t sDestructorCount      = 0;
 static int32_t *sDestructorOrderArr  = 0;
 static int32_t sDoCount              = 0;
 static int32_t *sDoOrderArr          = 0;
 static int32_t sUndoCount            = 0;
 static int32_t *sUndoOrderArr        = 0;
@@ -4441,17 +4442,17 @@ stress_test(TestTransactionFactory *fact
       result = mgr->UndoTransaction();
       if (NS_FAILED(result)) {
         fail("Failed to undo transaction %d-%d. (%d)\n", i, j, result);
         return result;
       }
     }
 
     // Trivial feedback not to let the user think the test is stuck.
-    if (NS_UNLIKELY(j % 100 == 0))
+    if (MOZ_UNLIKELY(j % 100 == 0))
       printf("%i ", j);
   } // for, iterations.
 
   printf("passed\n");
 
   result = mgr->Clear();
   if (NS_FAILED(result)) {
     fail("Clear() failed. (%d)\n", result);
--- a/extensions/auth/nsHttpNegotiateAuth.cpp
+++ b/extensions/auth/nsHttpNegotiateAuth.cpp
@@ -31,16 +31,17 @@
 #include "nsString.h"
 #include "nsNetCID.h"
 #include "plbase64.h"
 #include "plstr.h"
 #include "prprf.h"
 #include "prlog.h"
 #include "prmem.h"
 #include "prnetdb.h"
+#include "mozilla/Likely.h"
 
 //-----------------------------------------------------------------------------
 
 static const char kNegotiate[] = "Negotiate";
 static const char kNegotiateAuthTrustedURIs[] = "network.negotiate-auth.trusted-uris";
 static const char kNegotiateAuthDelegationURIs[] = "network.negotiate-auth.delegation-uris";
 static const char kNegotiateAuthAllowProxies[] = "network.negotiate-auth.allow-proxies";
 static const char kNegotiateAuthAllowNonFqdn[] = "network.negotiate-auth.allow-non-fqdn";
@@ -270,17 +271,17 @@ nsHttpNegotiateAuth::GenerateCredentials
 
     if (!encoded_token)
         return NS_ERROR_OUT_OF_MEMORY;
 
     LOG(("  Sending a token of length %d\n", outTokenLen));
 
     // allocate a buffer sizeof("Negotiate" + " " + b64output_token + "\0")
     *creds = (char *) nsMemory::Alloc(kNegotiateLen + 1 + strlen(encoded_token) + 1);
-    if (NS_UNLIKELY(!*creds))
+    if (MOZ_UNLIKELY(!*creds))
         rv = NS_ERROR_OUT_OF_MEMORY;
     else
         sprintf(*creds, "%s %s", kNegotiate, encoded_token);
 
     PR_Free(encoded_token);
     return rv;
 }
 
--- a/extensions/spellcheck/src/mozEnglishWordUtils.cpp
+++ b/extensions/spellcheck/src/mozEnglishWordUtils.cpp
@@ -5,16 +5,17 @@
 
 #include "mozEnglishWordUtils.h"
 #include "nsReadableUtils.h"
 #include "nsIServiceManager.h"
 #include "nsUnicharUtils.h"
 #include "nsUnicharUtilCIID.h"
 #include "nsUnicodeProperties.h"
 #include "nsCRT.h"
+#include "mozilla/Likely.h"
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozEnglishWordUtils)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozEnglishWordUtils)
 
 NS_INTERFACE_MAP_BEGIN(mozEnglishWordUtils)
   NS_INTERFACE_MAP_ENTRY(mozISpellI18NUtil)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozISpellI18NUtil)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozEnglishWordUtils)
@@ -242,17 +243,17 @@ NS_IMETHODIMP mozEnglishWordUtils::FromR
   PRUnichar **tmpPtr  = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *)*icount);
   if (!tmpPtr)
     return NS_ERROR_OUT_OF_MEMORY;
 
   mozEnglishWordUtils::myspCapitalization ct = captype(word);
   for(uint32_t i = 0; i < icount; ++i) {
     length = NS_strlen(iwords[i]);
     tmpPtr[i] = (PRUnichar *) nsMemory::Alloc(sizeof(PRUnichar) * (length + 1));
-    if (NS_UNLIKELY(!tmpPtr[i])) {
+    if (MOZ_UNLIKELY(!tmpPtr[i])) {
       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, tmpPtr);
       return NS_ERROR_OUT_OF_MEMORY;
     }
     memcpy(tmpPtr[i], iwords[i], (length + 1) * sizeof(PRUnichar));
 
     nsAutoString capTest(tmpPtr[i]);
     mozEnglishWordUtils::myspCapitalization newCt=captype(capTest);
     if(newCt == NoCap){
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -53,17 +53,18 @@ struct ReferencePtr
 
   operator void*() const {
     return (void*)mLongPtr;
   }
 
   uint64_t mLongPtr;
 };
 
-static std::string StringFromPtr(ReferencePtr aPtr)
+// Used by the Azure drawing debugger (player2d)
+inline std::string StringFromPtr(ReferencePtr aPtr)
 {
   std::stringstream stream;
   stream << aPtr;
   return stream.str();
 }
 
 class Translator
 {
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -80,18 +80,21 @@ public:
 
   gfxSize LayersPixelsPerCSSPixel() const
   {
     return mResolution * mDevPixelsPerCSSPixel;
   }
 
   gfx::Point GetScrollOffsetInLayerPixels() const
   {
-    return gfx::Point(mScrollOffset.x * LayersPixelsPerCSSPixel().width,
-                      mScrollOffset.y * LayersPixelsPerCSSPixel().height);
+    return gfx::Point(
+      static_cast<gfx::Float>(
+        mScrollOffset.x * LayersPixelsPerCSSPixel().width),
+      static_cast<gfx::Float>(
+        mScrollOffset.y * LayersPixelsPerCSSPixel().height));
   }
 
   // ---------------------------------------------------------------------------
   // The following metrics are all in widget space/device pixels.
   //
 
   // This is the area within the widget that we're compositing to, which means
   // that it is the visible region of this frame. It is not relative to
--- a/gfx/layers/TiledLayerBuffer.h
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -154,16 +154,18 @@ class TiledLayerComposer
 public:
   /**
    * Update the current retained layer with the updated layer data.
    * The BasicTiledLayerBuffer is expected to be in the ReadLock state
    * prior to this being called. aTiledBuffer is copy constructed and
    * is retained until it has been uploaded/copyed and unlocked.
    */
   virtual void PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* aTiledBuffer) = 0;
+
+  virtual void MemoryPressure() = 0;
 };
 
 // Normal integer division truncates towards zero,
 // we instead want to floor to hangle negative numbers.
 static inline int floor_div(int a, int b)
 {
   int rem = a % b;
   int div = a/b;
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -3,32 +3,74 @@
 /* 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 "CompositorChild.h"
 #include "CompositorParent.h"
 #include "LayerManagerOGL.h"
 #include "mozilla/layers/ShadowLayersChild.h"
+#include "nsIObserverService.h"
+#include "mozilla/Services.h"
 
 using mozilla::layers::ShadowLayersChild;
 
 namespace mozilla {
 namespace layers {
 
+// Observer for the memory-pressure notification, to trigger
+// flushing of stale/low res content.
+class MemoryPressureObserver MOZ_FINAL : public nsIObserver,
+                                         public nsSupportsWeakReference
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  explicit MemoryPressureObserver(CompositorChild* cc)
+    : mCC(cc)
+  {}
+
+private:
+  CompositorChild* mCC;
+};
+
+NS_IMPL_ISUPPORTS2(MemoryPressureObserver, nsIObserver, nsISupportsWeakReference)
+
+NS_IMETHODIMP
+MemoryPressureObserver::Observe(nsISupports *aSubject,
+                                const char *aTopic,
+                                const PRUnichar *someData)
+{
+  if (strcmp(aTopic, "memory-pressure") == 0) {
+    mCC->SendMemoryPressure();
+  }
+  return NS_OK;
+}
+
 /*static*/ CompositorChild* CompositorChild::sCompositor;
 
 CompositorChild::CompositorChild(LayerManager *aLayerManager)
   : mLayerManager(aLayerManager)
 {
   MOZ_COUNT_CTOR(CompositorChild);
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    mMemoryPressureObserver = new MemoryPressureObserver(this);
+    obs->AddObserver(mMemoryPressureObserver, "memory-pressure", false);
+  }
 }
 
 CompositorChild::~CompositorChild()
 {
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->RemoveObserver(mMemoryPressureObserver, "memory-pressure");
+  }
   MOZ_COUNT_DTOR(CompositorChild);
 }
 
 void
 CompositorChild::Destroy()
 {
   mLayerManager = NULL;
   while (size_t len = ManagedPLayersChild().Length()) {
--- a/gfx/layers/ipc/CompositorChild.h
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -49,16 +49,17 @@ protected:
     const gfxIntSize&, const uint32_t&, const uint32_t&,
     MaybeMagicGrallocBufferHandle*) MOZ_OVERRIDE
   { return nullptr; }
   virtual bool DeallocPGrallocBuffer(PGrallocBufferChild*)
   { return false; }
 
 private:
   nsRefPtr<LayerManager> mLayerManager;
+  nsCOMPtr<nsIObserver> mMemoryPressureObserver;
 
   // When we're in a child process, this is the process-global
   // compositor that we use to forward transactions directly to the
   // compositor context in another process.
   static CompositorChild* sCompositor;
 
   DISALLOW_EVIL_CONSTRUCTORS(CompositorChild);
 };
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -26,16 +26,17 @@
 #include "LayerManagerOGL.h"
 #include "nsIWidget.h"
 #include "nsGkAtoms.h"
 #include "RenderTrace.h"
 #include "nsStyleAnimation.h"
 #include "nsDisplayList.h"
 #include "AnimationCommon.h"
 #include "nsAnimationManager.h"
+#include "TiledLayerBuffer.h"
 
 using namespace base;
 using namespace mozilla::ipc;
 using namespace std;
 
 namespace mozilla {
 namespace layers {
 
@@ -207,16 +208,47 @@ CompositorParent::Destroy()
 {
   NS_ABORT_IF_FALSE(ManagedPLayersParent().Length() == 0,
                     "CompositorParent destroyed before managed PLayersParent");
 
   // Ensure that the layer manager is destructed on the compositor thread.
   mLayerManager = NULL;
 }
 
+static void
+DispatchMemoryPressureToLayers(Layer* aLayer)
+{
+  ShadowLayer* shadowLayer = aLayer->AsShadowLayer();
+  if (shadowLayer) {
+    TiledLayerComposer* tileComposer = shadowLayer->AsTiledLayerComposer();
+    if (tileComposer) {
+      tileComposer->MemoryPressure();
+    }
+  }
+
+  for (Layer* child = aLayer->GetFirstChild();
+         child; child = child->GetNextSibling()) {
+    DispatchMemoryPressureToLayers(child);
+  }
+
+}
+
+bool
+CompositorParent::RecvMemoryPressure()
+{
+  if (!mLayerManager)
+    return true;
+
+  Layer* layer = mLayerManager->GetRoot();
+  if (layer)
+    DispatchMemoryPressureToLayers(layer);
+
+  return true;
+}
+
 bool
 CompositorParent::RecvWillStop()
 {
   mPaused = true;
   RemoveCompositor(mCompositorID);
 
   // Ensure that the layer manager is destroyed before CompositorChild.
   mLayerManager->Destroy();
@@ -1164,16 +1196,19 @@ public:
 
   virtual PGrallocBufferParent* AllocPGrallocBuffer(
     const gfxIntSize&, const uint32_t&, const uint32_t&,
     MaybeMagicGrallocBufferHandle*) MOZ_OVERRIDE
   { return nullptr; }
   virtual bool DeallocPGrallocBuffer(PGrallocBufferParent*)
   { return false; }
 
+  virtual bool RecvMemoryPressure()
+  { return true; }
+
 private:
   void DeferredDestroy();
 
   // There can be many CPCPs, and IPDL-generated code doesn't hold a
   // reference to top-level actors.  So we hold a reference to
   // ourself.  This is released (deferred) in ActorDestroy().
   nsRefPtr<CrossProcessCompositorParent> mSelfRef;
 };
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -146,16 +146,22 @@ public:
    * Setup external message loop and thread ID for Compositor.
    * Should be used when CompositorParent should work in existing thread/MessageLoop,
    * for example moving Compositor into native toolkit main thread will allow to avoid
    * extra synchronization and call ::Composite() right from toolkit::Paint event
    */
   static void StartUpWithExistingThread(MessageLoop* aMsgLoop,
                                         PlatformThreadId aThreadID);
 
+  /**
+   * Release disposable memory. This will clear the tile store (stale tiles).
+   */
+  bool
+  RecvMemoryPressure();
+
 protected:
   virtual PLayersParent* AllocPLayers(const LayersBackend& aBackendHint,
                                       const uint64_t& aId,
                                       LayersBackend* aBackend,
                                       int32_t* aMaxTextureSize);
   virtual bool DeallocPLayers(PLayersParent* aLayers);
   virtual void ScheduleTask(CancelableTask*, int);
   virtual void Composite();
--- a/gfx/layers/ipc/ImageContainerChild.cpp
+++ b/gfx/layers/ipc/ImageContainerChild.cpp
@@ -9,16 +9,18 @@
 #include "ShadowLayers.h"
 #include "mozilla/layers/PLayers.h"
 #include "mozilla/layers/SharedImageUtils.h"
 #include "ImageContainer.h"
 #include "GonkIOSurfaceImage.h"
 #include "GrallocImages.h"
 #include "mozilla/layers/ShmemYCbCrImage.h"
 
+using namespace mozilla::ipc;
+
 namespace mozilla {
 namespace layers {
 
 /*
  * - POOL_MAX_SHARED_IMAGES is the maximum number number of shared images to
  * store in the ImageContainerChild's pool.
  *
  * - MAX_ACTIVE_SHARED_IMAGES is the maximum number of active shared images.
@@ -117,54 +119,62 @@ void ImageContainerChild::DestroySharedI
 {
   NS_ABORT_IF_FALSE(InImageBridgeChildThread(),
                     "Should be in ImageBridgeChild thread.");
 
   --mActiveImageCount;
   DeallocSharedImageData(this, aImage);
 }
 
+SharedImage* ImageContainerChild::AsSharedImage(Image* aImage)
+{
+#ifdef MOZ_WIDGET_GONK
+  if (aImage->GetFormat() == GONK_IO_SURFACE) {
+    GonkIOSurfaceImage* gonkImage = static_cast<GonkIOSurfaceImage*>(aImage);
+    SharedImage* result = new SharedImage(gonkImage->GetSurfaceDescriptor());
+    return result;
+  } else if (aImage->GetFormat() == GRALLOC_PLANAR_YCBCR) {
+    GrallocPlanarYCbCrImage* GrallocImage = static_cast<GrallocPlanarYCbCrImage*>(aImage);
+    SharedImage* result = new SharedImage(GrallocImage->GetSurfaceDescriptor());
+    return result;
+  }
+#endif
+  return nullptr; // XXX: bug 773440
+}
+
 bool ImageContainerChild::CopyDataIntoSharedImage(Image* src, SharedImage* dest)
 {
   if ((src->GetFormat() == PLANAR_YCBCR) && 
       (dest->type() == SharedImage::TYCbCrImage)) {
     PlanarYCbCrImage *planarYCbCrImage = static_cast<PlanarYCbCrImage*>(src);
-    const PlanarYCbCrImage::Data *data =planarYCbCrImage->GetData();
+    const PlanarYCbCrImage::Data *data = planarYCbCrImage->GetData();
     NS_ASSERTION(data, "Must be able to retrieve yuv data from image!");
     YCbCrImage& yuv = dest->get_YCbCrImage();
 
     ShmemYCbCrImage shmemImage(yuv.data(), yuv.offset());
 
-    for (int i = 0; i < data->mYSize.height; i++) {
-      memcpy(shmemImage.GetYData() + i * shmemImage.GetYStride(),
-             data->mYChannel + i * data->mYStride,
-             data->mYSize.width);
+    if (!shmemImage.CopyData(data->mYChannel, data->mCbChannel, data->mCrChannel,
+                             data->mYSize, data->mYStride,
+                             data->mCbCrSize, data->mCbCrStride)) {
+      NS_WARNING("Failed to copy image data!");
+      return false;
     }
-    for (int i = 0; i < data->mCbCrSize.height; i++) {
-      memcpy(shmemImage.GetCbData() + i * shmemImage.GetCbCrStride(),
-             data->mCbChannel + i * data->mCbCrStride,
-             data->mCbCrSize.width);
-      memcpy(shmemImage.GetCrData() + i * shmemImage.GetCbCrStride(),
-             data->mCrChannel + i * data->mCbCrStride,
-             data->mCbCrSize.width);
-    }
-
     return true;
   }
   return false; // TODO: support more image formats
 }
 
-SharedImage* ImageContainerChild::CreateSharedImageFromData(Image* image)
+SharedImage* ImageContainerChild::AllocateSharedImageFor(Image* image)
 {
   NS_ABORT_IF_FALSE(InImageBridgeChildThread(),
                   "Should be in ImageBridgeChild thread.");
-
   if (!image) {
     return nullptr;
   }
+
   if (image->GetFormat() == PLANAR_YCBCR ) {
     PlanarYCbCrImage *planarYCbCrImage = static_cast<PlanarYCbCrImage*>(image);
     const PlanarYCbCrImage::Data *data = planarYCbCrImage->GetData();
     NS_ASSERTION(data, "Must be able to retrieve yuv data from image!");
     if (!data) {
       return nullptr;
     }
 
@@ -176,48 +186,24 @@ SharedImage* ImageContainerChild::Create
       return nullptr;
     }
 
     ShmemYCbCrImage::InitializeBufferInfo(shmem.get<uint8_t>(),
                                           data->mYSize,
                                           data->mCbCrSize);
     ShmemYCbCrImage shmemImage(shmem);
 
-    if (!shmemImage.IsValid() || shmem.Size<uint8_t>() < size) {
+    if (!shmemImage.IsValid()) {
+      NS_WARNING("Failed to properly allocate image data!");
       DeallocShmem(shmem);
       return nullptr;
     }
 
-    for (int i = 0; i < data->mYSize.height; i++) {
-      memcpy(shmemImage.GetYData() + i * shmemImage.GetYStride(),
-             data->mYChannel + i * data->mYStride,
-             data->mYSize.width);
-    }
-    for (int i = 0; i < data->mCbCrSize.height; i++) {
-      memcpy(shmemImage.GetCbData() + i * shmemImage.GetCbCrStride(),
-             data->mCbChannel + i * data->mCbCrStride,
-             data->mCbCrSize.width);
-      memcpy(shmemImage.GetCrData() + i * shmemImage.GetCbCrStride(),
-             data->mCrChannel + i * data->mCbCrStride,
-             data->mCbCrSize.width);
-    }
-
     ++mActiveImageCount;
-    SharedImage* result = new SharedImage(YCbCrImage(shmem, 0, data->GetPictureRect()));
-    return result;
-#ifdef MOZ_WIDGET_GONK
-  } else if (image->GetFormat() == GONK_IO_SURFACE) {
-    GonkIOSurfaceImage* gonkImage = static_cast<GonkIOSurfaceImage*>(image);
-    SharedImage* result = new SharedImage(gonkImage->GetSurfaceDescriptor());
-    return result;